MediaWiki:Gadget-fix-schedule-times.js

From WikiConference North America
Revision as of 21:33, 9 October 2021 by Enterprisey (talk | contribs) (docs)
Jump to navigation Jump to search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
// vim: ts=4 sw=4 et ai si
// HOW TO USE: you really should know at least a little javascript for this... (find someone who does if not). Copy this page to your wiki. The title must be the same. Or you can use a different title, but it MUST start with "MediaWiki:" and end in ".js", and you'll have to edit the snippet. Then, on your wiki's MediaWiki:Common.js page (VERY DANGEROUS), determine the page ID of your schedule (click "Page information" under "Tools" in the sidebar), then insert this snippet onto that MediaWiki:Common.js page (don't include the slash and star on their own lines at the beginning and end... actually, you should only be doing this if you have at least minimal JavaScript knowledge...). Make sure to replace BOTH occurrences of REPLACE_ME_WITH_THE_PAGE_ID_OF_YOUR_SCHEDULE_PAGE with that page ID you found. The snippet loads in this gadget and also automatically reloads the page when the schedule changes. (It checks every 2 minutes.) You must also update CONFERENCE_DAYS and WRITTEN_SCHEDULE_OFFSET_SECONDS in this page with the appropriate values for your conference:
/* DELETE THIS LINE WHEN COPYING. This is the start of the stuff that goes in MediaWiki:Common.js
if ( ( mw.config.get( "wgArticleId" ) === REPLACE_ME_WITH_THE_PAGE_ID_OF_YOUR_SCHEDULE_PAGE ) && ( mw.config.get( 'wgAction' ) === 'view' ) ) {
mw.loader.load( '/index.php?title=MediaWiki%3AGadget-fix-schedule-times.js&action=raw&ctype=text/javascript' );
mw.loader.using( ['mediawiki.api'], function () {
if(window.location.search.indexOf("dontFixSchedule")>=0)return;
    var api = new mw.Api();
    window.setInterval(function(){
        api.get({
            action:'query',
            pageids:REPLACE_ME_WITH_THE_PAGE_ID_OF_YOUR_SCHEDULE_PAGE,
            prop:'revisions',
            rvprop:'ids',
            uselang:'content',
            format:'json',
            formatversion:'2'
        }).then(function(res){
            var revid = res.query.pages[0].revisions[0].revid;
            if(revid !== mw.config.get('wgRevisionId')){
                mw.notify('Schedule changed. Reloading.');
                window.location.reload();
            }
        });
    },1000 * 60 * 2); // check every 2 minutes. if you wanted 5 minutes, replace the 2 with a 5.
});
}
DELETE THIS LINE WHEN COPYING. This is the end of the stuff that goes in MediaWiki:Common.js */
$.when(
    $.ready
).then( function () {
// quit immediately if dontFixSchedule is in the URL after the ?
if(window.location.search.indexOf("dontFixSchedule")>=0)return;

    // Configuration
    var CONFERENCE_DAYS = {
        "Friday, October 8": Date.UTC( 2021, /* month index, not month number! */ 9, 8 ),
        "Saturday, October 9": Date.UTC( 2021, 9, 9 ),
        "Sunday, October 10": Date.UTC( 2021, 9, 10 )
    };
    var WRITTEN_SCHEDULE_OFFSET_SECONDS = -4 * 3600; // written schedule for WCNA 2021 is Eastern Time which is UTC-4

    // Other constants
    var TIME_REGEX = /(\d\d):(\d\d)( - (\d\d):(\d\d)|\+)/;

    function pl( n ) { return ( Math.floor( n ) === 1 ) ? "" : "s"; }

    function textDescribingRelativeTime( minutesUntilStart, minutesUntilEnd, countdownDuringEvent ) {
        if ( minutesUntilStart > /* one day */ 1440 ) {
            return "in " + Math.floor( minutesUntilStart / 1440 ).toFixed( 0 ) + " day" + pl( minutesUntilStart / 1440 );
        } else if ( minutesUntilStart > /* 3 hours */ 180 ) {
            return "in " + Math.floor( minutesUntilStart / 60 ).toFixed( 0 ) + " hour" + pl( minutesUntilStart / 60 );
        } else if ( minutesUntilStart > 120 ) {
            return "in 2 hours and " + Math.floor( minutesUntilStart % 60 ).toFixed( 0 ) + " minute" + pl( minutesUntilStart % 60 );
        } else if ( minutesUntilStart > 60 ) {
            return "in an hour and " + Math.floor( minutesUntilStart % 60 ).toFixed( 0 ) + " minute" + pl( minutesUntilStart % 60 );
        } else if ( minutesUntilStart > 1 ) {
            return "in " + Math.floor( minutesUntilStart ).toFixed( 0 ) + " minute" + pl( minutesUntilStart );
        } else if ( minutesUntilStart > 0 ) {
            return "in less than a minute";
        } else if ( minutesUntilStart > -1 ) {
            return "started just now";
        } else if ( minutesUntilStart > -5 ) {
            return "started " + Math.floor( -minutesUntilStart ).toFixed( 0 ) + " minute" + pl( -minutesUntilStart ) + " ago";
        } else if ( minutesUntilEnd > 1 ) {
            if ( countdownDuringEvent ) {
                return "ends in " + Math.floor( minutesUntilEnd ).toFixed( 0 ) + " minute" + pl( minutesUntilEnd );
            } else {
                if ( minutesUntilStart > -60 ) {
                    return "started " + Math.floor( -minutesUntilStart ).toFixed( 0 ) + " minute" + pl( -minutesUntilStart ) + " ago";
                } else {
                    return "started " + Math.floor( -minutesUntilStart / 60 ).toFixed( 0 ) + " hour" + pl( -minutesUntilStart / 60 ) + " ago";
                }
            }
        } else if ( minutesUntilEnd > 0 ) {
            return "ends in one minute";
        } else if ( minutesUntilEnd > -1 ) {
            return "ended just now";
        } else if ( minutesUntilEnd > -60 ) {
            return "ended " + Math.floor( -minutesUntilEnd ).toFixed( 0 ) + " minute" + pl( -minutesUntilEnd ) + " ago";
        } else if ( minutesUntilEnd > -1440 ) {
            return "ended " + Math.floor( -minutesUntilEnd / 60 ).toFixed( 0 ) + " hour" + pl( -minutesUntilEnd / 60 ) + " ago";
        } else {
            return "ended " + Math.floor( -minutesUntilEnd / 1440 ).toFixed( 0 ) + " day" + pl( -minutesUntilEnd / 1440 ) + " ago";
        }
    }

    function formatRelativeTime( minutesUntilStart, minutesUntilEnd, countdownDuringEvent ) {
        var text = textDescribingRelativeTime( minutesUntilStart, minutesUntilEnd, countdownDuringEvent );
        if ( minutesUntilStart > 0 ) {
            return "(" + text + ")";
        } else if ( minutesUntilEnd > 0 ) {
            return "<b>(" + text + ")</b>";
        } else {
            return "<i>(" + text + ")</i>";
        }
    }

    function formatTime( unixTimestamp ) {
        return new Date( unixTimestamp * 1000 ).toLocaleTimeString().replace( /(\d\d?:\d\d):00/, "$1" ).replace( / /g, "&nbsp;" );
    }

    function makeHtml( originalTimeMatch, tableCell ) {
        var dayHeading = $( tableCell ).closest( "table" ).prev().prev(); // skip icon key
        var dayHeadingText = dayHeading.find( ".mw-headline" ).text();
        var baseDateUnix = Math.floor( CONFERENCE_DAYS[dayHeadingText] / 1000 );
        var isSoftEndingTime = !originalTimeMatch[4]; // if there's no group-4 match, no ending time was specified

        // First, get the actual timestamps
        var startTimeUnix = baseDateUnix + parseInt( originalTimeMatch[1], 10 ) * 3600 +
                parseInt( originalTimeMatch[2], 10 ) * 60 - WRITTEN_SCHEDULE_OFFSET_SECONDS;
        var endTimeUnix = isSoftEndingTime ? ( startTimeUnix + 3600 * 5 ) : ( baseDateUnix + parseInt( originalTimeMatch[4], 10 ) * 3600 +
                parseInt( originalTimeMatch[5], 10 ) * 60 - WRITTEN_SCHEDULE_OFFSET_SECONDS );

        // Now, get some text like "Starts in 10 minutes".
        var nowUnix = Math.floor( new Date().getTime() / 1000 );
        var relativeTimeFormatted = formatRelativeTime(
            ( startTimeUnix - nowUnix ) / 60,
            ( endTimeUnix - nowUnix ) / 60,
            /* countdownDuringEvent */ !isSoftEndingTime,
        );
        return formatTime( startTimeUnix ) + ( isSoftEndingTime ? "+" : ( " - " + formatTime( endTimeUnix ) ) ) + "<br />" + relativeTimeFormatted;
    }

    $( "small" ).each( function () {
        if ( this.textContent === "(US Eastern Time)" ) {
try{
            $( this ).text( "In " + Intl.DateTimeFormat().resolvedOptions().timeZone.replace( /_/g, " " ) + " time" );
}catch(e){
console.error(e);
$(this).text("In your local timezone (hover to see Eastern U.S. time)");
        }
        }
    } );

    $( "td" ).each( function () {
        var match = TIME_REGEX.exec( this.textContent );
        if ( match ) {
            this.innerHTML = this.innerHTML.replace( match[0], "<span class='fixed' title='"+match[0]+" Eastern Time' data-original='" + match[0] + "'>" + match[0] + "</span>" );
        }
    } );

    function go() {
        $( "span.fixed" ).each( function () {
            $( this ).html( makeHtml( TIME_REGEX.exec( this.dataset.original ), this.parentNode ) );
        } );
    }

    go();
    window.setInterval( go, 60 * 1000 );
} );