From 65a6694925a602bbe24eca706b65ef6a0faf379e Mon Sep 17 00:00:00 2001 From: noirscape Date: Wed, 4 Jan 2023 22:00:12 +0100 Subject: [PATCH] client: add pool navigation elements this implementation was *heavily* cherry-picked from PR #403. --- client/css/pool-navigator-control.styl | 34 +++++++++++++ client/css/pool-navigator-list.styl | 9 ++++ client/html/pool_navigator.tpl | 49 ++++++++++++++++++ client/html/pool_navigator_list.tpl | 4 ++ client/html/post_main.tpl | 4 ++ client/js/controllers/post_main_controller.js | 12 ++++- client/js/controls/pool_navigator_control.js | 33 ++++++++++++ .../controls/pool_navigator_list_control.js | 51 +++++++++++++++++++ client/js/models/post_list.js | 9 ++++ client/js/views/post_main_view.js | 15 ++++++ 10 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 client/css/pool-navigator-control.styl create mode 100644 client/css/pool-navigator-list.styl create mode 100644 client/html/pool_navigator.tpl create mode 100644 client/html/pool_navigator_list.tpl create mode 100644 client/js/controls/pool_navigator_control.js create mode 100644 client/js/controls/pool_navigator_list_control.js diff --git a/client/css/pool-navigator-control.styl b/client/css/pool-navigator-control.styl new file mode 100644 index 00000000..56c22d28 --- /dev/null +++ b/client/css/pool-navigator-control.styl @@ -0,0 +1,34 @@ +@import colors + +.pool-navigator-container + padding: 0 + margin: 0 auto + + .pool-info-wrapper + box-sizing: border-box + width: 100% + margin: 0 0 1em 0 + display: flex + padding: 0.5em 1em + border: 1px solid $pool-navigator-border-color + background: $pool-navigator-background-color + + .pool-name + flex: 1 1; + text-align: center; + overflow: hidden; + white-space: nowrap; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + + .first, .last + flex-basis: 1em; + + .first, .prev, .next, .last + flex: 0 1; + margin: 0 .25em; + white-space: nowrap; + + +.darktheme .pool-navigator-container + background: $pool-navigator-header-background-color-darktheme \ No newline at end of file diff --git a/client/css/pool-navigator-list.styl b/client/css/pool-navigator-list.styl new file mode 100644 index 00000000..080ad01a --- /dev/null +++ b/client/css/pool-navigator-list.styl @@ -0,0 +1,9 @@ +.pool-navigators>ul + list-style-type: none + margin: 0 + padding: 0 + + >li + margin-bottom: 1em + &:last-child + margin-bottom: 0 diff --git a/client/html/pool_navigator.tpl b/client/html/pool_navigator.tpl new file mode 100644 index 00000000..647684d8 --- /dev/null +++ b/client/html/pool_navigator.tpl @@ -0,0 +1,49 @@ +
+
+ + <% if (ctx.canViewPosts && ctx.firstPost) { %> + + <% } %> + « + <% if (ctx.canViewPosts && ctx.firstPost) { %> + + <% } %> + + + <% if (ctx.canViewPosts && ctx.previousPost) { %> + + <% } %> + ‹ prev + <% if (ctx.canViewPosts && ctx.previousPost) { %> + + <% } %> + + + <% if (ctx.canViewPools) { %> + + <% } %> + Pool: <%- ctx.pool.names[0] %> + <% if (ctx.canViewPools) { %> + + <% } %> + + + <% if (ctx.canViewPosts && ctx.nextPost) { %> + + <% } %> + next › + <% if (ctx.canViewPosts && ctx.nextPost) { %> + + <% } %> + + + <% if (ctx.canViewPosts && ctx.lastPost) { %> + + <% } %> + » + <% if (ctx.canViewPosts && ctx.lastPost) { %> + + <% } %> + +
+
diff --git a/client/html/pool_navigator_list.tpl b/client/html/pool_navigator_list.tpl new file mode 100644 index 00000000..6c60e4e2 --- /dev/null +++ b/client/html/pool_navigator_list.tpl @@ -0,0 +1,4 @@ +
+ +
\ No newline at end of file diff --git a/client/html/post_main.tpl b/client/html/post_main.tpl index 54c57333..b2e1e6f5 100644 --- a/client/html/post_main.tpl +++ b/client/html/post_main.tpl @@ -54,6 +54,10 @@
+ <% if (ctx.canListPools && ctx.canViewPools) { %> +
+ <% } %> + <% if (ctx.canListComments) { %>
<% } %> diff --git a/client/js/controllers/post_main_controller.js b/client/js/controllers/post_main_controller.js index 95cfdb52..b60a1686 100644 --- a/client/js/controllers/post_main_controller.js +++ b/client/js/controllers/post_main_controller.js @@ -11,11 +11,17 @@ const PostList = require("../models/post_list.js"); const PostMainView = require("../views/post_main_view.js"); const BasePostController = require("./base_post_controller.js"); const EmptyView = require("../views/empty_view.js"); +const PoolNavigatorListControl = require("../controls/pool_navigator_list_control.js"); class PostMainController extends BasePostController { constructor(ctx, editMode) { super(ctx); + let poolPostsNearby = Promise.resolve({results: []}); + if (api.hasPrivilege("pools:list") && api.hasPrivilege("pools:view")) { + poolPostsNearby = PostList.getNearbyPoolPosts(ctx.parameters.id) + } + let parameters = ctx.parameters; Promise.all([ Post.get(ctx.parameters.id), @@ -23,9 +29,10 @@ class PostMainController extends BasePostController { ctx.parameters.id, parameters ? parameters.query : null ), + poolPostsNearby ]).then( (responses) => { - const [post, aroundResponse] = responses; + const [post, aroundResponse, poolPostsNearby] = responses; // remove junk from query, but save it into history so that it can // be still accessed after history navigation / page refresh @@ -44,6 +51,7 @@ class PostMainController extends BasePostController { this._post = post; this._view = new PostMainView({ post: post, + poolPostsNearby: poolPostsNearby, editMode: editMode, prevPostId: aroundResponse.prev ? aroundResponse.prev.id @@ -56,6 +64,8 @@ class PostMainController extends BasePostController { canFeaturePosts: api.hasPrivilege("posts:feature"), canListComments: api.hasPrivilege("comments:list"), canCreateComments: api.hasPrivilege("comments:create"), + canListPools: api.hasPrivilege("pools:list"), + canViewPools: api.hasPrivilege("pools:view"), parameters: parameters, }); diff --git a/client/js/controls/pool_navigator_control.js b/client/js/controls/pool_navigator_control.js new file mode 100644 index 00000000..fa4394d1 --- /dev/null +++ b/client/js/controls/pool_navigator_control.js @@ -0,0 +1,33 @@ +"use strict"; + +const api = require("../api.js"); +const misc = require("../util/misc.js"); +const events = require("../events.js"); +const views = require("../util/views.js"); + +const template = views.getTemplate("pool-navigator"); + +class PoolNavigatorControl extends events.EventTarget { + constructor(hostNode, poolPostNearby) { + super(); + this._hostNode = hostNode; + this._poolPostNearby = poolPostNearby; + + views.replaceContent( + this._hostNode, + template({ + pool: poolPostNearby.pool, + parameters: { query: `pool:${poolPostNearby.pool.id}` }, + linkClass: misc.makeCssName(poolPostNearby.pool.category, "pool"), + canViewPosts: api.hasPrivilege("posts:view"), + canViewPools: api.hasPrivilege("pools:view"), + firstPost: poolPostNearby.firstPost, + previousPost: poolPostNearby.previousPost, + nextPost: poolPostNearby.nextPost, + lastPost: poolPostNearby.lastPost, + }) + ); + } +} + +module.exports = PoolNavigatorControl; \ No newline at end of file diff --git a/client/js/controls/pool_navigator_list_control.js b/client/js/controls/pool_navigator_list_control.js new file mode 100644 index 00000000..38ec2f12 --- /dev/null +++ b/client/js/controls/pool_navigator_list_control.js @@ -0,0 +1,51 @@ +"use strict"; + +const events = require("../events.js"); +const views = require("../util/views.js"); +const PoolNavigatorControl = require("../controls/pool_navigator_control.js"); + +const template = views.getTemplate("pool-navigator-list"); + +class PoolNavigatorListControl extends events.EventTarget { + constructor(hostNode, poolPostNearby) { + super(); + this._hostNode = hostNode; + this._poolPostNearby = poolPostNearby; + this._indexToNode = {}; + + for (let [i, entry] of this._poolPostNearby.entries()) { + this._installPoolNavigatorNode(entry, i); + } + } + + get _poolNavigatorListNode() { + return this._hostNode; + } + + _installPoolNavigatorNode(poolPostNearby, i) { + const poolListItemNode = document.createElement("div"); + const poolControl = new PoolNavigatorControl( + poolListItemNode, + poolPostNearby, + ); + // events.proxyEvent(commentControl, this, "submit"); + // events.proxyEvent(commentControl, this, "score"); + // events.proxyEvent(commentControl, this, "delete"); + this._indexToNode[poolPostNearby.id] = poolListItemNode; + } + + _uninstallPoolNavigatorNode(index) { + const poolListItemNode = this._indexToNode[index]; + poolListItemNode.parentNode.removeChild(poolListItemNode); + } + + _evtAdd(e) { + this._installPoolNavigatorNode(e.detail.index); + } + + _evtRemove(e) { + this._uninstallPoolNavigatorNode(e.detail.index); + } +} + +module.exports = PoolNavigatorListControl; \ No newline at end of file diff --git a/client/js/models/post_list.js b/client/js/models/post_list.js index 8c2c9d4e..0d3655be 100644 --- a/client/js/models/post_list.js +++ b/client/js/models/post_list.js @@ -16,6 +16,15 @@ class PostList extends AbstractList { ); } + static getNearbyPoolPosts(id) { + return api.get( + uri.formatApiLink("post", id, "pools-nearby", { + query: PostList._decorateSearchQuery(searchQuery || ""), + fields: "id", + }) + ); + } + static search(text, offset, limit, fields) { return api .get( diff --git a/client/js/views/post_main_view.js b/client/js/views/post_main_view.js index 5ef7f61e..88b056d4 100644 --- a/client/js/views/post_main_view.js +++ b/client/js/views/post_main_view.js @@ -57,6 +57,7 @@ class PostMainView { this._installSidebar(ctx); this._installCommentForm(); this._installComments(ctx.post.comments); + this._installPoolNavigators(ctx.poolPostsAround); const showPreviousImage = () => { if (ctx.prevPostId) { @@ -137,6 +138,20 @@ class PostMainView { } } + _installPoolNavigators(poolPostsAround) { + const poolNavigatorsContainerNode = document.querySelector( + "#content-holder .pool-navigators-container" + ); + if (!poolNavigatorsContainerNode) { + return; + } + + this.poolNavigatorsControl = new PoolNavigatorListControl( + poolNavigatorsContainerNode, + poolPostsAround, + ); + } + _installCommentForm() { const commentFormContainer = document.querySelector( "#content-holder .comment-form-container"