User:Tgr/conference-helper.js
Appearance
< User:Tgr
Note: After publishing, 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)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* Various functionality for on-wiki conference pages:
* - show <time> elements in the user's local time
* - align time zone names with the used time zone
* - highlight events currently in progress
*
* 1) Show <time> elements in the user's local time: the content of any <time>
* elements with one of the 'zonestamp', 'tpl-zonestamp' 'lt-time' classes
* will be replaced with the element's datetime attribute, converted to the
* user's local timezone (as defined by the browser) and formatted as HH:mm.
* If the element has an 'end-datetime' data attribute, it will show both,
* formatted as HH:mm - HH:mm.
* The {{zonestamp}} template can be used to generate such elements, with a
* no-JS fallback.
*
* 2) Align time zone names with the used time zone: the content of elements
* with an 'lt-timezone' class will be replaced with the short name of the
* user's timezone. The intention with this is to write
* <span class="lt-timezone">UTC</span> and then the times and time zones
* on the page will stay consistent whether the user has enabled this
* helper or not.
*
* 3) Highlight events currently in progress: any elements with a
* 'lt-highlight-if-now' class and 'start' and 'end' data attributes will get
* an additional 'lt-highlighted' class if the current time is between the
* given start and end timestamps. Alternatively, 'lt-highlight-td-if-now'
* will result in the closest <td> parent getting 'lt-highlighted'.
* It also adds a 'lt-current' id attribute to the first such element.
*
* Test page: https://wikimania.wikimedia.org/wiki/User:Tgr/conference-helper/test
*/
( function () {
var timezone,
highlightTimer,
fmt = Intl.DateTimeFormat( Navigator.language, { timeStyle: 'short' } );
timezone = new Intl.DateTimeFormat( Navigator.language, { timeZoneName: 'short' } )
.formatToParts( new Date() )
.filter( function( el ) {
return el.type === 'timeZoneName';
} ).map( function( el ) {
return el.value;
} )[0] || null;
if ( !timezone ) {
return;
}
function localizeTimeElements() {
$( 'time.zonestamp, time.tpl-zonestamp, time.lt-time' ).each( function ( i ) {
var text = '',
$time = $( this ),
startText = $time.attr( 'datetime' ),
endText = $time.data( 'end-datetime' ),
start = new Date( startText ),
end = endText ? new Date( endText ) : null;
if ( isNaN( start ) ) {
// could not parse the date, bail out
mw.log.error( 'Invalid start date #%d: %s', i, startText );
$time.addClass( 'error' );
return;
} else if ( isNaN( end ) ) {
mw.log.error( 'Invalid end date #%d: %s', i, startText );
$time.addClass( 'error' );
return;
} else if ( end && ( end < start ) ) {
mw.log.error( 'Invalid range #%d: %s - %s', i, startText, endText );
$time.addClass( 'error' );
return;
}
if ( end ) {
text = fmt.formatRange( start, end );
} else {
text = fmt.format( start );
}
$time.text( text );
} );
}
function localizeTimezone() {
$( '.lt-timezone' ).each( function () {
var $timezone = $( this );
$timezone.text( timezone );
} );
}
function highlightCurrent() {
var firstCurrentFound = false;
$( '.lt-highlight-if-now, .lt-highlight-td-if-now' ).each( function () {
var $this = $( this ),
$target = $( [] ),
start = new Date( $this.data( 'start' ) ),
end = new Date( $this.data( 'end' ) ),
now = new Date(),
current = end && start <= now && now <= end;
if ( isNaN( start ) || isNaN( end ) ) {
return;
}
if ( $this.hasClass( 'lt-highlight-if-now' ) ) {
$target = $target.add( $this );
}
if ( $this.hasClass( 'lt-highlight-td-if-now' ) ) {
$target = $target.add( $this.closest( 'td' ) );
}
$target.toggleClass( 'lt-highlighted', current );
if ( current && !firstCurrentFound && $target.length ) {
$( '#lt-current' ).attr( 'id', null );
$target.last().attr( 'id', 'lt-current' );
}
} );
}
mw.hook( 'wikipage.content' ).add( function () {
localizeTimeElements();
localizeTimezone();
highlightCurrent();
if ( !highlightTimer ) {
highlightTimer = setInterval( function () {
highlightCurrent();
}, 60 * 1000 );
}
} );
} )();