Reply/Upvote/Share Post from Category page
-
@Mickola okay. First of all, themes are plugins, so anything you can do with a plugin, you can do with a theme.
Voting is a more involved addition. You need template changes and some added JS. Prior discussion here https://community.nodebb.org/post/69597
I can send some tips for the other changes later when I'm at my PC.
-
@mickola I made some example changes here: https://github.com/NodeBB/nodebb-theme-persona/commit/12c2d19780ce7200d1187b10097af58b97164b1c
-
@pitaj , thanks. It works!
However the bookmark function doesn't work the same as the one on the post (post-menu-list.tpl). When I clicked the bookmark button, it doesn't retain the status 'bookmarked=true'. So, when I get back to the category or refresh the page, the bookmark button is going back to the defautl OFF state. However, if I click the 'bookmark' button again, it shows an error 'You have already bookmarked this post'.
Secondly, I'd like to show the number of bookmarks next to the button, similar to the one inside the post. I added:
<span class="human-readable-number" component="post/bookmark-count" data-bookmarks="{./bookmarks}">{./bookmarks}</span>
Also tried this one:
<span class="human-readable-number" component="post/bookmark-count" data-bookmarks="{./posts.bookmarks}">{./posts.bookmarks}</span>
Both doesn't update the bookmark count at all.
Lastly, I'd like to add a sharing function (from post-menu-list.tpl) to category. This is what I added to topics_list.tpl
<!-- Share --> <span class="share-tools"> <a href="#" data-toggle="dropdown" title="[[topic:share_this_post]]"><i class="fa fa-16px fa-fw fa-share"></i></a> <ul class="dropdown-menu" role="menu"> <!-- IF postSharing.length --> <li class="dropdown-header">[[topic:share_this_post]]</li> <!-- ENDIF postSharing.length --> {{{each post.index.postSharing}}} <li> <a role="menuitem" component="share/{postSharing.id}" tabindex="-1" href="#"><span class="menu-icon"><i class="fa fa-fw {postSharing.class}"></i></span> {postSharing.name}</a> </li> {{{end}}} </ul> </span> <!-- /Share -->
It seems 'postSharing' doesn't return anything. Can you point me to the right direction?
Thanks!
-
However the bookmark function doesn't work the same as the one on the post (post-menu-list.tpl). When I clicked the bookmark button, it doesn't retain the status 'bookmarked=true'. So, when I get back to the category or refresh the page, the bookmark button is going back to the defautl OFF state. However, if I click the 'bookmark' button again, it shows an error 'You have already bookmarked this post'.
This does not happen in my dev environment. How did you go about implementing the changes? And what version of NodeBB are you on?
Secondly, I'd like to show the number of bookmarks next to the button, similar to the one inside the post.
By default NodeBB does not provide that information along with the topic. Do you see the addition to
library.js
?library.getTopics = async (data) => { const pids = data.topics.map(x => x.mainPid); const [{ upvotes, downvotes }, bookmarked] = await Promise.all([ Posts.getVoteStatusByPostIDs(pids, data.uid), Posts.hasBookmarked(pids, data.uid), ]); data.topics.forEach((topic, i) => { topic.upvoted = upvotes[i]; topic.downvoted = downvotes[i]; topic.bookmarked = bookmarked[i]; }); return data; };
This adds the extra information to the topic for displaying whether the current user upvoted, downvoted, or bookmarked the main post. You'll need to do something similar for adding the number of bookmarks. Hint:
Posts.getPostsFields(pids, ['bookmarks'])
You'll need to do a similar thing for the
postSharing
stuff, which looks like you'll wantSocial.getActivePostSharing()
.Tip:
ajaxify.data
in the browser holds the data that the current page was rendered with. Use it to explore what data is available from the browser console. You can compare what's available on the topic page vs the category page and add what you need. -
@pitaj , I implemented the changed by creating a child theme and added the scripts there. I have NodeBB 1.16.0.
If a post hasn't been bookmarked yet, I am able to toggle it back & forth. However, if it's already bookmarked, the bookmark icon shows the off-state and when I click it, it shows an error. This is the error I got:
Error: [[error:already-bookmarked]] at toggleBookmark (E:\Projects\my.forum.test\src\posts\bookmarks.js:28:10) at runMicrotasks (<anonymous>) at processTicksAndRejections (internal/process/task_queues.js:97:5) at async Posts.bookmark (E:\Projects\my.forum.test\src\posts\bookmarks.js:8:10) at async executeCommand (E:\Projects\my.forum.test\src\api\helpers.js:120:17) at async Object.exports.postCommand (E:\Projects\my.forum.test\src\api\helpers.js:116:9) at async Object.postsAPI.bookmark (E:\Projects\my.forum.test\src\api\posts.js:210:9) at async Posts.bookmark (E:\Projects\my.forum.test\src\controllers\write\posts.js:67:2) at async E:\Projects\my.forum.test\src\routes\helpers.js:34:5
-
@mickola that's simply not the behavior I see in my environment. Are you sure you made all of the changes correctly? You could try placing a
console.log
ingetTopics
to make sure it's firing when you load a category page.Share your child theme theme.json and plugin.json
-
I use https://github.com/nodebb/nodebb-theme-quickstart to create a child theme and added the following based on your changes.
plugin.json:
{ "id": "nodebb-theme-mytheme", "main": "./lib/theme.js", "hooks": [ { "hook": "filter:widgets.getAreas", "method": "defineWidgetAreas" }, { "hook": "filter:category.topics.get", "method": "getTopics" } ], "scripts": [ "./lib/client.js", "../nodebb-theme-persona/public/persona.js", "../nodebb-theme-persona/public/modules/autohidingnavbar.js", "../nodebb-theme-persona/public/modules/quickreply.js" ], "modules": { "pulling.js": "node_modules/pulling/build/pulling-drawer.js" } }
theme.js
(function(module) { "use strict"; var Posts = require.main.require('./src/posts'); var Theme = {}; Theme.defineWidgetAreas = function(areas, callback) { areas = areas.concat([ { 'name': 'MOTD', 'template': 'home.tpl', 'location': 'motd' }, { 'name': 'Homepage Footer', 'template': 'home.tpl', 'location': 'footer' }, { 'name': 'Category Sidebar', 'template': 'category.tpl', 'location': 'sidebar' }, { 'name': 'Topic Footer', 'template': 'topic.tpl', 'location': 'footer' } ]); callback(null, areas); }; Theme.getTopics = async (data) => { const pids = data.topics.map(x => x.mainPid); const [{ upvotes, downvotes }, bookmarked, bookmarks, sharing] = await Promise.all([ Posts.getVoteStatusByPostIDs(pids, data.uid), Posts.hasBookmarked(pids, data.uid), Posts.getPostsFields(pids, ['bookmarks']), Social.getActivePostSharing(pids) ]); data.topics.forEach((topic, i) => { topic.upvoted = upvotes[i]; topic.downvoted = downvotes[i]; topic.bookmarked = bookmarked[i]; topic.bookmarks = bookmarks[i]; topic.sharing = sharing[i]; }); console.log(data); return data; }; module.exports = Theme; }(module));
client.js
$(document).ready(function() { require(['forum/topic/votes', 'api'], function (votes, api) { function bookmarkPost(button) { var method = button.attr('data-bookmarked') === 'false' ? 'put' : 'del'; var pid = button.closest('[data-pid]').attr('data-pid'); api[method](`/posts/${pid}/bookmark`, undefined, function (err) { if (err) { return app.alertError(err); } var type = method === 'put' ? 'bookmark' : 'unbookmark'; $(window).trigger('action:post.' + type, { pid: pid }); }); return false; } $(document).on('click', '[component="category/topic"] [component="post/upvote"]', function () { console.log('upvote'); return votes.toggleVote($(this), '.upvoted', 1); }); $(document).on('click', '[component="category/topic"] [component="post/downvote"]', function () { console.log('downvote'); return votes.toggleVote($(this), '.downvoted', -1); }); $(document).on('click', '[component="category/topic"] [component="post/bookmark"]', function () { console.log('bookmark'); return bookmarkPost($(this)); }); }); $(document).on('click', '[component="category/topic"] [component="post/flag"]', function () { var pid = getData($(this), 'data-pid'); require(['flags'], function (flags) { flags.showFlagModal({ type: 'post', id: pid, }); }); }); $(document).on('click', '[component="category/topic"] [component="post/flagUser"]', function () { var uid = getData($(this), 'data-uid'); require(['flags'], function (flags) { flags.showFlagModal({ type: 'user', id: uid, }); }); }); function getData(button, data) { return button.parents('[data-pid]').attr(data); } function togglePostVote(data) { var post = $('[component="category/topic"] [data-pid="' + data.post.pid + '"]'); post.find('[component="post/upvote"]').toggleClass('upvoted', data.upvote); post.find('[component="post/downvote"]').toggleClass('downvoted', data.downvote); post.find('[component="post/vote-count"]').html(data.post.votes).attr('data-votes', data.post.votes); } socket.on('posts.upvote', togglePostVote); socket.on('posts.downvote', togglePostVote); socket.on('posts.unvote', togglePostVote); function togglePostBookmark(data) { var el = $('[data-pid="' + data.post.pid + '"] [component="post/bookmark"]'); if (!el.length) { return; } el.attr('data-bookmarked', data.isBookmarked); el.find('[component="post/bookmark/on"]').toggleClass('hidden', !data.isBookmarked); el.find('[component="post/bookmark/off"]').toggleClass('hidden', data.isBookmarked); el.find('[component="post/bookmarks"]').html(data.bookmarks).attr('data-bookmarks', data.bookmarks); } socket.on('posts.bookmark', togglePostBookmark); socket.on('posts.unbookmark', togglePostBookmark); });
Note:
console.log
ingetTopics
isn't triggered.Originally, I tried to add the changes straight to 'nodebb-theme-persona', but the result is still the same (and
console.log
ingetTopics
doesn't seem to be executed). -
Note: console.log in getTopics isn't triggered.
Well that would be why it's not working for you. Are there any errors on nodebb startup?
I'm using master, it shouldn't make a difference but you could try that instead of 1.16.0
-
@mickola well yes, the second hook should also work, but either one should work for what you're doing.