diff --git a/TODO b/TODO
index 8a889f9c..bf4a80b3 100644
--- a/TODO
+++ b/TODO
@@ -6,10 +6,6 @@ everything related to posts:
- better thumbnail loading
- single post view
- - previous and next post (difficult)
- - remember last search
- - take care of pages
- - add A/D hotkeys
- editing
- ability to loop video posts
diff --git a/public_html/css/post.css b/public_html/css/post.css
index b3e1f011..d61c5b9c 100644
--- a/public_html/css/post.css
+++ b/public_html/css/post.css
@@ -9,6 +9,25 @@
border: 0;
}
+#post-current-search-wrapper {
+ text-align: center;
+}
+#post-current-search {
+ margin: 0 auto 1em auto;
+ display: inline-block;
+}
+
+#post-current-search a {
+ margin: 0 2em;
+}
+#post-current-search a,
+#post-current-search div {
+ display: inline-block;
+}
+#post-current-search a:not(.enabled) {
+ color: silver;
+}
+
#post-view-wrapper #sidebar {
line-height: 1.33em;
font-size: 90%;
diff --git a/public_html/index.html b/public_html/index.html
index 3387a340..dbef564a 100644
--- a/public_html/index.html
+++ b/public_html/index.html
@@ -89,6 +89,8 @@
+
+
diff --git a/public_html/js/Keyboard.js b/public_html/js/Keyboard.js
index 11fef3d8..2261ce87 100644
--- a/public_html/js/Keyboard.js
+++ b/public_html/js/Keyboard.js
@@ -22,10 +22,15 @@ App.Keyboard = function(mousetrap) {
mousetrap.reset();
}
+ function unbind(key) {
+ mousetrap.unbind(key);
+ }
+
return {
keydown: keydown,
keyup: keyup,
reset: reset,
+ unbind: unbind,
};
};
diff --git a/public_html/js/Pager.js b/public_html/js/Pager.js
index 398f8026..6062631e 100644
--- a/public_html/js/Pager.js
+++ b/public_html/js/Pager.js
@@ -9,6 +9,7 @@ App.Pager = function(
var pageNumber;
var searchParams;
var url;
+ var cache = {};
function init(args) {
url = args.url;
@@ -55,7 +56,7 @@ App.Pager = function(
function retrieve() {
return promise.make(function(resolve, reject) {
- promise.wait(api.get(url, _.extend({}, searchParams, {page: pageNumber})))
+ promise.wait(api.get(url, _.extend({page: pageNumber}, searchParams)))
.then(function(response) {
var pageSize = response.json.pageSize;
var totalRecords = response.json.totalRecords;
@@ -71,6 +72,27 @@ App.Pager = function(
});
}
+ function retrieveCached() {
+ return promise.make(function(resolve, reject) {
+ var cacheKey = JSON.stringify(_.extend({}, searchParams, {url: url, page: getPage()}));
+ if (cacheKey in cache) {
+ resolve.apply(this, cache[cacheKey]);
+ } else {
+ promise.wait(retrieve())
+ .then(function() {
+ cache[cacheKey] = arguments;
+ resolve.apply(this, arguments);
+ }).fail(function() {
+ reject.apply(this, arguments);
+ });
+ }
+ });
+ }
+
+ function resetCache() {
+ cache = {};
+ }
+
function getVisiblePages() {
var pages = [1, totalPages || 1];
var pagesAroundCurrent = 2;
@@ -100,7 +122,9 @@ App.Pager = function(
getSearchParams: getSearchParams,
setSearchParams: setSearchParams,
retrieve: retrieve,
+ retrieveCached: retrieveCached,
getVisiblePages: getVisiblePages,
+ resetCache: resetCache,
};
};
diff --git a/public_html/js/Presenters/PostListPresenter.js b/public_html/js/Presenters/PostListPresenter.js
index 44db2976..abd65084 100644
--- a/public_html/js/Presenters/PostListPresenter.js
+++ b/public_html/js/Presenters/PostListPresenter.js
@@ -24,6 +24,7 @@ App.Presenters.PostListPresenter = function(
topNavigationPresenter.select('posts');
topNavigationPresenter.changeTitle('Posts');
searchArgs = util.parseComplexRouteArgs(args.searchArgs);
+ searchArgs.page = parseInt(searchArgs.page) || 1;
promise.wait(
util.promiseTemplate('post-list'),
@@ -93,6 +94,7 @@ App.Presenters.PostListPresenter = function(
_.each(posts, function(post) {
$target.append(jQuery('
' + itemTemplate({
+ searchArgs: searchArgs,
post: post,
}) + ''));
});
diff --git a/public_html/js/Presenters/PostPresenter.js b/public_html/js/Presenters/PostPresenter.js
index 1740c215..196b9cf2 100644
--- a/public_html/js/Presenters/PostPresenter.js
+++ b/public_html/js/Presenters/PostPresenter.js
@@ -11,6 +11,7 @@ App.Presenters.PostPresenter = function(
router,
keyboard,
presenterManager,
+ postsAroundCalculator,
postCommentListPresenter,
topNavigationPresenter,
messagePresenter) {
@@ -23,11 +24,13 @@ App.Presenters.PostPresenter = function(
var postContentTemplate;
var historyTemplate;
+ var postNameOrId;
+ var searchArgs;
+
var post;
var postScore;
var postFavorites;
var postHistory;
- var postNameOrId;
var privileges = {};
var editPrivileges = {};
@@ -40,6 +43,7 @@ App.Presenters.PostPresenter = function(
function init(args, loaded) {
topNavigationPresenter.select('posts');
+ postsAroundCalculator.resetCache();
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
@@ -76,6 +80,9 @@ App.Presenters.PostPresenter = function(
function reinit(args, loaded) {
postNameOrId = args.postNameOrId;
+ searchArgs = util.parseComplexRouteArgs(args.searchArgs);
+ searchArgs.page = parseInt(searchArgs.page) || 1;
+
promise.wait(refreshPost())
.then(function() {
topNavigationPresenter.changeTitle('@' + post.id);
@@ -84,6 +91,39 @@ App.Presenters.PostPresenter = function(
}).fail(loaded);
}
+ function attachLinksToPostsAround() {
+ var searchParams = {query: searchArgs.query, order: searchArgs.order};
+ promise.wait(postsAroundCalculator.getLinksToPostsAround(searchParams, searchArgs.page, post.id))
+ .then(function(nextPostUrl, prevPostUrl) {
+ var $prevPost = $el.find('#post-current-search .right a');
+ var $nextPost = $el.find('#post-current-search .left a');
+
+ if (nextPostUrl) {
+ $nextPost.addClass('enabled');
+ $nextPost.attr('href', nextPostUrl);
+ keyboard.keyup('a', function() {
+ router.navigate(nextPostUrl);
+ });
+ } else {
+ $nextPost.removeClass('enabled');
+ $nextPost.removeAttr('href');
+ keyboard.unbind('a');
+ }
+
+ if (prevPostUrl) {
+ $prevPost.addClass('enabled');
+ $prevPost.attr('href', prevPostUrl);
+ keyboard.keyup('d', function() {
+ router.navigate(prevPostUrl);
+ });
+ } else {
+ $prevPost.removeClass('enabled');
+ $prevPost.removeAttr('href');
+ keyboard.unbind('d');
+ }
+ });
+ }
+
function refreshPost() {
return promise.make(function(resolve, reject) {
promise.wait(api.get('/posts/' + postNameOrId))
@@ -128,6 +168,8 @@ App.Presenters.PostPresenter = function(
presenterManager.initPresenters([
[postCommentListPresenter, _.extend({post: post}, {$target: $el.find('#post-comments-target')})]],
function() { });
+
+ attachLinksToPostsAround();
}
function renderSidebar() {
@@ -137,6 +179,7 @@ App.Presenters.PostPresenter = function(
function renderPostTemplate() {
return postTemplate({
+ searchArgs: searchArgs,
post: post,
ownScore: postScore,
postFavorites: postFavorites,
@@ -370,6 +413,7 @@ App.DI.register('postPresenter', [
'router',
'keyboard',
'presenterManager',
+ 'postsAroundCalculator',
'postCommentListPresenter',
'topNavigationPresenter',
'messagePresenter'],
diff --git a/public_html/js/Presenters/UserListPresenter.js b/public_html/js/Presenters/UserListPresenter.js
index 1dfd073a..5c0d14f7 100644
--- a/public_html/js/Presenters/UserListPresenter.js
+++ b/public_html/js/Presenters/UserListPresenter.js
@@ -47,6 +47,7 @@ App.Presenters.UserListPresenter = function(
var searchArgs = util.parseComplexRouteArgs(args.searchArgs);
searchArgs.order = searchArgs.order || 'name,asc';
+ searchArgs.page = parseInt(searchArgs.page) || 1;
updateActiveOrder(searchArgs.order);
pagerPresenter.reinit({
diff --git a/public_html/js/Router.js b/public_html/js/Router.js
index 5fda740b..01ab1b12 100644
--- a/public_html/js/Router.js
+++ b/public_html/js/Router.js
@@ -39,7 +39,7 @@ App.Router = function(pathJs, _, jQuery, promise, util, appState, presenterManag
inject('#/users(/:searchArgs)', 'userListPresenter');
inject('#/user/:userName(/:tab)', 'userPresenter');
inject('#/posts(/:searchArgs)', 'postListPresenter');
- inject('#/post(/:postNameOrId)', 'postPresenter');
+ inject('#/post(/:postNameOrId)(/:searchArgs)', 'postPresenter');
inject('#/comments(/:searchArgs)', 'globalCommentListPresenter');
inject('#/tags(/:searchArgs)', 'tagListPresenter');
inject('#/help', 'helpPresenter');
diff --git a/public_html/js/Services/PostsAroundCalculator.js b/public_html/js/Services/PostsAroundCalculator.js
new file mode 100644
index 00000000..80d0f1b4
--- /dev/null
+++ b/public_html/js/Services/PostsAroundCalculator.js
@@ -0,0 +1,70 @@
+var App = App || {};
+App.Services = App.Services || {};
+
+App.Services.PostsAroundCalculator = function(_, promise, util, pager) {
+
+ pager.init({url: '/posts'});
+
+ function resetCache() {
+ pager.resetCache();
+ }
+
+ function getLinksToPostsAround(searchParams, page, postId) {
+ return promise.make(function(resolve, reject) {
+ pager.setSearchParams(searchParams);
+ pager.setPage(page);
+ promise.wait(pager.retrieveCached())
+ .then(function(response) {
+ var postIds = _.pluck(response.entities, 'id');
+ var position = _.indexOf(postIds, postId);
+
+ if (position === -1) {
+ resolve(null, null);
+ }
+
+ promise.wait(
+ getLinkToPostAround(postIds, position, page, -1),
+ getLinkToPostAround(postIds, position, page, 1))
+ .then(function(nextPostUrl, prevPostUrl) {
+ resolve(nextPostUrl, prevPostUrl);
+ });
+ });
+ });
+ }
+
+ function getLinkToPostAround(postIds, position, page, direction) {
+ return promise.make(function(resolve, reject) {
+ if (position + direction >= 0 && position + direction < postIds.length) {
+ var url = util.compileComplexRouteArgs(
+ '#/post/' + postIds[position + direction],
+ _.extend({page: page}, pager.getSearchParams()));
+ resolve(url);
+ } else if (page + direction >= 1) {
+ pager.setPage(page + direction);
+ promise.wait(pager.retrieveCached()).then(function(response) {
+ if (response.entities.length) {
+ var post = direction === - 1 ?
+ _.last(response.entities) :
+ _.first(response.entities);
+
+ var url = util.compileComplexRouteArgs(
+ '#/post/' + post.id,
+ _.extend({page: page + direction}, pager.getSearchParams()));
+ resolve(url);
+ } else {
+ resolve(null);
+ }
+ });
+ } else {
+ resolve(null);
+ }
+ });
+ }
+
+ return {
+ resetCache: resetCache,
+ getLinksToPostsAround: getLinksToPostsAround,
+ };
+};
+
+App.DI.register('postsAroundCalculator', ['_', 'promise', 'util', 'pager'], App.Services.PostsAroundCalculator);
diff --git a/public_html/templates/post-list-item.tpl b/public_html/templates/post-list-item.tpl
index b5c44144..3d646bfe 100644
--- a/public_html/templates/post-list-item.tpl
+++ b/public_html/templates/post-list-item.tpl
@@ -1,7 +1,11 @@