|
|
Line 1: |
Line 1: |
| /** | | /* |
| * Enables or disables the dark-mode gadget. | | * WikimediaUI Dark Mode |
| * | | * |
| * Authors: [[User:SD0001]], [[User:Nardog]] | | * Original authors: |
| | * - Volker E. (Wikimedia Foundation Product Design) |
| | * - Alex Hollender (Wikimedia Foundation Product Design) |
| | * - Ed Sanders |
| | * - MusikAnimal |
| | * |
| | * Last updated: 2020-04-24 |
| */ | | */ |
|
| |
|
| // 'Dark mode' and 'Light mode' messages must match the ::before content in | | // Load dependencies (remove when loading through ResourceLoader). |
| // [[MediaWiki:Gadget-dark-mode-toggle-pagestyles.css]] and [[MediaWiki:Gadget-dark-mode.css]], respectively. | | mw.loader.load( 'https://en.wikipedia.org/w/index.php?title=User:Volker_E._(WMF)/dark-mode.css&action=raw&ctype=text/css', 'text/css' ); |
| // Don't overwrite existing messages, if already set on a foreign wiki prior to loading this file | | // User has dark color scheme preference set in operating system. |
| if (!mw.messages.get('darkmode-turn-on-label')) { | | if ( window.matchMedia( '( prefers-color-scheme: dark )' ).matches || mw.storage.get( 'client-dark-mode-toggle' ) === '1' ) { |
| mw.messages.set({
| | document.documentElement.className = 'client-dark-mode'; |
| 'darkmode-turn-on-label': 'Dark mode',
| |
| 'darkmode-turn-on-tooltip': 'Turn dark mode on',
| |
| 'darkmode-turn-off-label': 'Light mode',
| |
| 'darkmode-turn-off-tooltip': 'Turn dark mode off',
| |
| });
| |
| } | | } |
|
| |
|
| $.when($.ready, mw.loader.using(['mediawiki.util', 'mediawiki.api', 'mediawiki.Uri', 'mediawiki.storage', 'es6-polyfills'])).then(function() { | | $( function () { |
| var isOn = !!mw.user.options.get('gadget-dark-mode'); | | // Fix logos. |
| | | $( '#p-logo' ).clone().addClass( 'mw-no-invert' ).insertAfter( '#p-logo' ); |
| if (isOn) {
| | |
| // CSS class for externally styling elements in dark mode via TemplateStyles (or CSS from other gadgets or common.css)
| | mw.util.addPortletLink( 'p-personal', '#', 'Dark mode', 'pt-darkmode', '', 'np', '#pt-watchlist' ); |
| // A brief flash of the original styles will occur, so this is only suitable for style changes for which flashes are tolerable.
| |
| // For others, update Gadget-dark-mode.css directly which is loaded without FOUCs
| |
| document.documentElement.classList.add('client-dark-mode');
| |
|
| |
| // Update the initial minerva theme-color
| |
| $('meta[name="theme-color"]').attr('content', '#000000');
| |
| }
| |
| | |
| var onOrOff = isOn ? 'off' : 'on';
| |
| var label = mw.msg('darkmode-turn-' + onOrOff + '-label');
| |
| var tooltip = mw.msg('darkmode-turn-' + onOrOff + '-tooltip');
| |
| var nextnode = mw.config.get('skin') !== 'minerva' && '#pt-watchlist'; | |
| var portletLink = mw.util.addPortletLink('p-personal', '#', label, 'pt-darkmode', tooltip, '', nextnode); | |
| | |
| function toggleMode() {
| |
| var newState = Number(!mw.user.options.get('gadget-dark-mode'));
| |
| new mw.Api().saveOption('gadget-dark-mode', newState);
| |
| mw.user.options.set('gadget-dark-mode', newState);
| |
| $(document.documentElement).toggleClass('client-dark-mode', !!newState);
| |
| | |
| // In case the user navigates to another page too quickly
| |
| mw.storage.session.set('dark-mode-toggled', newState);
| |
| | |
| var onOrOff = ['on', 'off'][newState];
| |
| | |
| // Toggle portlet link label and tooltip
| |
| var labelSelector = ['vector', 'minerva'].includes(mw.config.get('skin')) ? '#pt-darkmode span:not(.mw-ui-icon)' : '#pt-darkmode a';
| |
| $(labelSelector).text(mw.msg('darkmode-turn-' + onOrOff + '-label'));
| |
| $('#pt-darkmode a').attr('title', mw.msg('darkmode-turn-' + onOrOff + '-tooltip'));
| |
| // Update the minerva theme-color
| |
| $('meta[name="theme-color"]').attr('content', newState ? '#000000' : '#eaecf0' );
| |
| | |
| // Modify the <link> element on the page to include/exclude dark-mode styles
| |
| // We can't use mw.loader as it doesn't work both ways (see talk page)
| |
| var scriptPath = mw.util.wikiScript('load');
| |
| var gadgetsLinkElement = $('link[rel="stylesheet"][href^="' + scriptPath + '?"][href*="ext.gadget."]')[0];
| |
| if (gadgetsLinkElement) {
| |
| var uri = new mw.Uri(gadgetsLinkElement.href);
| |
| if (newState) {
| |
| uri.query.modules += ',dark-mode';
| |
| } else {
| |
| uri.query.modules = uri.query.modules
| |
| .replace('ext.gadget.dark-mode', 'ext.gadget.') // dark-mode is first in the gadget list
| |
| .replace(/,dark-mode(,|$)/, '$1'); // dark-mode is in middle or end of the list
| |
| }
| |
| gadgetsLinkElement.href = uri.getRelativePath();
| |
| } else {
| |
| // No gadget-containing styles are enabled
| |
| $('<link>').attr({
| |
| rel: 'stylesheet',
| |
| href: scriptPath + '?lang=' + mw.config.get('wgUserLanguage') +
| |
| '&modules=ext.gadget.dark-mode&only=styles&skin=' + mw.config.get('skin')
| |
| }).appendTo(document.head);
| |
| }
| |
| }
| |
| | |
| $(portletLink).on('click', function(e) {
| |
| e.preventDefault();
| |
| toggleMode();
| |
| });
| |
| | |
| // Recover state if the navigation was too quick
| |
| var storageState = mw.storage.session.get('dark-mode-toggled');
| |
| if (storageState && Number(storageState) !== Number(isOn)) {
| |
| toggleMode();
| |
| }
| |
| | |
| if (window.wpDarkModeAutoToggle) {
| |
| var toggleBasedOnSystemColourScheme = function () {
| |
| var systemSchemeNow = matchMedia('(prefers-color-scheme: dark)').matches;
| |
| var systemSchemeLast = mw.storage.get('dark-mode-system-scheme') === '1';
| |
| | |
| var wpSchemeNow = !!mw.user.options.get('gadget-dark-mode');
| |
| | |
| if (systemSchemeNow !== systemSchemeLast) {
| |
| if (systemSchemeNow !== wpSchemeNow) {
| |
| toggleMode();
| |
| }
| |
| mw.requestIdleCallback(function() {
| |
| mw.storage.set('dark-mode-system-scheme', Number(systemSchemeNow));
| |
| });
| |
| }
| |
| };
| |
| | |
| toggleBasedOnSystemColourScheme();
| |
|
| |
|
| // If system colour scheme changes while user is viewing, toggle immediately
| | $( '#pt-darkmode' ).on( 'click', function( e ) { |
| var mediaQuery = matchMedia('(prefers-color-scheme: dark)');
| | var $html = $( 'html' ); |
| if (mediaQuery.addEventListener) {
| | e.preventDefault(); |
| mediaQuery.addEventListener('change', toggleBasedOnSystemColourScheme);
| | |
| } else if (mediaQuery.addListener) { // Safari 13 and older
| | $html.toggleClass( 'client-dark-mode' ); |
| mediaQuery.addListener(toggleBasedOnSystemColourScheme); | | mw.storage.set( |
| } | | 'client-dark-mode-toggle', |
| }
| | String( Number( $html.hasClass( 'client-dark-mode' ) ) ) |
| }); | | ); |
| | } ); |
| | } ); |