User:Tgr/conference-helper-WM2022.js

From Wikimania

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)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/**
 * Helper script to format the Wikimania 2022 program to work with [[User:Tgr/conference-helper.js]]
 * Dynamically updates the HTML of program pages to match the expectations of that script.
 * Also adds a button to the top right corner to jump to the currently ongoing event.
 *
 * This is a hack - ideally program pages should include machine-readable event start/end time
 * notation in the first place.
 *
 * Do not load conference-helper.js - this script will do that. Order of exectuion matters.
 */
( function() {
	function init() {
		var title = mw.config.get( 'wgPageName' );
	
		if ( title && title.match( /^2022:Program|Program\/Schedule($|\/)/ ) ) {
			$( document ).ready( function () {
				addZonestampDurations();
				replaceTimezone();
				addSessionStartEnd();
				loadCss();
				loadConferenceHelper();
				addCurrentButton();
			} );
		}
	}
	
	function addZonestampDurations() {
		$( '.zonestamp' ).each( function ( i ) {
			var $stamp = $( this ),
				startText = $stamp.attr( 'datetime' ),
				start = new Date( startText ),
				end = new Date( start ),
				durationText = $stamp.text(),
				matches = durationText.match( /\s*(\d+):(\d+)\s*-\s*(\d+):(\d+)\s*/ ),
				startHour = matches && parseInt( matches[1] ),
				startMinute = matches && parseInt( matches[2] ),
				endHour = matches && parseInt( matches[3] ),
				endMinute = matches && parseInt( matches[4] );
			
			if ( isNaN(start) ) {
				mw.log.error( 'could not parse zonestamp #%d: %s', i, start );
				return;
			} else if ( !matches ) {
				mw.log.error( 'could not parse zonestamp #%d: %s', i, durationText );
				return;
			}
			
			end.setUTCHours( endHour );
			end.setUTCMinutes( endMinute );
			if ( endHour < startHour ) {
				end.setUTCDate( start.getUTCDate() + 1 );
			}
			
			$stamp.attr( 'data-end-datetime', end.toISOString() );
		} );
	}
	
	function replaceTimezone() {
		$( 'th' ).each( function() {
			$(this).html( function ( i, html ) {
				return html.replace( /UTC \(click to see local time\)/,
					'<span class="lt-timezone">UTC (click to see local time)</span>' );
			} );
		} );
	}
	
	function addSessionStartEnd() {
		$( '.wikimania-2022-session' ).each( function ( i ) {
			var $sessionBlock = $( this ),
				$td = $sessionBlock.closest( 'td, th' ),
				rowspan = $td.attr( 'rowspan' ) || 1,
				$firstTimeBlock = $td.closest( 'tr' ).first( 'th' ),
				$lastTimeBlock =  $td.closest( 'tr' ).nextAll( 'tr' ).addBack().eq( rowspan - 1 ),
				startTime = $firstTimeBlock.find( 'time.zonestamp' ).attr( 'datetime' ),
				endTime = $lastTimeBlock && $lastTimeBlock.find( 'time.zonestamp' ).data( 'end-datetime' );
			
			if ( !startTime || !endTime ) {
				mw.log.error( 'could not find range data #%d: %o %o %s %s', i,
					$firstTimeBlock, $lastTimeBlock, startTime, endTime );
				return;
			}
			
			$sessionBlock.data( 'start', startTime );
			$sessionBlock.data( 'end', endTime );
			$sessionBlock.addClass( 'lt-highlight-td-if-now' );
		} );
	}
	
	function addCurrentButton() {
		var $button = $(
			'<a id="lt-current-button" href="#lt-current" style="display:block; float:right">' +
				'<button class="mw-ui-button" role="button">' +
					'Jump to current session' +
				'</button>' +
			'</a>'
		);
		
		$( '#firstHeading' ).before( $button );

		function updateButtonState() {
			if ( $( '#lt-current' ).length &&
				$button.find( 'button' ).attr( 'disabled' )
			) {
				$button.find( 'button' ).attr( 'disabled', null );
				$button.css( 'pointer-events', 'auto' );
			} else if ( !$( '#lt-current' ).length &&
				!$button.find( 'button' ).attr( 'disabled' )
			) {
				$button.find( 'button' ).attr( 'disabled', true );
				$button.css( 'pointer-events', 'none' );
			}
		}
		
		updateButtonState();
		setInterval( updateButtonState, 10 * 1000 );
	}

	function loadCss() {
		mw.loader.load('https://wikimania.wikimedia.org/w/index.php?title=Template:Test/User:Tgr/conference.css&action=raw&ctype=text/css', 'text/css');
	}

	function loadConferenceHelper() {
		mw.loader.load('https://wikimania.wikimedia.org/w/index.php?title=User:Tgr/conference-helper.js&action=raw&ctype=text/javascript');
	}

	init();
} )();