Skip to content

What is this bar called?

Solved Customisation
  • @DownPW it can easily be reverted, but I don’t want to maintain two sets of code. I’ll defer to others here for that final decision as I know it did cause some confusion.

  • no problem dude @phenomlab 🙂
    I put a modification here that seems to work as a reminder if you don’t mind.

    –> If yes, you can delete it.

    use $('html, body').animate({ scrollTop: 0 }, '300'); to smoothly scroll the page to the top when the #pageUp button is clicked. This code will provide a smooth scrolling effect from the bottom to the top of the page without reloading it.

    What do you think of this?

    // Scroll to top function
    $(window).on('action:ajaxify.end', function(data) {
        var matched = false;
        $(document).ready(function() {
            var pageUp = $('#pageUp');
            var bar = $('.reading-meter');
            var perWidth = $('.reading-meter').width();
            
            // Main progressbar function
            function pageScroller() {
                var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
                var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
                var scrolled = (winScroll / height) * 100;
    
                document.getElementById("progress-bar").style.width = parseFloat(scrolled).toFixed(0) + "%";
                $('#percentage').val(parseFloat(scrolled).toFixed(0) + "%");
    
                // Prevent the mouse scroll wheel from scrolling down after the pageUp button is clicked
                if ($('#pageUp').is(':focus')) {
                    event.preventDefault();
                }
            }
    
            // Bind the pageScroller function to the window's scroll event
            $(window).scroll(function() {
                pageScroller();
            });
    
            // Check the URL and composer visibility separately from the scroll event
            function checkURL() {
                var thisURL = window.location.href;
                var checkArray = ["topic", "notifications", "user"];
                var isFound = false;
                
                for (var i = 0, len = checkArray.length; i < len; i++) {
                    if (thisURL.indexOf(checkArray[i]) > -1) {
                        isFound = true;
                        break;
                    }
                }
                
                return isFound;
            }
    
            // Function to update visibility based on URL and composer
            function updateVisibility() {
                if (checkURL()) {
                    bar.removeClass('show');
                    pageUp.removeClass('show');
                } else {
                    // Exception here is that we don't want the scroll bar to show when the composer is active
                    if ($(window).scrollTop() > 0 && (!$('[component="composer"]').is(":visible"))) {
                        bar.addClass('show');
                        pageUp.addClass('show');
                    } else {
                        bar.removeClass('show');
                        pageUp.removeClass('show');
                    }
                }
            }
    
            // Call updateVisibility initially
            updateVisibility();
    
            // Bind updateVisibility function to the window's scroll event
            $(window).scroll(function() {
                updateVisibility();
            });
    
            // Scroll to top when #pageUp is clicked
            $(document).on("click", "#pageUp", function(e) {
                $('html, body').animate({ scrollTop: 0 }, '300'); // Animate scrolling to top
                $('#progress-bar').width(0);
                pageUp.removeClass('show');
            });
        });
    });
    
  • @DownPW looks good to me.

  • @DownPW Just to circle back to this, the decision to reload the page instead of multiple scrolling / clicking was based on this discussion, which I’m including here for brevity

    https://community.nodebb.org/topic/17395/scroll-top-function?_=1695115491466

  • @phenomlab said in What is this bar called?:

    @DownPW you are right - it used to scroll to the top but I changed it because “scroll top” actually only applied to what was in the DOM at the time meaning that as data was being added, the “top” position was no longer a true representation and so the button had to be clicked multiple times to reach the “real” top.

    you are right @phenomlab the code I gave yesterday works but does the same thing as you described.

    here a mix of the 2 (scroll to top & scroll to top with refresh)

    // Scroll to top function (classic scroll to top)
    $(window).on('action:ajaxify.end', function(data) {
        var matched = false;
        $(document).ready(function() {
            var pageUp = $('#pageUp');
            var bar = $('.reading-meter');
            var perWidth = $('.reading-meter').width();
            
            // Main progressbar function
            function pageScroller() {
                var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
                var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
                var scrolled = (winScroll / height) * 100;
    
                document.getElementById("progress-bar").style.width = parseFloat(scrolled).toFixed(0) + "%";
                $('#percentage').val(parseFloat(scrolled).toFixed(0) + "%");
    
                // Prevent the mouse scroll wheel from scrolling down after the pageUp button is clicked
                if ($('#pageUp').is(':focus')) {
                    event.preventDefault();
                }
            }
    
            // Bind the pageScroller function to the window's scroll event
            $(window).scroll(function() {
                pageScroller();
            });
    
            // Check the URL and composer visibility separately from the scroll event
            function checkURL() {
                var thisURL = window.location.href;
                var checkArray = ["topic", "notifications", "user"];
                var isFound = false;
                
                for (var i = 0, len = checkArray.length; i < len; i++) {
                    if (thisURL.indexOf(checkArray[i]) > -1) {
                        isFound = true;
                        break;
                    }
                }
                
                return isFound;
            }
    
            // Function to update visibility based on URL and composer
            function updateVisibility() {
                if (checkURL()) {
                    bar.removeClass('show');
                    pageUp.removeClass('show');
                } else {
                    // Exception here is that we don't want the scroll bar to show when the composer is active
                    if ($(window).scrollTop() > 0 && (!$('[component="composer"]').is(":visible"))) {
                        bar.addClass('show');
                        pageUp.addClass('show');
                    } else {
                        bar.removeClass('show');
                        pageUp.removeClass('show');
                    }
                }
            }
    
            // Call updateVisibility initially
            updateVisibility();
    
            // Bind updateVisibility function to the window's scroll event
            $(window).scroll(function() {
                updateVisibility();
            });
    
            // Scroll to top when #pageUp is clicked
            $(document).on("click", "#pageUp", function(e) {
                $('html, body').animate({ scrollTop: 0 }, '300'); // Animate scrolling to top
                $('#progress-bar').width(0);
                pageUp.removeClass('show');
            });
        });
    });
    
    // Scroll to refresh function (for specific URLs)
    $(window).on('action:ajaxify.end', function(data) {
        var refreshRoutes = ['/recent', '/unread', '/popular', '/top', '/solved', '/unsolved'];
        var currentRoute = ajaxify.data.url;
    
        if (refreshRoutes.includes(currentRoute)) {
            var pageUp = $('#pageUp');
            var bar = $('.reading-meter');
            var perWidth = $('.reading-meter').width();
    
            // Main progressbar function
            function pageScroller() {
                var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
                var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
                var scrolled = (winScroll / height) * 100;
    
                document.getElementById("progress-bar").style.width = parseFloat(scrolled).toFixed(0) + "%";
                $('#percentage').val(parseFloat(scrolled).toFixed(0) + "%");
    
                // Prevent the mouse scroll wheel from scrolling down after the pageUp button is clicked
                if ($('#pageUp').is(':focus')) {
                    event.preventDefault();
                }
            }
    
            // Bind the pageScroller function to the window's scroll event
            $(window).scroll(function() {
                pageScroller();
            });
    
            // Function to update visibility based on URL and composer
            function updateVisibility() {
                // No need to check composer visibility for these routes
                if ($(window).scrollTop() > 0) {
                    bar.addClass('show');
                    pageUp.addClass('show');
                } else {
                    bar.removeClass('show');
                    pageUp.removeClass('show');
                }
            }
    
            // Call updateVisibility initially
            updateVisibility();
    
            // Bind updateVisibility function to the window's scroll event
            $(window).scroll(function() {
                updateVisibility();
            });
    
            // Scroll to refresh when #pageUp is clicked
            $(document).on("click", "#pageUp", function(e) {
                ajaxify.refresh();
                $('#progress-bar').width(0);
                pageUp.removeClass('show');
            });
        }
    });
    

    I found it interesting to keep the scroll effect on the home page

    The scroll to top with refresh is applied on the routes indicated in the script (/recent, /unread, etc.). The classic scroll to top applies to other pages and the scroll to top is disabled in chat, etc…

    For the previous script, I used the code from your v2 and doing myself but I’m not being a good JS developer, so this time I asked to ChatGPT to help me, sorry !

    I tested the code and it seems to work correctly without any bugs but could you check @phenomlab if this seems correct to you even if the code works?

    A machine will not replace humans in this regard. At least for now 🙂

  • @DownPW 🙂 Love it - let me try this out!

    EDIT - Tried it, and there’s a couple of bugs. For example, if you use a custom page, scroll to the bottom, then use the back to top button, you have to scroll the mouse wheel down 16 times (if you do it quickly - depending on intervals it can be much less) before it’ll work properly. This is animation jitter as far as I can see where the animation does not complete on time and is therefore stuck in a loop.

    Have a look yourself here and see if you get the same experience

    https://sudonix.org/journey

  • Seems you can fix this by using e.preventDefault() see below

        // Scroll to top when #pageUp is clicked
        $(document).on("click", "#pageUp", function(e) {
            e.preventDefault(); // Prevent default behavior
            $('html, body').animate({ scrollTop: 0 }, '300'); // Animate scrolling to top
            $('#progress-bar').width(0);
            pageUp.removeClass('show');
        });
    
  • Not test on custom page. Test ASAP

  • @DownPW said in What is this bar called?:

    Not test on custom page. Test ASAP

    The above code change I provided seems to resolve the issue.

  • This is good 👍


