Skip to content

Threaded post support for NodeBB

Let's Build It
  • @DownPW said in Threading support for NodeBB:

    Do you know where it could come from?

    Yes, just fixed it in your dev environment. I assumed (probably incorrectly) that people may not have this installed, so omitted it. I fixed it in prod because I do have it there, but wanted to keep DEV as vanilla as possible.

    I’ll need to write a function that checks for the existence of this plugin then determines where to inject the toggle switch

    For now, see the below

    $('.topic .sticky-tools ul .hidden-xs').append(threadView);
                    // If you have browsing users plugin, comment out the above line and uncomment the one below
                    //$('.topic .sticky-tools ul [component="topic/browsing-users"]:last-of-type').append(threadView);
    

    Result (might need some position tweaking…)

    b0de4f7a-55bb-4611-93e5-f43f211b8a70-image.png

  • Good, thanks!!!
    Test asap, i’m on intervention AT work

  • @phenomlab said in Threading support for NodeBB:

    EDIT 2 - I just noticed on your DEV box that you have (thanks to me - sorry) a ton of JS code you don’t need. You should probably clean that up.

    no I need it 😉

    @phenomlab said in Threading support for NodeBB:

    @DownPW said in Threading support for NodeBB:

    Can we do the same thing but without expanding the topic toolbar on header ?

    Yes, but then you’ll have elements that are wider than the sticky bar which looks odd on scroll.

    Could you still explain to me how to obtain this result so that I can see what I prefer?

  • @DownPW said in Threading support for NodeBB:

    Could you still explain to me how to obtain this result so that I can see what I prefer?

    Yes, of course. Locate the below block in the CSS, and comment out margin-left: -8%;

      .topic .threaded.sticky-tools { 
         margin-left: -8%; 
         margin-top: 0px; 
         margin-bottom: 0px; 
         transition: margin-left 0.3s ease, margin-right 0.3s ease; 
       }
    
  • Great, thank you Mark !

    –> I also have a little suggestion to add a tooltip on the button mouse hover like "Thread view On and thread View Off depending on the state or maybe just one?

    What do you think about it ?

  • @DownPW said in Threading support for NodeBB:

    What do you think about it ?

    Great idea. I’ll add that.

  • maybe with an HTML SPAN class like this ?

    <span class="title-tooltip top" tooltip-text="Thread View On">
    
  • @DownPW yes, that should work, although probably better to use one tooltip with on/off text.

  • Small specific request.

    I try to adapt the code to my environment.

    I modified the background of the following classes:

    .page-topic .topic .posts.timeline .timeline-event,
    .page-topic .topic .posts.timeline > [component="post/placeholder"],
    .page-topic .topic .posts.timeline > [component="post"] {
      border-left: none;
      transition: transform 0.3s ease !important;
      background: var(--bs-body-bg);
      background: var(--bs-body-navbar);
    }
    
    .post-container.threaded {
      background: var(--bs-body-bg) !important;
      background: var(--bs-body-navbar)!important;
    }
    
    li.pt-4.self-post:not(.self-post .topic-owner-post).threaded {
      transform: translateX(0px) !important;
      transition: transform 0.3s ease !important;
      background: var(--bs-body-bg);
      background: var(--bs-body-navbar)!important;
      padding-right: 30px;
    }
    

    and other code, for example :

    .page-topic .topic .posts.timeline [component="topic/event"].timeline-event, .page-topic .topic .posts.timeline [component="topic/necro-post"].timeline-event {
        background: transparent;
    }
    
    .page-topic .topic .posts.timeline .timeline-event:last-child, .page-topic .topic .posts.timeline>[component="post/placeholder"]:last-child, .page-topic .topic .posts.timeline>[component=post]:last-child {
        margin-left: 0.5rem;
    }
    

    When I activate mode it works without problem but it does not disappear when I deactivate the mode. (Return to vanilla)

    I think I understand by reading the code that it is necessary to specify the classes chnaged in the function.js (with add .threaded) but I don’t really see how to add more

    f0208e5f-2863-48df-98a7-273e8a944377-image.png

  • @DownPW any reason as to why you’ve defined background twice ?

    See

    background: var(--bs-body-bg);
    background: var(--bs-body navbar)!important;
    
  • I have just forget to delete the first but this nothing change.

  • @DownPW just curious 🤭

    The second would override the first anyway.

    I’m in transit currently and not in front of a pc but will review this as soon as I can.

  • i have a problem with my codes 😞

    image.png

  • phenomlabundefined phenomlab referenced this topic on
  • @phenomlab thank you Mark i did not read this one.

  • @cagatay no problems. Easily missed!!

  • @DownPW said in Threading support for NodeBB:

    I think I understand by reading the code that it is necessary to specify the classes chnaged in the function.js (with add .threaded) but I don’t really see how to add more

    Can you post the current function code you have?

  • sure :

    function threaded() {
        $(document).ready(function () {
            // Check if the screen width is 1200px or more
            if ($(window).width() >= 1200) {
                // Check if the dropdown already exists
                if ($('#enableThreading').length === 0) {
                    var threadView = $('<div class="threads-wrapper"><i class="fa fa-fw fa-bars left"></i><form class="form"><div class="form-check form-switch sticky-tools-bar"> \
                        <input class="form-check-input" id="enableThreading" type="checkbox" data-field="enableThreading"> \
                        <label class=" d-none d-md-inline fw-semibold" for="enableThreading"><i class="fa fa-fw fa-bars-staggered right"></i></label> \
                    </div></form></div>');
                    $('.topic .sticky-tools ul [component="topic/browsing-users"]:last-of-type').append(threadView);
                    // Check if there's a stored state for the checkbox and update it
                    var storedState = localStorage.getItem('enableThreadingState');
                    if (storedState === 'true') {
                        $('#enableThreading').prop('checked', true);
                    }
                }
                // Toggle the class 'threaded' on or off when the checkbox changes state
                $('#enableThreading').on('change', function () {
                    var isChecked = $(this).is(':checked');
                    if (isChecked) {
                        console.log('Thread view is active.');
                        $('ul[component="topic"]').addClass('threaded');
                        $('.posts-container').addClass('threaded')
                        $('ul[component="topic"]').addClass('threaded')
                        $('.post-container').addClass('threaded')
                        $('.timeline-event').addClass('threaded')
                        $('[component="post/footer"]').addClass('threaded');
                        $('[component="post"]').each(function () {
                            // Add the 'threaded' class to matching elements
                            if ($(this).hasClass('pt-4') || $(this).hasClass('self-post')) {
                                $(this).addClass('threaded');
                                $('.topic .sticky-tools').addClass('threaded');
                            }
                        });
                    } else {
                        console.log('Thread view is inactive.');
                        $('[component="post"]').removeClass('threaded');
                        $('ul[component="topic"]').removeClass('threaded');
                        $('.posts-container').removeClass('threaded')
                        $('ul[component="topic"]').removeClass('threaded')
                        $('.post-container').removeClass('threaded')
                        $('.timeline-event').removeClass('threaded')
                        $('[component="post/footer"]').removeClass('threaded');
                        $('.topic .sticky-tools').removeClass('threaded');
                    }
                    // Store the checkbox state in localStorage
                    localStorage.setItem('enableThreadingState', isChecked);
                });
                // Check for changes in the checkbox state when the page loads
                $('#enableThreading').trigger('change');
            }
        });
    }
    
    function threadedChat() {
        $(document).ready(function () {
            // Check if the screen width is 1200px or more
            if ($(window).width() >= 1200) {
                // Check if the dropdown already exists
                if ($('#enableThreadingChat').length === 0) {
                    var chatView = $('<div class="threads-wrapper"><i class="fa fa-fw fa-bars left"></i><form class="form"><div class="form-check form-switch sticky-tools-bar"> \
                        <input class="form-check-input" id="enableThreadingChat" type="checkbox" data-field="enableThreading"> \
                        <label class=" d-none d-md-inline fw-semibold" for="enableThreadingChat"><span class="title-tooltip top" tooltip-text="Éditer Profil"><i class="fa fa-fw fa-bars-staggered right"></i></label> \
                    </div></form></div>');
                    $('[component="chat/header"]').prepend(chatView);
    
                    // Check if there's a stored state for the checkbox and update it
                    var storedState = localStorage.getItem('enableThreadingStateChat');
                    if (storedState === 'true') {
                        $('#enableThreadingChat').prop('checked', true);
                    }
                }
    
                // Toggle the class 'threaded' on or off when the checkbox changes state
                $('#enableThreadingChat').on('change', function () {
                    var isChecked = $(this).is(':checked');
                    if (isChecked) {
                        console.log('Thread view is active.');
                        $('[component="chat/message"]').each(function () {
                            // Add the 'threaded' class to matching elements
                            if ($(this).hasClass('chat-message')) {
                                $(this).addClass('threaded');
                            }
                        });
                    } else {
                        console.log('Thread view is inactive.');
                        $('[component="chat/message"]').removeClass('threaded');
                    }
    
                    // Store the checkbox state in localStorage
                    localStorage.setItem('enableThreadingStateChat', isChecked);
                });
    
                // Check for changes in the checkbox state when the page loads
                $('#enableThreadingChat').trigger('change');
            }
        });
    }
    
    
    $(window).on('action:chat.loaded', function(data) {
            threadedChat();
    });
    $(window).on('action:chat.received', function(data) {
            threadedChat();
    });
    $(window).on('action:ajaxify.end', function (data) {
        threaded();
    });
    
    $(window).on('action:posts.edited', function (data) {
        threaded();
    });
    
    $(window).on('action:posts.loaded', function (data) {
        threaded();
    });
    
  • @DownPW Thanks. You should remove the threadedChat function and these lines

    $(window).on('action:chat.loaded', function(data) {
            threadedChat();
    });
    $(window).on('action:chat.received', function(data) {
            threadedChat();
    });
    

    That code is not functional yet and is very experimental 🙂

    I’ll have a look at your DEV environment to make the code recommendations.

  • @DownPW I changed your CSS as it was lacking the actual .threaded class which is the target we add and remove

    .page-topic .topic .posts.timeline [component="topic/event"].timeline-event, .page-topic .topic .posts.timeline [component="topic/necro-post"].timeline-event.threaded {
        background: transparent !important;
        margin-bottom: 10px !important;
    }
    .page-topic .topic .posts.timeline .threaded:last-child .timeline-event:last-child,
    .page-topic .topic .posts.timeline .threaded:last-child>[component="post/placeholder"]:last-child,
    .page-topic .topic .posts.timeline .threaded:last-child>[component=post]:last-child {
        margin-left: 0.5rem !important;
    }
    

    Seems to work, but can you confirm?


