:User:Ahecht/Scripts/UTCLiveClock.js

/**

*

* This gadget adds a clock in the personal toolbar that shows the current time

* in UTC (or a different timezone of your choosing), and also provides a link

* to recursively purge the current page.

*

* Based on: https://www.mediawiki.org/wiki/MediaWiki:Gadget-UTCLiveClock.js (Revision: July 2020)

*

* Installation:

*

* Add the following line to Special:MyPage/common.js or :meta:Special:MyPage/global.js to install:

* mw.loader.load( "//en.wikipedia.org/w/index.php?title=User:Ahecht/Scripts/UTCLiveClock.js&action=raw&ctype=text/javascript" ); // Linkback: :en:User:Ahecht/Scripts/UTCLiveClock.js

*

* To set the timezone used to one other than UTC, set window.LiveClockTimeZone to

* the desired timezone. For example, adding the following to your common.js

* window.LiveClockTimeZone = 'America/Los_Angeles';

* would result in the local time in Los Angeles being shown. See

* :w:List of tz database time zones for valid options (use the TZ database name).

*

**/

/* Below line defaults to a recursive link update */

window.LiveClockPurgeType = window.LiveClockPurgeType || "forcerecursivelinkupdate";

/*global mw, $ */

mw.loader.using( ['mediawiki.util', 'mediawiki.api', 'user'] ).then( function () {

var liveClockTimeZoneFormat, liveClockDateFormat;

function makeTzFunction() {

window.LiveClockTimeZone_old = window.LiveClockTimeZone;

var timezone = window.LiveClockTimeZone || 'UTC';

if ( timezone == 'local' ) return false;

try {

return new Intl.DateTimeFormat('en-US', {

timeZone: timezone,

dateStyle:'medium',

timeStyle:'medium'

}).format;

} catch ( err ) {

console.warn( "LiveClock - error creating Intl object with timezone '" + timezone + "': " + err.name);

if ( timezone == 'UTC' ) return false;

window.LiveClockTimeZone = 'UTC';

return makeTzFunction();

}

}

function padWithZeroes( num ) {

// Pad a number with zeroes. The number must be an integer where

// 0 <= num < 100.

return num < 10 ? '0' + num.toString() : num.toString();

}

function showTime( $target ) {

var now = new Date();

if ( window.LiveClockTimeZone_old != window.LiveClockTimeZone ) {

liveClockTimeZoneFormat = makeTzFunction();

}

// Set the time.

var newNow = now;

if ( liveClockTimeZoneFormat !== false ) {

newNow = new Date( liveClockTimeZoneFormat(now) );

}

var time = padWithZeroes( newNow.getHours() ) + ':' + padWithZeroes( newNow.getMinutes() );

if ( !(window.LiveClockHideSeconds || false) ) {

time = time + ':' + padWithZeroes( newNow.getSeconds() );

}

$target.text( time );

// Set the date.

$target.attr( 'title', liveClockDateFormat(newNow) );

// Schedule the next time change.

//

// We schedule the change for 100 ms _after_ the next clock tick. The delay

// from setTimeout is not precise, and if we aim exactly for the tick, there

// is a chance that the function will run slightly before it. If this

// happens, we will display the same time for two seconds in a row - not

// good. By scheduling 100 ms after the tick, we will always be about 100 ms

// late, but we are also very likely to display a new time every second.

var ms = now.getUTCMilliseconds();

setTimeout( function () {

showTime( $target );

}, 1100 - ms );

}

function liveClock() {

// Set CSS styles. We do this here instead of on the CSS page because some

// wikis load this page directly, without loading the accompanying CSS.

mw.util.addCSS( '#utcdate a { font-weight:bolder; font-size:120%; }' );

// Reset whitespace that was set in the peer CSS gadget; this prevents the

// effect of the p-personal menu jumping to the left when the JavaScript

// loads.

$( '.client-js > body.skin-vector #p-personal ul' ).css( 'margin-right', 'initial' );

$( '.client-js > body.skin-monobook #p-personal ul' ).css( 'margin-right', 'initial' );

// Create date/time formatting functions. This is done once as opposed to using

// toLocaleString to avoid multiple localization database lookups.

liveClockDateFormat = new Intl.DateTimeFormat( navigator.language, {dateStyle: 'full'} ).format;

liveClockTimeZoneFormat = makeTzFunction();

// We are experimenting with different locations for this in Vector 2022 based on feedback

// so currently this is limited to MediaWiki.org

var dbName = mw.config.get( 'wgDBname' );

var showOutsideDropdown = dbName === 'mediawikiwiki' || dbName === 'enwiki';

var clockLocation = document.getElementById( 'p-vector-user-menu-overflow' ) && showOutsideDropdown ?

'p-vector-user-menu-overflow' : 'p-personal';

addLiveClockInstance( clockLocation );

addLiveClockInstance( 'p-personal-sticky-header' );

}

function addLiveClockInstance( clockLocation ) {

var purge = { action: 'purge' };

var re = new RegExp( '^force(?:recursive)?linkupdate$' );

if ( re.test(window.LiveClockPurgeType) ) {

purge[window.LiveClockPurgeType] = '1';

}

// Add the portlet link.

var node = mw.util.addPortletLink(

clockLocation,

mw.util.getUrl( null, purge ),

'',

'utcdate',

''

);

if ( !node ) {

return;

}

// Purge the page when the clock is clicked. We have to do this through the

// API, as purge URLs now make people click through a confirmation screen.

$( node ).on( 'click', function ( e ) {

purge.titles = mw.config.get( 'wgPageName' );

new mw.Api( { userAgent: 'UTCLiveClock/0.0.1' } ).post( purge ).then( function () {

location.reload();

}, function () {

mw.notify( 'Purge failed', { type: 'error' } );

} );

e.preventDefault();

} );

// Show the clock.

showTime( $( node ).find( 'a' ).first() );

}

$( liveClock );

} );