Skip to content
  • 0 Votes
    2 Posts
    520 Views
    barisB
    A hook is fired when that page is loaded it is filter:account/profile.build
  • Calendar Plugin/API?

    General Discussion
    3
    0 Votes
    3 Posts
    726 Views
    dunlixD
    @esha search in ACP plugins for nodebb-plugin-calendar
  • 0 Votes
    2 Posts
    756 Views
    M
    After some more code digging and experiments I can answer my own question. A theme is a normal plugin and as such does not inherit any behavior from other plugins. So you need to copy everything you need from the base theme library.js to your child theme. And of course, you need to declare client scripts explicitly. Loading of missing templates from base theme is the only link between the base and the child theme.
  • How to write hooks

    Tutorials
    5
    6 Votes
    5 Posts
    1k 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
  • On v1.17 carousal slider issue

    Technical Support
    3
    0 Votes
    3 Posts
    757 Views
    Varun Ganesh DV
    @dogs thank you Issue resolved
  • How to make custom JS persist

    Technical Support
    5
    0 Votes
    5 Posts
    996 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
  • iframely plugin doesn't work...

    Technical Support
    17
    1 Votes
    17 Posts
    4k 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
    677 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. [image: tenor.gif] 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. [image: 1617153057423-bildschirmfoto-2021-03-31-um-03.10.32.png] [image: tenor.gif] 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
    1k Views
    dogsD
    @pitaj Nice that was easy! Thank you
  • 0 Votes
    5 Posts
    948 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
    3k 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)
  • Unable to install plugin

    NodeBB Plugins
    2
    0 Votes
    2 Posts
    807 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
    956 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
    3k 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.
  • [nodebb-plugin-feed] NodeBB Feed Plugin

    NodeBB Plugins
    19
    7 Votes
    19 Posts
    3k Views
    barisB
    @dave1904 thanks for reporting, fixed in 3.1.27.
  • 6 Votes
    3 Posts
    1k 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. [image: 1611963514006-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
    863 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
    1k 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
  • nodebb-plugin-db-explorer

    NodeBB Plugins
    6
    3 Votes
    6 Posts
    1k Views
    JürgenJ
    It finally showed up - but that definitely took a quite a while. Maybe I was fooled by cached content?