Related Topics
  • 5 Votes
    3 Posts
    1k Views

    Very good like always 😉

  • Material View Support for Stock NodeBB

    Unsolved Let's Build It
    51
    15 Votes
    51 Posts
    3k Views

    Oh yes, that’s what’s super cool, I learn something every day. Afterwards I start from so low in JS

  • Threaded chat support for NodeBB

    Let's Build It
    35
    19 Votes
    35 Posts
    2k Views

    @DownPW said in Threaded chat support for NodeBB:

    Better like this : add shadow and border-left on self answer

    Of course - you style to your own requirements and taste 🙂 I’ll commit that CSS we discussed yesterday also

  • www. Infront stops website access?

    Solved Configure
    10
    1 Votes
    10 Posts
    476 Views

    @Panda because there is no match for the DNS entry specified. The receiving web server parses the headers looking for a destination hostname to match, and anything the web server is unable to resolve will be sent back to the root.

  • Nodebb design

    Solved General
    2
    1 Votes
    2 Posts
    295 Views

    @Panda said in Nodebb design:

    One negative is not being so good for SEO as more Server side rendered forums, if web crawlers dont run the JS to read the forum.

    From recollection, Google and Bing have the capability to read and process JS, although it’s not in the same manner as a physical person will consume content on a page. It will be seen as plain text, but will be indexed. However, it’s important to note that Yandex and Baidu will not render JS, although seeing as Google has a 90% share of the content available on the web in terms of indexing, this isn’t something you’ll likely lose sleep over.

    @Panda said in Nodebb design:

    The “write api” is preferred for server-to-server interactions.

    This is mostly based around overall security - you won’t typically want a client machine changing database elements or altering data. This is why you have “client-side” which could be DOM manipulation etc, and “server-side” which performs more complex operations as it can communicate directly with the database whereas the client cannot (and if it can, then you have a serious security flaw). Reading from the API is perfectly acceptable on the client-side, but not being able to write.

    A paradigm here would be something like SNMP. This protocol exists as a UDP (UDP is very efficient, as it is “fire and forget” and does not wait for a response like TCP does) based service which reads performance data from a remote source, thus enabling an application to parse that data for use in a monitoring application. In all cases, SNMP access should be “RO” (Read Only) and not RW (Read Write). It is completely feasible to assume complete control over a firewall for example by having RW access to SNMP and then exposing it to the entire internet with a weak passphrase.

    You wouldn’t do it (at least, I hope you wouldn’t) and the same ethic applies to server-side rendering and the execution of commands.

  • Nodebb 3.2.0

    Bugs
    20
    2 Votes
    20 Posts
    913 Views

    @crazycells yes, I’m aware of that. Need to fix

    EDIT- fixed. Caused by the same CSS that is used to absolutely position the “verified” group badge in the posts view. Amended this CSS so that is specifically targets the post stream as below

    li[component="post"] a[href*="/groups/verified"] { position: absolute !important; left: 8px; z-index: 2; margin-top: 1px; border-radius: 999px !important; line-height: 14px; display: block; height: 22px; margin-left: 0px !important; }
  • Setup OGProxy for use in NodeBB

    Moved Let's Build It
    110
    21 Votes
    110 Posts
    11k Views

    @crazycells said in Setup OGProxy for use in NodeBB:

    are they cached for each user separately?

    No. It’s a shared cache

    @crazycells said in Setup OGProxy for use in NodeBB:

    additionally, this is also handling youtube videos etc, right?

    No. This is handled by nodebb-plugin-ns-embed

  • 2 Votes
    2 Posts
    182 Views

    @dave1904 that’s a really good point actually. I know it was there previously on Persona, but you’re right - no such function exists on harmony.

    However, putting something in place to mimick the behaviour of Persona won’t be hard from the js standpoint, although I wonder if perhaps we should ask the NodeBB developers is this feature was overlooked?