Triggering on events in userscript (rather than plugin)

NodeBB Plugins
  • Sorry this isn't actually about a plugin, but this seemed like the most reasonable forum for the question regardless...

    I'm a member of a forum where users want to be able to ignore users and threads, but the administrators don't want to write/install plugins for it. So, I decided I could at least write a userscript to let people do it clientside.

    It's trivial to hide the posts/topics on initial load. However, I'm having some trouble getting hold of a trigger when pages are changed -- for example, going from Unread Topics to Recent Topics, or scrolling down an infinite scroll. It seems as though global for ajax is set to false, so I can't have the script react to these changes as I normally would. Is there a way to access the nodeBB hooks documented for plugins from a userscript? action:topics.loaded seems (at least on the surface of it) as though it would be a good event to use for thread ignoring, for example, but I can't seem to get at it.

    Thanks!

  • https://github.com/NodeBB/NodeBB/wiki/Hooks#client-side-hooks should help, there is a hook for all the things you mentioned, like infinite scroll loading more posts/topics or changing between pages etc.

  • @baris
    Thank you for the reply! Unfortunately, that's where I'd found their existence (and why I knew about action:topics.loaded). It's just that the hooks don't seem to work in my userscript. For example, if I put in:

    $(window).on('action:ajaxify.end', function(event, data) {
    alert('ok');
    });

    ...there are never any alerts. If I change 'action:ajaxify.end' to 'click', I get alerts when the window's clicked, as one would expect. Is there something special I need to do to access them outside an actual plugin?

  • @Ninjakitten said:

    $(window).on('action:ajaxify.end', function(event, data) {
    alert('ok');
    });

    Where are you putting this?

  • @baris

    Currently, not including the userscript header, the script is:

    this.$ = this.jQuery = jQuery.noConflict(true);

    var names = ["Name1","Name2","NameN"];

    $.each(names,function(index,value) {
    $('li[data-username="'+value+'"]').css('display','none');
    $('strong:contains("'+value+'")').parent('p').parent('.card').css('display','none');
    });

    $(window).on('action:ajaxify.end', function(event, data) {
    alert('ok');
    });

  • What I meant is how are you including that piece of code in nodebb? The event handler should work if you simply put it in /admin/appearance/customise#custom-header

  • Oh. As I've been saying, it's a userscript, i.e., for Greasemonkey and its ilk, in the browser, because I have absolutely no control over the nodebb board in question or anything on the server. The people who do aren't willing to make or install plugins to allow ignoring users or threads, which is why I'm trying to make an entirely clientside solution for the people who are unhappy -- thus, userscript.

    So the answer is that it's not being included in nodebb , and can't be. It has to act on it from outside. Usually, this is simple, but because it appears ajax has had global set to false in nodebb, it becomes almost impossible unless there's some way to access those special hooks from clientside.

  • There are two possible sources of failure:

    1. The @run-at option must be set to document-end or document-idle for your script to work (It should be document-end by default).
      So the document-start option for example wouldn't work quite well (It'd get executed before dependency scripts such as jquery are loaded).
      It's not helpful to completely hide the userscript meta from us 😉 (just enclose codes with ``` for future posts 👍 )
      Check out the docs for more details.

    2. Your script seems to call jQuery.noConflict(true), I don't think this is what you're trying to achieve. Please check the docs.
      Calling this removes the window.jQuery and window.$ bindings which causes the entire NodeBB board to break apart.

    So this is working (Tampermonkey, chromium) while keeping separated scope for $:

    // ==UserScript==
    // @name         New Userscript
    // @namespace    http://tampermonkey.net/
    // @version      0.1
    // @description  try to take over the world!
    // @author       Jon Doe
    // @match        https://community.nodebb.org/*
    // @run-at       document-end
    // @grant        none
    // ==/UserScript==
    'use strict';
    
    (function ($) {
        var names = ["Name1","Name2","NameN"];
    
        $.each(names,function(index,value) {
            $('li[data-username="'+value+'"]').css('display','none');
            $('strong:contains("'+value+'")').parent('p').parent('.card').css('display','none');
        });
    
        $(window).on('action:ajaxify.end', function(event, data) {
            alert('ok');
        });
    })(jQuery)
    

    Keeping everything of your script within an IIFE is best practice for userscripts in general ;).

  • @frissdiegurke
    Thank you! That sorted it out. Very much appreciated. 🙂


Suggested Topics


  • Need help with plugin Hyde

    NodeBB Plugins
    0 Votes
    1 Posts
    581 Views
  • 1 Votes
    5 Posts
    1383 Views
  • official paid membership plugin

    Unsolved NodeBB Plugins
  • nodebb-plugin-wechat-share

    NodeBB Plugins
    0 Votes
    2 Posts
    1383 Views
  • 0 Votes
    1 Posts
    835 Views