Did this solution help you?
Did you find the suggested solution useful? Why not buy me a coffee? It's a nice gesture, and a great way to show your appreciation 💗

  • Bug Report

    Solved Bugs
    43
    21 Votes
    43 Posts
    882 Views

    @crazycells yep. I get it! Good point.

  • 1 Votes
    10 Posts
    297 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
    147 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.

  • 2 Votes
    26 Posts
    1k 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?

  • Footer bar add center text

    Solved Customisation
    41
    8 Votes
    41 Posts
    3k Views

    @phenomlab said in Footer bar add center text:

    div#console-nav-tab

    Ah ok test with bottom: 0px !important; idem

  • 1 Votes
    2 Posts
    611 Views

    @eveh Welcome board 🙂

    The code you are referring to is custom written as no such functionality exists under NodeBB. However, adding the functionality is relatively trivial. Below are the required steps

    Navigate to /admin/appearance/customise#custom-header Add the below code to your header, and save once completed <ol id="mainbanner" class="breadcrumb"><li id="addtext">Your Title Goes Here</li></ol> Navigate to /admin/appearance/customise#custom-js and add the below code, then save $(document).ready(function() { $(window).on('action:ajaxify.end', function(data) { // Initialise mainbanner ID, but hide it from view $('#mainbanner').hide(); var pathname = window.location.pathname; if (pathname === "/") { $("#addtext").text("Your Title"); $('#mainbanner').show(); } else {} // If we want to add a title to a sub page, uncomment the below and adjust accordingly //if (pathname === "/yourpath") { //$("#addtext").text("Your Title"); //$('#mainbanner').show(); //} }); }); Navigate to /admin/appearance/customise#custom-css and add the below CSS block .breadcrumb { right: 0; margin-right: auto; text-align: center; background: #0086c4; color: #ffffff; width: 100vw; position: relative; margin-left: -50vw; left: 50%; top: 50px; position: fixed; z-index: 1020; }

    Note, that you will need to adjust your CSS code to suit your own site / requirements.

  • Reading Meter Progress bar

    Locked Solved Customisation
    15
    9 Votes
    15 Posts
    822 Views

    For anyone else following this thread, please see
    https://sudonix.com/topic/467/issues-with-progress-bar-on-v3

  • Display tweets in widget [NodeBB]

    Solved Customisation
    29
    4 Votes
    29 Posts
    2k Views

    @phenomlab brilliant, many thanks Mark 😁