client: add pool navigation elements

this implementation was *heavily* cherry-picked from PR #403.
This commit is contained in:
noirscape 2023-01-04 22:00:12 +01:00
parent 00e2b503d6
commit 65a6694925
10 changed files with 219 additions and 1 deletions

View file

@ -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

View file

@ -0,0 +1,9 @@
.pool-navigators>ul
list-style-type: none
margin: 0
padding: 0
>li
margin-bottom: 1em
&:last-child
margin-bottom: 0

View file

@ -0,0 +1,49 @@
<div class='pool-navigator-container'>
<div class='pool-info-wrapper'>
<span class='first'>
<% if (ctx.canViewPosts && ctx.firstPost) { %>
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.firstPost.id, ctx.parameters) %>'>
<% } %>
«
<% if (ctx.canViewPosts && ctx.firstPost) { %>
</a>
<% } %>
</span>
<span class='prev'>
<% if (ctx.canViewPosts && ctx.previousPost) { %>
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.previousPost.id, ctx.parameters) %>'>
<% } %>
prev
<% if (ctx.canViewPosts && ctx.previousPost) { %>
</a>
<% } %>
</span>
<span class='pool-name'>
<% if (ctx.canViewPools) { %>
<a class='<%- ctx.linkClass %>' href='<%= ctx.formatClientLink("pool", ctx.pool.id) %>'>
<% } %>
Pool: <%- ctx.pool.names[0] %>
<% if (ctx.canViewPools) { %>
</a>
<% } %>
</span>
<span class='next'>
<% if (ctx.canViewPosts && ctx.nextPost) { %>
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.nextPost.id, ctx.parameters) %>'>
<% } %>
next
<% if (ctx.canViewPosts && ctx.nextPost) { %>
</a>
<% } %>
</span>
<span class='last'>
<% if (ctx.canViewPosts && ctx.lastPost) { %>
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.lastPost.id, ctx.parameters) %>'>
<% } %>
»
<% if (ctx.canViewPosts && ctx.lastPost) { %>
</a>
<% } %>
</span>
</div>
</div>

View file

@ -0,0 +1,4 @@
<div class='pool-navigators'>
<ul>
</ul>
</div>

View file

@ -54,6 +54,10 @@
<div class='content'>
<div class='post-container'></div>
<% if (ctx.canListPools && ctx.canViewPools) { %>
<div class='pool-navigators-container'></div>
<% } %>
<% if (ctx.canListComments) { %>
<div class='comments-container'></div>
<% } %>

View file

@ -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,
});

View file

@ -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;

View file

@ -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;

View file

@ -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(

View file

@ -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"