Skip to content

[NodeBB] Welcome Message with an automatic footer logo change cycle

Unsolved Customisation
  • Hi @phenomlab

    As discussed in PM, I put the request here that will serve everyone.

    At my demand, we already have the Welcome Message script with a change of footer logo that works very well for each time period (here for reference) :

    https://sudonix.com/topic/233/nodebb-welcome-message-with-logo-footer-change/

    I submit another idea which is the following (resume of PM with you Mark):

    –> The same script as actually with the addition
    of a cycle of different/several logo with automaticaly change every XX seconds/minutes for each period without refresh the page.

    • In the end, we would have as many cycles as there are periods of time.

    • 1 cycle = 1 time period (0h-6h, 6h-8h etc.) with different logos each time that would change every X minutes/seconds automatically.

    • an animation, like fade, scroll, etc for the images, or should they just be replaced. Like you want Mark 😉

    • Increase CPU usage on the client, so we have to add pauses periodically to prevent the visiting user browser taking too much RAM and CPU.

  • @DownPW As JavaScript (unless it’s server side) has no access to the file system, we can’t use a native NodeJS function like the below to list the files

    const testFolder = '/home/nodebb/nodebb/public/customlogo/afternoon';
    const fs = require('fs');
    
    fs.readdir(testFolder, (err, files) => {
      files.forEach(file => {
        console.log(file);
      });
    });
    

    It’s pretty simple to do this with PHP, and then pass back the variables to JS for client side processing. However, if you don’t have PHP installed, then of course this won’t work. However, it is possible to form an array in jQuery and use that with a timer to change the image. This is actual working code designed in your test environment

    NB - this is a proof of concept, and is not the completed script. The idea is to test the functionality, and then if it works as desired, we increase the scope, and implement across the original code we already have

    // ------------------------------------------
    // Rotate footer images at 60 second interval
    // ------------------------------------------
        // Provide a list of the files we need, less the .png extension as we add this automatically
        var files = ['01', '02', '03'];
        // Set the path where the images are stored
        var thepath = "/assets/customlogo/cycle/evening/";
        // Timer starting point
        var offset = 0;
        // Loop through each array item (files), and after 60 seconds, replace the current image with the next index in the array.
        // We fade out the image first, then fade in the new one (0.4 seconds)
        $(files).each(function(logo, index) {
            setTimeout(function() {
                $("#thislogo").fadeOut('slow', function() {
                    $('#thislogo').on('load', function() {
                        $('#thislogo').fadeIn(400);
                    }).attr("src", thepath + index + '.png');
                });
                // Place a log in the console so we can see that the script is active
                console.log("Switching footer image to " + thepath + index + ".png");
            }, 60000 + offset);
            // Add another 60 seconds and restart the loop on the next array index
            offset += 60000;
            // Once the file array is exhausted, exit
        });
    
    
    

    This initially loads the selected image according to the previous code I provided, then waits 60 seconds, and changes to the next in the cycle, so 01, 02, 03 etc until it reaches the end where it will exit.

    Important

    • The script will start again and add the default image selected for that time period if the page is reloaded, or the home logo / text is clicked, as this is the equivalent of reloading the site.
    • The script does not care what you are doing at the time of change, as it uses it’s own timer outside of any callback functions in NodeBB - it will execute regardless
    • The exit is graceful, and designed not to chew the CPU or memory of the visiting host. The recommendation would be to take the time period, divide it by the number of images you have, and then alter the 60 second value (denoted as 60000) to the value you land up with.
    • The interval is recorded in milliseconds (see below for calculation)

    So, based on this from the previous script

    	if (thehours >= 0 && thehours < 6) {
    		themessage = night; 
    		theicon = "fa-solid fa-moon";
    		thelogo = "/assets/customlogo/night/pw_night.png";
    }
    

    Note that an additional } has been added here for cosmetic purposes, and does not appear in the original script

    6 hours (or 360,000ms = 60 minutes x 6 = 360) with 4 images would equate to 60000 x 60 = 3600000 / 4 meaning your interval period would be 900000 milliseconds or 15 minutes.

    My advice would be to play with this first to get yourself familiar with the concept, and then we can factor into the previously provided code to make the one function 🙂

  • – yeah Mark @phenomlab , I understand the method of calcul for CPU/mem Host.

    – One question, why millisecond and not seconds for example?

    – For this:

    var files = ['01', '02', '03'];
    

    –> I noticed that I have obliged to mark all the files to the script.
    If I have 10 images, I am obliged to indicate them:

    var files = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10',];
    

    –> Possible to change that or not ? Not a big deal if it’s not possible

    – I also noticed that once arrived on the last image, there is no loop that redirects to the first image.

    –> It would be really cool to add a loop.

  • EDIT:

    if I understand correctly the code: no loop, just calcul off how many times logo appears for each period time. With this = no loop

    But it will be very cool if we have a loop if we want to make them cycle a little faster

  • @DownPW

    why millisecond and not seconds for example?

    It’s always been that way - not sure why, but it has 🙂

    If I have 10 images, I am obliged to indicate them:

    Yes, because of this point I made in the very first post

    As JavaScript (unless it’s server side) has no access to the file system

    For security reasons, access will always be denied. Imagine a situation where client side JS did in fact have access to the server’s file system - you could easily bring down a server by simply planting a malicious payload.

    I also noticed that once arrived on the last image, there is no loop that redirects to the first image.

    This is intentional. The reason for this is that when the standard setInterval function fires (example below)

    setInterval(function () {
            console.log('seems to work');
        },30000);
    

    It will require the issuance of clearInterval in order to stop it - by default, setInterval will run in a loop and will run forever, and if you reload the page, you then have two processes running because the first was never stopped. Once each time period has passed, you’d also need to fire clearInterval to stop it. Another issue here is that this may not stop other rogue processes launched by browser reloads etc - essentially, you land up with a mess, and unreliable rotation of images.

    It’s for this reason that I provided the below formulae as an example to ensure you get a graceful shutdown of the running process

    6 hours (or 360,000ms = 60 minutes x 6 = 360) with 4 images would equate to 60000 x 60 = 3600000 / 4 meaning your interval period would be 900000 milliseconds or 15 minutes.

    It would be really cool to add a loop.

    If you still want to do this, you can, but I wouldn’t honestly recommend it for the reasons I’ve provided above.

  • @phenomlab said in [NodeBB] Welcome Message with an automatic footer logo change cycle:

    @DownPW

    why millisecond and not seconds for example?

    It’s always been that way - not sure why, but it has 🙂

    Ok I understand. In JS, it’s like that. Ok 😉

    If I have 10 images, I am obliged to indicate them:

    Yes, because of this point I made in the very first post

    As JavaScript (unless it’s server side) has no access to the file system

    It’s Logical

    For security reasons, access will always be denied. Imagine a situation where client side JS did in fact have access to the server’s file system - you could easily bring down a server by simply planting a malicious payload.

    I also noticed that once arrived on the last image, there is no loop that redirects to the first image.

    This is intentional. The reason for this is that when the standard setInterval function fires (example below)

    setInterval(function () {
            console.log('seems to work');
        },30000);
    

    It will require the issuance of clearInterval in order to stop it - by default, setInterval will run in a loop and will run forever, and if you reload the page, you then have two processes running because the first was never stopped. Once each time period has passed, you’d also need to fire clearInterval to stop it. Another issue here is that this may not stop other rogue processes launched by browser reloads etc - essentially, you land up with a mess, and unreliable rotation of images.

    It’s for this reason that I provided the below formulae as an example to ensure you get a graceful shutdown of the running process

    6 hours (or 360,000ms = 60 minutes x 6 = 360) with 4 images would equate to 60000 x 60 = 3600000 / 4 meaning your interval period would be 900000 milliseconds or 15 minutes.

    It’s better for perf and kill all process and avoid too much process on the broswer client side on any reload on any host.

    I thought I understood the calculation but I don’t feel like it in the end.
    If I understand correctly, your result is for 1 hour? Each image appears every 15min in 1 hours. so each image appears 6 times ?

    can you better explain this calculation please ?

    It would be really cool to add a loop.

    If you still want to do this, you can, but I wouldn’t honestly recommend it for the reasons I’ve provided above.

    I trust you 100%.
    If you say that it’s not advised side perf = No problem

  • @phenomalb

    Example 1

    period of Time (evening) = 4h
    we have 4 images

    1h= 3 600 000 Mlliseconds
    3 600 000 / 4 images = 900 000 Milliseconds = 15 min

    each images appears every 15 minutes for 1 hours
    each images appears 4 times for 4 hours

    / Place a log in the console so we can see that the script is active
                console.log("Switching footer image to " + thepath + index + ".png");
            }, 900000 + offset);
            // Add another 60 seconds and restart the loop on the next array index
            offset += 900000;
            // Once the file array is exhausted, exit
        });
    

    Example 2

    period of Time (afternoon) = 6h
    we have 13 images

    1h= 3 600 000 Mlliseconds
    3 600 000 / 13 images = 276923,07 Milliseconds = 4.615383 min

    each images appears every 4.615383 minutes
    each images appears 6 times for 6 hours

    / Place a log in the console so we can see that the script is active
                console.log("Switching footer image to " + thepath + index + ".png");
            }, 276923,07 + offset);
            // Add another 60 seconds and restart the loop on the next array index
            offset += 276923,07;
            // Once the file array is exhausted, exit
        });
    
  • @DownPW Yes, this is pretty much it. Whilst I appreciate that this isn’t fully what you wanted, with the script I already provided, this is the only way. It doesn’t need to be one hour either. If you had a 6 hour window, then

    36000000 x 6 = 216000000 which is the full 6 hours, then divided by the amount of images, so if you had 13 images, you’d land up with

    216000000 / 13 = 16615384.615384615 which isn’t exactly easy on the math, but would have to be this way to fit into the time period being defined. If you wanted them to cycle fully every hour, then the calculation you provided is correct.

    We could try this with a loop and attempt to kill at each time period change, but in my view, this would prove problematic for the reasons I already stated - unless we issue a kill .onload which in turn would [sic] kill all running processes on page load and restart them dependent on the time period of the day.

    Overall, this is quite complex and could land up locking your site or the user’s browser if not coded correctly. In all honesty, for the cosmetic goal or benefit, I really don’t think it’s palatable from experience perspective.

  • @phenomlab

    ok so what would be next step?
    We just have to change the cycles automatically according to each period ?

    or add the script as many times as there are periods by changing the variable?

    var thepath = “/assets/customlogo/cycle/afternoon/”;

    I think it is possible to achieve the goal, I have already seen this kind of thing on a site without any perf problems.

  • @DownPW

    We just have to change the cycles automatically according to each period ?

    Yes, this is by far the safest

    I think it is possible to achieve the goal, I have already seen this kind of thing on a site without any perf problems.

    It’s certainly possible, but not without issues or impact to performance (in my view)


  • 7 Votes
    7 Posts
    428 Views

    @phenomlab thank you very much 🙂

  • 5 Votes
    9 Posts
    2k Views

    @phenomlab

    Very very great Mark 😉
    Thanks again, It’s perfect now !

    –> I share my code that I modified.

    I’ve added French and English comments.
    If you see things to change Mark, don’t hesitate.

    As usual, all the access paths (FA icons, logo) will have to be modified according to your architecture.

    You can also very well add/remove time slots and change welcome messages to suit your needs.

    Widgets ACP/HTML Widget Footer Logo <center> <br><br> <img id="thislogo" src="path/to/my/image"> </center> Widget Welcome Message <!-- IF loggedIn --> <div class="getUsername">, <a href="/me"><span class="username"></span></a></div> <!-- ENDIF loggedIn --> CSS

    – I added the size font-weight: 900; in the CSS because otherwise some FA icon wasn’t displayed correctly and reduce margin :

    i#thisicon { font-family: "Font Awesome 5 Free"; font-style: normal; margin-right: 8px; font-weight: 900; } .getUsername { padding-top: 20px; text-align: right; } /*Smartphone*/ /*On désactive le message de bienvenue"*/ /*We disable the welcome message"*/ @media all and (max-width: 1024px) { .getUsername { display: none; } } JAVASCRIPT // ------------------------------------------ // Welcome Message avec icône et Footer logo // Welcome Message with icon and Footer logo // ------------------------------------------ $(window).on('action:ajaxify.end', function (data) { //On récupère le username dans le DOM et on l'affiche //We retrieve the username from the DOM and display it function updateUsername() { $('.getUsername .username').text(app.user.username); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', updateUsername); } else { updateUsername(); } //On déclare les variables principales (themessage & thehours) ainsi que les variables secondaires correspondants aux plages horaires //We declare the main variables (themessage & thehours) as well as the secondary variables corresponding to the time slots var thehours = new Date().getHours(); var themessage; var wakeup = ('Good day'); var morning = ('Good morning'); var lunch = ('Bon appétit'); var afternoon = ('Good afternoon'); var drink = ('Cheers'); var evening = ('Good evening'); var night = ('Good night'); var welcome = ('Welcome'); var matched = false; //On peux ici tester le résultat du code en spécifiant une heure (!!!IMPORTANT: Commenter une fois le script testé!!!) //Here we can test the result of the code by specifying a time (!!!IMPORTANT: Comment once the script has been tested!!!) //thehours = 20 //On déclare les plages horaires avec les icones FA et les logos //We declare the time slots with FA icons and logos path if (thehours >= 0 && thehours < 6) { themessage = night; theicon = "fa-solid fa-moon"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 6 && thehours < 8) { themessage = wakeup; theicon = "fa-solid fa-mug-hot"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 8 && thehours < 12) { themessage = morning; theicon = "fa-solid fa-sun"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 12 && thehours < 13) { themessage = lunch; theicon = "fas fa-hamburger"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 13 && thehours < 16) { themessage = afternoon; theicon = "fa-solid fa-sun"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 16 && thehours < 18) { themessage = welcome; theicon = "fa-solid fa-rocket"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 18 && thehours < 19) { themessage = drink; theicon = "fa-solid fa-wine-glass"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 19 && thehours < 20) { themessage = lunch; theicon = "fas fa-pizza-slice"; thelogo = "/assets/customlogo/XXX.png"; } else if (thehours >= 20 && thehours < 24) { themessage = evening; theicon = "fa-solid fa-tv"; thelogo = "/assets/customlogo/XXX.png"; } // Si la page active est un topic, on désactive/cache le message de bienvenue // If the active page is a topic, we deactivate/hide the welcome message if (window.location.href.indexOf("topic") > -1) { console.log("This is a topic, so hide the user welcome message"); $('#thisuser').hide(); } // Sinon, on affiche le message en fonction, l'icone FA et son emplacement (prepend) // Otherwise, we display the message in function, the FA icon and its location (prepend) else { $('.getUsername').prepend("<i id='thisicon' class='" + theicon + "'></i>" + themessage); $("#thislogo").attr("src", thelogo); //$('.getUsername').prepend("<img id='thisicon' src='" + thelogo + "'></>" + themessage); } });
  • 3 Votes
    12 Posts
    986 Views

    @cagatay you’ll need to define this in the body tag (or another element if you want greater or more granular targets) - for example

    body { font-family: "Poppins"; font-size: 16px; }

    Essentially, you use the font-size CSS directive.

  • 0 Votes
    9 Posts
    806 Views

    @downpw I’m inclined to agree with this. There isn’t much else you can do, and provided it works with no odd looking artefacts in other browsers, then ok. The :before and :after are pseudo classes and very well supported across all browsers (except perhaps Internet Exploder, but who uses that these days ?)

  • 4 Votes
    25 Posts
    2k Views

    Topic open
    https://sudonix.com/topic/207/nodebb-help-for-my-custom-css

  • nodebb-plugin-customize error

    Solved Customisation
    25
    2 Votes
    25 Posts
    2k Views

    @phenomlab it work, thanks 🙂

  • NodeBB Design help

    Solved Customisation
    8
    2 Votes
    8 Posts
    834 Views

    @riekmedia I’ve applied some new CSS to your site. Can you reload the page and try again ?

    For the record, this is what I added

    #footer { background: #2d343e; border-top: 4px solid #2d343e; font-size: 0.9em; margin-top: 70px; padding: 80px 0 0; position: relative; clear: both; bottom: 0; left: 0; right: 0; z-index: 1000; margin-left: -15px; margin-right: -338px; }

    The /categories page seems a bit messed up, so looking at that currently

    EDIT - issued some override CSS in the CATEGORIES widget

    <!--- CSS fix for overspill on /categories page - DO NOT DELETE --> <style> #footer { margin-right: -45px; } </style>

    That should resolve the /categories issue.

  • 1 Votes
    6 Posts
    978 Views

    @jac said in [NodeBB] custom Gravatar image not showing:

    @phenomlab said in [NodeBB] custom Gravatar image not showing:

    @jac are you using Custom ?

    Sure am mate 👍🏻

    Confirmed Fixed