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
  • 3 Votes
    2 Posts
    117 Views

    Very great 😉

  • NodeBB Twitter / X embeds

    Let's Build It
    31
    19 Votes
    31 Posts
    901 Views

    @OT I honestly am not able to replicate this. Can you PM me a link to a post on your forum with the specific issue so I can have a look?

  • Bug Report

    Solved Bugs
    47
    26 Votes
    47 Posts
    2k Views

    @crazycells Good points, thanks. I completely forgot that classes are added - makes life much simpler!

    EDIT - seems this is pretty straightforward, and only needs the below CSS

    .upvoted i { color: var(--bs-user-level) !important; }

    This then yields

    3f072f8a-ebfa-4910-8723-73c493b8e4eb-image.png

    However, the caveat here is that the .upvoted class will only show for your upvotes, and nobody else’s. However, this does satisfy the original request

    however I would love to see my upvoted posts more clearly, because currently, when I upvote, nothing on the post tool is changing, it would be nicer if there is an indication that I have upvoted (like a filled or colored triangle?)

  • Interesting Widget code, but can't fetch API

    Solved Customisation
    26
    2 Votes
    26 Posts
    2k Views

    @Panda said in Interesting Widget code, but can’t fetch API:

    How did you drop that widget into the post there?
    I hadnt seen this BSgenerator anywhere on sudonix site, do you use it somewhere already?

    Yes, here

    https://sudonix.org/topic/414/corporate-bullshit-generator?_=1687774393044

    It’s not a “post” or “topic” in the common sense. It is actually a page in it’s own right and leverages nodebb-plugin-custom-pages. This in turn creates a new “route” which behaves like a page, meaning it is then exposed for widgets.

    @Panda said in Interesting Widget code, but can’t fetch API:

    Also can you explain more what you mean by calling the code externally. In my API call example, how would I go about doing that?

    By this, I mean create all the required code in an external JS file that is reachable by the NodeBB instance - so, in “public” for example - or in my case /public/js. The widget then “calls” that file and because it runs outside of the scope of NodeBB, you just need to return the values to the widget.

    Hope this makes sense?

  • NodeBB v3 Chat Very Slow

    Moved Performance
    47
    11 Votes
    47 Posts
    4k Views

    @DownPW Seems fine.

  • NodeBB: Favicon upload issue

    Solved Configure
    12
    3 Votes
    12 Posts
    541 Views

    @phenomlab I am on a Mac, so I used the “Option + Command + I”, and then performed the steps. It loaded my favicon! I checked on Firefox which I haven’t used before, and it showed my favicon also! That’s fantastic and thank you for the help!

  • 11 Votes
    14 Posts
    874 Views

    @dave1904 excellent news. Thanks for the feedback

  • How to fix size of photos & videos NodeBB

    Solved Customisation
    7
    3 Votes
    7 Posts
    669 Views

    @crazycells pleasure. Using percentages makes much more sense in this case. It’s the same argument with px vs pt vs em with fonts, margins, padding, etc., in the sense that em is generally preferred over px and pt

    https://stackoverflow.com/questions/609517/why-em-instead-of-px