:: StoryTitle Timed Progress Bars in SugarCube :: UserScript[script] /* Macro: timedprogressbar Description: Show a dynamically-created "progress bar" that changes colors as its timer runs down. Original design: Akjosch (https://github.com/Akjosch) Arguments: [0]: The time to run in seconds [1]: The length of the progress bar in CSS units (px, em, or %) */ Macro.add("timedprogressbar", { isAsync : true, tags: null, handler: function() { // Filter the payload for newlines and save it for later execution var payload = this.payload[0].contents.replace(/\n$/, '').trim(); // Save or generate a default duration var duration = (Number(this.args[0]) || 60) * 1000; // Save or generate a width var width = this.args[1] || "100%"; // Generate a unique hash var hash = Math.floor(Math.random() * 0x100000000).toString(16); // Create an outer ID var outerId = "outer_" + hash; // Create an inner ID var innerId = "inner_" + hash; // Create an outer div, // add an ID, // add a class, // change the CSS width, and // append to the output var progressbar = $("
") .attr("id", outerId) .addClass("progress-bar") .css('width', width) .appendTo(this.output); // Create an inner div, // add an ID, // add a class, // change the CSS width, and // append to the progressbar var progressvalue = $("
") .attr("id", innerId) .addClass("progress-value") .css('width', "100%") .appendTo(progressbar); // Create a function to convert into hexadecimal var toHex = function(num) { var res = Math.round(Number(num)).toString(16); return (res.length === 1 ? "0" + res : res); }; // Save a reference to possible payload content var functionToRun = this.createShadowWrapper( payload ? function() { Wikifier.wikifyEval(payload); } : null ); // Watch for the :passagedisplay event once jQuery(document).one(":passagedisplay", function() { // Get the current time var timeStarted = (new Date()).getTime(); // Save a reference to the setInterval function var workFunction = setInterval(function() { // Check if the element is still 'connected' if(! progressbar.prop("isConnected") ) { // Navigated away from the passage clearInterval(workFunction); return; } // Figure out how much time has passed var timePassed = (new Date()).getTime() - timeStarted; // Check if the timer has run out if(timePassed >= duration) { // Reduce the inner width to 0 progressvalue.css('width', "0"); // Clear interval clearInterval(workFunction); // Run the inner function (if set) setTimeout(functionToRun, 40); return; } // Update the progress percentage var percentage = 100 - 100 * timePassed / duration; // Save the new color var color = "#" + toHex(Math.min(255, 510 - 5.1 * percentage)) + toHex(Math.min(255, 5.1 * percentage)) + "00"; // Update the background color of the inner div progressvalue.css("backgroundColor", color); // Update the inner div width progressvalue.css("width", (100 - 100 * timePassed / duration) + "%"); }, 40); }); }, }); :: UserStylesheet[stylesheet] .progress-bar { position: relative; border: 1px solid #777; background: black; height: 1em; } .progress-value { position: absolute; top: 0; left: 0; height: 100%; background: #00ff00; } :: Start <> <> <>