MediaWiki:Gadget-RightToolbar.js

Maintenance script​(留言 | 贡献)2026年7月16日 (四) 16:59的版本 (维护 RightToolbar:样式归一到 CSS 页)

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
  • Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
/* MediaWiki Gadget: RightToolbar */
( function () {
	'use strict';

	mw.loader.using( [ 'mediawiki.util' ] ).then( function () {
		function msg( key ) {
			var lang = mw.config.get( 'wgUserLanguage' ) || mw.config.get( 'wgContentLanguage' ) || 'zh-cn';
			var en = lang.toLowerCase().indexOf( 'en' ) === 0;
			var messages = {
				top: en ? '▲' : '▲',
				bottom: en ? '▼' : '▼',
				topTitle: en ? 'Back to top' : '回到顶部',
				bottomTitle: en ? 'Back to bottom' : '回到底部',
				loading: en ? 'Loading...' : '加载中...'
			};
			return messages[ key ];
		}

		function createButton( id, text, tooltip, clickHandler ) {
			var button = document.createElement( 'button' );
			button.id = id;
			button.className = 'mw-rt-button';
			button.title = tooltip;
			button.textContent = text;
			button.type = 'button';
			button.addEventListener( 'click', clickHandler );
			return button;
		}

		function renderClock() {
			var now = new Date();
			var userLang = mw.config.get( 'wgUserLanguage' ) || 'zh-cn';
			var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

			function formatParts( zone ) {
				var parts = new Intl.DateTimeFormat( userLang, {
					year: 'numeric',
					month: 'long',
					day: 'numeric',
					hour: '2-digit',
					minute: '2-digit',
					second: '2-digit',
					hour12: false,
					timeZone: zone
				} ).formatToParts( now );

				return {
					date: parts.filter( function ( part ) {
						return part.type === 'year' || part.type === 'month' || part.type === 'day';
					} ).map( function ( part ) {
						return part.value;
					} ).join( ' ' ),
					time: parts.filter( function ( part ) {
						return part.type === 'hour' || part.type === 'minute' || part.type === 'second';
					} ).map( function ( part ) {
						return part.value;
					} ).join( ':' )
				};
			}

			var local = formatParts( timeZone );
			var utc = formatParts( 'UTC' );
			var localDateEl = document.getElementById( 'mw-local-date' );
			var localTimeEl = document.getElementById( 'mw-local-time' );
			var utcTimeEl = document.getElementById( 'mw-utc-time' );

			if ( localDateEl ) {
				localDateEl.textContent = local.date;
			}
			if ( localTimeEl ) {
				localTimeEl.textContent = local.time;
			}
			if ( utcTimeEl ) {
				utcTimeEl.textContent = 'UTC: ' + utc.date + ' ' + utc.time;
			}
		}

		function initToolbar() {
			var isMobile = window.innerWidth <= 768;
			var container = document.getElementById( 'mw-right-toolbar' );
			var topButton;
			var bottomButton;
			var clockDiv;
			var ticking = false;
			var clockTimer;

			if ( !container ) {
				container = document.createElement( 'div' );
				container.id = 'mw-right-toolbar';
				container.className = 'mw-right-toolbar';
				document.body.appendChild( container );
			}

			topButton = document.getElementById( 'mw-scroll-top' );
			if ( !topButton ) {
				topButton = createButton( 'mw-scroll-top', msg( 'top' ), msg( 'topTitle' ), function () {
					window.scrollTo( { top: 0, behavior: 'smooth' } );
				} );
				container.appendChild( topButton );
			}

			bottomButton = document.getElementById( 'mw-scroll-bottom' );
			if ( !bottomButton ) {
				bottomButton = createButton( 'mw-scroll-bottom', msg( 'bottom' ), msg( 'bottomTitle' ), function () {
					window.scrollTo( { top: document.body.scrollHeight, behavior: 'smooth' } );
				} );
				container.appendChild( bottomButton );
			}

			clockDiv = document.getElementById( 'mw-right-toolbar-clock' );
			if ( !isMobile && !clockDiv ) {
				clockDiv = document.createElement( 'div' );
				clockDiv.id = 'mw-right-toolbar-clock';
				clockDiv.className = 'mw-rt-clock';
				clockDiv.innerHTML = '<div id="mw-local-date"></div><div id="mw-local-time"></div><div id="mw-utc-time"></div>';
				clockDiv.firstChild.textContent = msg( 'loading' );
				container.appendChild( clockDiv );
			}

			topButton.style.display = 'none';
			window.addEventListener( 'scroll', function () {
				if ( ticking ) {
					return;
				}
				ticking = true;
				window.requestAnimationFrame( function () {
					var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
					topButton.style.display = scrollTop > 200 ? 'block' : 'none';
					ticking = false;
				} );
			} );

			window.requestAnimationFrame( function () {
				container.classList.add( 'is-visible' );
			} );

			clockTimer = window.setInterval( renderClock, 1000 );
			renderClock();
			mw.hook( 'user.languageChange' ).add( renderClock );

			document.addEventListener( 'visibilitychange', function () {
				if ( document.hidden ) {
					window.clearInterval( clockTimer );
					clockTimer = null;
					return;
				}
				if ( !clockTimer ) {
					clockTimer = window.setInterval( renderClock, 1000 );
					renderClock();
				}
			} );
		}

		if ( document.readyState === 'loading' ) {
			document.addEventListener( 'DOMContentLoaded', initToolbar );
		} else {
			initToolbar();
		}
	} );
}() );