Skip to content
  • 6 Votes
    5 Posts
    974 Views
    barisB

    Quick start plugin has an example on how to add a new api route https://github.com/NodeBB/nodebb-plugin-quickstart/blob/master/library.js#L40-L76.

    The hooks that are fired client side are for client side code in plugins. If you want to pass data from the client to the server you have two options.

    Create an api route like in quick start plugin Create a new socket event listener on the server side and use socket.emit() client side. Example here
  • 0 Votes
    3 Posts
    591 Views
    Varun Ganesh DV

    @dogs thank you
    Issue resolved

  • 0 Votes
    5 Posts
    815 Views
    phenomlabP

    @dogs this worked a treat - thanks. For anyone else who might be looking for something similar, here's a simple scroll to top function that you can place into your Custom JS

    // Scroll to top button $(window).on('action:ajaxify.end', function(data) { var btn = $('#btt'); $(window).scroll(function() { if ($(window).scrollTop() > 300) { btn.addClass('show'); } else { btn.removeClass('show'); } }); btn.on('click', function(e) { e.preventDefault(); $('html, body').animate({scrollTop:0}, '300'); }); })

    Then place this into your Custom Header

    <a id="btt"><i class="fas fa-chevron-up"></i></a>

    Obviously, you would need to provide some CSS to style this. An example of this can be found on https://phenomlab.com

  • 1 Votes
    17 Posts
    3k Views
    phenomlabP

    Hi All,

    As much as I dislike cross posting, can anyone help with this ?
    https://community.nodebb.org/topic/16231/iframely-help

  • 0 Votes
    1 Posts
    586 Views
    dogsD
    This is just a little snippet.

    This is about the question How can I add custom data to a post? a small tutorial

    How to add custom data permanently to a post It will be saved into the object:

    You need the following hook:

    { "hook": "filter:post.create", "method": "postCreate" }

    This hook is fired, when a Post is created. So it contains RAW Data.

    A filter:hook like "hook": "filter:post.create" can be edited before beeing proceeded.

    plugin.postCreate = function(data, callback){ // Edit data here callback(null, data); }

    You can access all Data you can work with via the data object.

    All those filter-hooks needs callbacks. The callback contains the modified / added / removed data.

    Whats inside the data object?

    The data object contains two main objects.

    this.post this.data post: { pid: 259, uid: 2, tid: 111, content: '### This is just a little snippet.', timestamp: 1617150411838 }, data: { uuid: '7277s31-6d23-43sa-1284-ad27e42yx879', title: 'How to add custom data to post serverside - in a nutshell', content: '### This is just a little snippet.', thumb: '', cid: '2', tags: [], uid: 2, req: { [...] }, timestamp: 1617150411838, fromQueue: false, tid: 111, ip: '111.123.2123.21', isMain: true } }

    With all the data you can work with. But only this.post is directly effected (lol) to the post Object.
    If you add data here. It will be attached to the post forever and you can access it any time. Even after plugin disable.

    So now add custom data:

    plugin.postCreate = function(data, callback){ // adds data **PERMANENT** to post // before any other procession -> RAW DATA (markdown) //data.post.myData = "directly effected to post you can work with it in next step"; //data.data.myData = "other data for other things I don't know"; var myData = {}; myData.name = "Schmock"; myData.signature = "raz0rn"; // Stick myData to post object data.post.myData = myData; // Debug? // console.log("POST CREATE", data); // finish the process() - passes on modified data callback(null, data); }

    So myData has added to post:

    post: { pid: 259, uid: 2, tid: 111, content: '### This is just a little snippet.', timestamp: 1617150411838, myData: { name = "Schmock", signature = "raz0rn", } }

    The data is stored. Everybody is happy.

    dance minions

    How to add dynamic data before render a post in template It wont be saved to the object. You can use this for dynamic things or logic before rendering the page.:

    You need the following hook:

    { "hook": "filter:topics.addPostData", "method": "addPostData" }

    This hook is fired before engine renders the template.
    It also needs a callback because its a filter-hook.

    plugin.addPostData = function(data, callback){ // modify data temporarily before it gets passed on to next step callback(null, data); }

    Same thing as above. Only the hook is different. And the data we are changing is temporarily.
    Data contains all data we can use for the dynamicness lol: .

    plugin.addPostData = function(data, callback){ // You can work with pre-parsed and already saved data .... // or put in something very flexible without saving to db like jquery-like dynamic etc etc // Debug? // console.log("addPostData?", data) var _posts = data.posts; _posts.forEach(function(post){ if(post.myData){ // add data to post if "myData" is there post.content = "THIS POST HAS MY OWN DATA -> CONTENT IS OVERWRITTEN"; } // this here affects all posts post.user.signature = "Ihr seid alle Schmocks!"; }); // Overwrite data and pass modified data on to the template engine data.posts = _posts; callback(null, data); }

    Now you can work with posts like a boss.

    Bildschirmfoto 2021-03-31 um 03.10.32.png

    dab

    Thanks and bye

    Important Note:

    Remind, that myData is available via API.

    https://nodebb.development.fail/api/topic/114/new-post

    returns your added data

    "content": "THIS POST AS MY OWN DATA -> CONTENT IS OVERWRITTEN", "myData": { "name": "Schmock", "signature": "raz0rn" }
  • 0 Votes
    5 Posts
    953 Views
    dogsD

    @pitaj Nice that was easy! Thank you 🙂

  • 0 Votes
    5 Posts
    745 Views
    E

    @dogs Thanks.
    Can you point me to some materials explaining how the frontend and hooks interact?
    I don't complete follows their discussion on data.submittedData and is still confused about which variable is the post data stored in and which hooks are involved when it is passed around.

    Edit:
    Also found this, maybe relevant
    Difference between templateValues and templateData

  • 0 Votes
    18 Posts
    2k Views
    barisB

    Yes you can use them inside the AMD module but keep in mind once you add an event listener on the window object it will be called everytime there is an action:ajaxify.end. If you don't want it triggered after you leave that page you need to turn it off with $(window).off('eventName', myMethod)

  • 0 Votes
    2 Posts
    678 Views
    dunlixD

    @piyush try installing with npm after opening a terminal in your nodebb folder.

    npm install nodebb-plugin-whitelist-email-domains

    then go to plugin page and activate it, rebuild and restart.

  • 0 Votes
    11 Posts
    1k Views
    Keng HerK

    @dogs
    Not sure if this is still relevant to you, but I followed your code and was getting the same results. The code wasn't firing despite having a console log in the theme.js file.

    Then I decided to click on the 'Clone widgets from...' and selected 'Categories'. After that all of the .tpl names showed up in the drop down. After that any changes to the theme.js file are firing as should.

    Make sure you build and restart. I am using the included GRUNT to make development faster. Cheers!

  • 2 Votes
    3 Posts
    784 Views
    dogsD

    @aleksei I read your topic: https://community.nodebb.org/topic/15252/execute-custom-js-on-infinite-scroll and saw you're dealing with C4D-Files. 😄

  • 10 Votes
    6 Posts
    2k Views
    Spin0usS

    @dogs thank for this plugin 👍
    Here is the way i installed it :

    npm install git+https://github.com/me-cooper/nodebb-plugin-makesmart-gallery.git

    Hope this help.

  • 7 Votes
    16 Posts
    2k Views
    crazycellsC

    previously I wrote here: https://community.nodebb.org/post/87648

    this custom CSS (what baris mentioned above) is related to the Feed plugin as well...

    .posts-list .posts-list-item .content { overflow: auto; max-height: 480px; }

    with this change, people can go through all the posts by scrolling on the same page... feel free to change the post height...

  • 6 Votes
    3 Posts
    949 Views
    manolinoM

    @kadmy , sure: upload the file controls.png from the plugin folder \node_modules\bxslider\dist into NodeBB assets. The file looks like the bitmap below.

    controls.png
    Then change the LESS to

    .my-wrapper { box-shadow: none; border: none; .bx-prev { background: url(/assets/uploads/controls.png) no-repeat 0px -32px; } .bx-next { background: url(/assets/uploads/controls.png) no-repeat -43px -32px; } }

    This file contains the standard bxSlider. But you can use any other icon. Just upload it or point to the url of your preference.

    Please update to v0.1.2 for more fixes.

  • 0 Votes
    6 Posts
    661 Views
    murcsM

    @DownPW said in [nodebb-widget-board-stats] discrepancy to dashboard count:

    any news @murcs ?

    i just digged a little deeper for you: „our“ /var/www/nodebb/node_modules/nodebb-widget-board-stats/library.js looks like this

    'use strict'; const async = require('async'); const nconf = module.parent.require('nconf'); const db = require.main.require('./src/database'); const user = require.main.require('./src/user'); const utils = require.main.require('./src/utils'); const socketPlugins = require.main.require('./src/socket.io/plugins'); const socketRooms = require.main.require('./src/socket.io/admin/rooms'); let app; const Widget = module.exports; Widget.init = function (params, callback) { app = params.app; callback(); }; socketPlugins.boardStats = {}; socketPlugins.boardStats.get = function (socket, tid, callback) { getWidgetData(callback); }; function addDots(text) { return String(text).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.'); }; function getWidgetData(callback) { async.parallel({ global: function (next) { db.getObjectFields('global', ['topicCount', 'postCount', 'userCount'], next); }, latestUser: getLatestUser, activeUsers: getActiveUsers, onlineUsers: Widget.updateAndGetOnlineUsers, activeWithin24h: function (next) { var now = Date.now(); db.sortedSetCount('users:online', now - 86400000, '+inf', next); }, }, function (err, results) { if (err) { return callback(err); } var data = { within24h: results.activeWithin24h, count: addDots(results.onlineUsers.onlineCount + results.onlineUsers.guestCount), members: addDots(results.onlineUsers.onlineCount), guests: addDots(results.onlineUsers.guestCount), list: joinUsers(results.activeUsers), posts: addDots(results.global.postCount ? results.global.postCount : 0), topics: addDots(results.global.topicCount ? results.global.topicCount : 0), registered: addDots(results.global.userCount ? results.global.userCount : 0), latest: joinUsers(results.latestUser), relative_path: nconf.get('relative_path'), mostUsers: { date: (new Date(parseInt(results.onlineUsers.timestamp, 10))).toDateString(), total: results.onlineUsers.total, }, }; callback(null, data); }); } function getActiveUsers(callback) { async.waterfall([ function (next) { user.getUidsFromSet('users:online', 0, 19, next); }, function (uids, next) { user.getUsersFields(uids, ['username', 'userslug', 'status'], next); }, ], function (err, data) { if (err) { return callback(err); } data = data.filter(function (a) { return a.status === 'online'; }); callback(err, data); }); } function getLatestUser(callback) { async.waterfall([ function (next) { user.getUidsFromSet('users:joindate', 0, 0, next); }, function (uids, next) { user.getUsersWithFields(uids, ['username', 'userslug'], 0, next); }, ], callback); } function joinUsers(usersData) { var str = []; for (var i = 0, ii = usersData.length; i < ii; i++) { str.push('<a href="' + nconf.get('relative_path') + '/user/' + usersData[i].userslug + '">' + usersData[i].username + '</a>'); } return str.join(', '); } Widget.updateAndGetOnlineUsers = function (callback) { callback = typeof callback === 'function' ? callback : function () {}; async.waterfall([ function (next) { next(null, socketRooms.getLocalStats().onlineRegisteredCount); }, function (onlineCount, next) { socketRooms.getTotalGuestCount(function (err, guestCount) { if (err) { return next(err); } next(null, { onlineCount: parseInt(onlineCount, 10), guestCount: parseInt(guestCount, 10), }); }); }, function (users, next) { db.getObjectFields('plugin:widget-board-stats', ['total', 'timestamp'], function (err, data) { if (err) { return next(err); } var totalUsers = users.onlineCount + users.guestCount; data.timestamp = data.timestamp || Date.now(); if (parseInt(data.total || 0, 10) <= totalUsers) { data.timestamp = Date.now(); data.total = totalUsers; db.setObject('plugin:widget-board-stats', data); } data.onlineCount = users.onlineCount; data.guestCount = users.guestCount; return next(null, data); }); }, ], callback); }; Widget.renderWidget = function (widget, callback) { getWidgetData(function (err, data) { if (err) { return callback(err); } app.render('widgets/board-stats', data, function (err, html) { if (err) { return callback(err); } widget.html = html; callback(null, widget); }); }); }; Widget.defineWidgets = function (widgets, callback) { var widget = { widget: 'board-stats', name: 'Board Stats', description: 'Classical board stats widget in real-time.', content: 'admin/board-stats', }; app.render(widget.content, {}, function (err, html) { widget.content = html; widgets.push(widget); callback(err, widgets); }); };

    which corresponds with our localized version of /var/www/nodebb/node_modules/nodebb-widget-board-stats/public/templates/widgets/board-stats.tpl

    <div component="widget/board-stats" class="widget-board-stats" style="border: 1px solid #999"> <h3 style="background: #666; font-size: 15px; font-weight: 500">Folgende Nutzende sind gerade online: <a href="{config.relative_path}/users?section=online">[komplette Liste]</a></h3> <p> Davon sind aktuell <strong component="widget/board-stats/count">{count}</strong> Nutzende aktiv (<strong component="widget/board-stats/members">{members}</strong> Registrierte + <strong component="widget/board-stats/guests">{guests}</strong>G&auml;ste).<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> <span component="widget/board-stats/list">{list}</span> <span style="display: block; line-height: 0.5em" >&nbsp;</span> In den letzten 24 Stunden waren <strong component="widget/board-stats/within24h">{within24h}</strong> verschiedene Nutzende eingeloggt. </p> <h3 style="background: #666; font-size: 15px; font-weight: 500">Forum-Statistik</h3> <p> Unsere aktiven registrierten Mitglieder haben <strong component="widget/board-stats/posts">{posts}</strong> Beitr&auml;ge zu <strong component="widget/board-stats/topics">{topics}</strong> Themen verfasst &ndash;<strong component="widget/board-stats/registered">{registered}</strong> Mitglieder sind bei <em>schoenen-dunk.de</em> registriert.<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> <span component="widget/board-stats/latest">{latest}</span> ist unser neuestes Mitglied.&nbsp;Herzlich Willkommen!<br /> <span style="display: block; line-height: 0.5em" >&nbsp;</span> Am {mostUsers.date} waren <strong>{mostUsers.total}</strong> Nutzende gleichzeitig online. </p> </div>

    well.  i hope this helps a bit.

    ober!schöne grüße,
    m.

  • 0 Votes
    5 Posts
    924 Views
    dogsD

    @baris Thank you very much. This worked! 🙂

    €: I additionally use the hook

    $(window).on('action:ajaxify.start', function (ev, data) { $('div.topic-header-image').hide(); });

    so that the header container with the image is hiding immediatly and before ajaxify.end 👍

  • 3 Votes
    6 Posts
    938 Views
    JürgenJ

    It finally showed up - but that definitely took a quite a while. Maybe I was fooled by cached content?

  • 0 Votes
    3 Posts
    879 Views
    G

    @mana Thank you

  • 0 Votes
    1 Posts
    343 Views
    magnusvhendinM

    Is there some way to hide all topics within a category from all feeds (recent, popular, new, the digest)?

    I need the topics to be accessible (and usable) to all users directly, but not searchable or showing up at random.

  • 0 Votes
    7 Posts
    1k Views
    dogsD

    @pitaj Many thanks for your effort 🙏

    Okay so I just npm link'ed my plugin again so I thought some file will be updated. But they weren't.

    Here is my full source code of libary.js:

    'use strict'; /* NodeBB Basic Plugin Libraries */ const controllers = require('./lib/controllers'); const plugin = {}; /* Third Party Libraries */ const Discord = require("discord.js"); const fs = require("fs"); // Nodebb Discord Bot const config = JSON.parse(fs.readFileSync("./utils/config.json", "utf-8")); var client = new Discord.Client(); let debug = true; plugin.init = function (params, callback, client) { myDebug("nodebb-discord-bot-started"); callback(); }; function myDebug(msg){ if(debug){ console.log(msg); } } module.exports = plugin; 2021-01-12T10:46:19.318Z [4567/4689] - error: Error: ENOENT: no such file or directory, open './utils/config.json' at Object.openSync (fs.js:462:3) at Object.readFileSync (fs.js:364:35) at Object.<anonymous> (/home/ubuntu/nodebb-linked-modules/nodebb-plugin-makesmart-discord-bot/library.js:15:30) at Module._compile (internal/modules/cjs/loader.js:999:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) at Module.load (internal/modules/cjs/loader.js:863:32) at Function.Module._load (internal/modules/cjs/loader.js:708:14) at Module.require (internal/modules/cjs/loader.js:887:19) at require (internal/modules/cjs/helpers.js:74:18) at Object.Plugins.requireLibrary (/home/ubuntu/nodebb/src/plugins/index.js:70:39)

    I tried it with path again:

    // Nodebb Discord Bot var configpath = path.join(__dirname, 'utils', 'config.json'); const config = JSON.parse(fs.readFileSync(configpath, "utf-8")); var client = new Discord.Client();

    an suddenly ... it worked! o.O

    2021-01-12T10:51:15.711Z [4567/4765] - info: [api] Adding 2 route(s) to `api/v3/plugins` 2021-01-12T10:51:15.889Z [4567/4765] - info: Routes added 2021-01-12T10:51:15.933Z [4567/4765] - info: NodeBB Ready 2021-01-12T10:51:15.943Z [4567/4765] - info: Enabling 'trust proxy' 2021-01-12T10:51:15.972Z [4567/4765] - info: NodeBB is now listening on: 0.0.0.0:4567

    I think it was really because I ran npm link again. Funny.* I'm sorry. Most of the time, the problem is in front of the computer. 🙄

    But still a strange behavior in my opinion. Well ... Good to know for the future. @PitaJ as mentioned thank you for you effort. 🙏

    For any others having the same issue:

    Read the Stackoverflow Solution posted by @PitaJ right here If it still not work use npm link in ./nodebb again to refresh something in the plugin folder ...I dont know tbh ... 😄