From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/**

 * Enables or disables the dark-mode gadget.

 *

 * Authors: [[User:SD0001]], [[User:Nardog]]

 */



// 'Dark mode' and 'Light mode' messages must match the ::before content in

// [[MediaWiki:Gadget-dark-mode-toggle-pagestyles.css]] and [[MediaWiki:Gadget-dark-mode.css]], respectively.

// Don't overwrite existing messages, if already set on a foreign wiki prior to loading this file

if (!mw.messages.get('darkmode-turn-on-label')) {

	mw.messages.set({

		'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',

	});

}



var isOn = mw.loader.getState('ext.gadget.dark-mode') === 'ready';



var broadcastChannel = new BroadcastChannel('gadget-dark-mode');



function setThemeColor() {

	// Update the theme-color used by some browsers for coloration of the tab headers and surrounding UI

	$('meta[name="theme-color"]').attr('content', isOn ? '#000000' : '#eaecf0');

}



function setHtmlClass() {

	// CSS class for externally styling elements in dark mode via TemplateStyles (or CSS from other gadgets or common.css)

	// 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).toggleClass('client-dark-mode', isOn);

}



function vectorStickyCallback() {

	mw.hook('vector.page_title_scroll').remove(vectorStickyCallback);

	if (document.getElementById('pt-darkmode-sticky-header')) return;

	makePortletLink('p-personal-sticky-header', 'pt-darkmode-sticky-header', '#pt-watchlist-sticky-header');

}



function addPortlets() {

	makePortletLink('p-personal', 'pt-darkmode', '#pt-watchlist');



	if (mw.config.get('skin') === 'vector-2022') {

		mw.hook('vector.page_title_scroll').add(vectorStickyCallback);

	}

}



function getMsg(suffix) {

	var key = 'darkmode-turn-' + (isOn ? 'off' : 'on') + '-' + suffix;

	return mw.msg(key);

}



function makePortletLink(portletId, portletLinkId, nextnode) {

	var label = getMsg('label');

	var tooltip = getMsg('tooltip');

	$(mw.util.addPortletLink(portletId, '#', label, portletLinkId, tooltip, '', nextnode))

		.children().on('click', function (e) {

			e.preventDefault();

			toggleMode();

		});

}



function togglePortlets() {

	var labelSelector;

	switch (mw.config.get('skin')) {

		case 'vector':

		case 'vector-2022':

		case 'minerva':

			labelSelector = '#pt-darkmode span:not(:empty), #pt-darkmode-sticky-header span:not(:empty)';

			break;

		default:

			labelSelector = '#pt-darkmode a';

	}

	$(labelSelector).text(getMsg('label'));

	$('#pt-darkmode a, #pt-darkmode-sticky-header a')

		.attr('title', getMsg('tooltip'));

}



function actuallyToggleDarkMode() {

	// 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 $gadgetsLink = $('link[rel="stylesheet"][href^="' + scriptPath + '?"][href*="ext.gadget."]');

	if ($gadgetsLink.length) {

		var uri = new mw.Uri($gadgetsLink.prop('href'));

		if (isOn) {

			uri.query.modules += ',dark-mode';

		} else {

			if (uri.query.modules === 'ext.gadget.dark-mode') {

				// dark-mode is the only module in this link

				$gadgetsLink.remove();

				return;

			}

			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

		}

		$gadgetsLink.prop('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);

	}

}



function savePreference() {

	new mw.Api().saveOption('gadget-dark-mode', isOn ? '1' : '0');

}



function savePreferenceLocally() {

	mw.user.options.set('gadget-dark-mode', Number(isOn));



	// In case the user navigates to another page too quickly

	mw.storage.session.set('dark-mode-toggled', isOn ? '1' : '0');

}



function notifyOtherTabs() {

	// Broadcast state change to other tabs

	broadcastChannel.postMessage(isOn);

}



function toggleMode(offline) {

	isOn = !isOn;

	if (!offline) {

		savePreference();

		notifyOtherTabs();

	}

	setHtmlClass();

	setThemeColor();

	savePreferenceLocally();

	togglePortlets();

	actuallyToggleDarkMode();

}



function toggleBasedOnSystemColourScheme() {

	var systemSchemeNow = matchMedia('(prefers-color-scheme: dark)').matches;

	var systemSchemeLast = mw.storage.get('dark-mode-system-scheme') === '1';



	if (systemSchemeNow !== systemSchemeLast) {

		if (systemSchemeNow !== isOn) {

			toggleMode();

		}

		mw.requestIdleCallback(function () {

			mw.storage.set('dark-mode-system-scheme', systemSchemeNow ? '1' : '0');

		});

	}

}





$.when($.ready, mw.loader.using(['mediawiki.util', 'mediawiki.api', 'mediawiki.Uri', 'mediawiki.storage'])).then(function () {

	setHtmlClass();

	setThemeColor();

	addPortlets();



	// Recover state if the navigation was too quick

	var storageState = mw.storage.session.get('dark-mode-toggled');

	if (storageState && Number(storageState) !== Number(isOn)) {

		toggleMode(true);

	}



	// Listen to dark mode state change made on other tabs

	broadcastChannel.onmessage = function (msg) {

		if (msg.data !== isOn) {

			toggleMode(true);

		}

	};



	if (window.wpDarkModeAutoToggle) {

		toggleBasedOnSystemColourScheme();



		// If system colour scheme changes while user is viewing, toggle immediately

		var mediaQuery = matchMedia('(prefers-color-scheme: dark)');

		if (mediaQuery.addEventListener) {

			mediaQuery.addEventListener('change', toggleBasedOnSystemColourScheme);

		} else if (mediaQuery.addListener) { // Safari 13 and older

			mediaQuery.addListener(toggleBasedOnSystemColourScheme);

		}

	}

});
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/**

 * Enables or disables the dark-mode gadget.

 *

 * Authors: [[User:SD0001]], [[User:Nardog]]

 */



// 'Dark mode' and 'Light mode' messages must match the ::before content in

// [[MediaWiki:Gadget-dark-mode-toggle-pagestyles.css]] and [[MediaWiki:Gadget-dark-mode.css]], respectively.

// Don't overwrite existing messages, if already set on a foreign wiki prior to loading this file

if (!mw.messages.get('darkmode-turn-on-label')) {

	mw.messages.set({

		'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',

	});

}



var isOn = mw.loader.getState('ext.gadget.dark-mode') === 'ready';



var broadcastChannel = new BroadcastChannel('gadget-dark-mode');



function setThemeColor() {

	// Update the theme-color used by some browsers for coloration of the tab headers and surrounding UI

	$('meta[name="theme-color"]').attr('content', isOn ? '#000000' : '#eaecf0');

}



function setHtmlClass() {

	// CSS class for externally styling elements in dark mode via TemplateStyles (or CSS from other gadgets or common.css)

	// 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).toggleClass('client-dark-mode', isOn);

}



function vectorStickyCallback() {

	mw.hook('vector.page_title_scroll').remove(vectorStickyCallback);

	if (document.getElementById('pt-darkmode-sticky-header')) return;

	makePortletLink('p-personal-sticky-header', 'pt-darkmode-sticky-header', '#pt-watchlist-sticky-header');

}



function addPortlets() {

	makePortletLink('p-personal', 'pt-darkmode', '#pt-watchlist');



	if (mw.config.get('skin') === 'vector-2022') {

		mw.hook('vector.page_title_scroll').add(vectorStickyCallback);

	}

}



function getMsg(suffix) {

	var key = 'darkmode-turn-' + (isOn ? 'off' : 'on') + '-' + suffix;

	return mw.msg(key);

}



function makePortletLink(portletId, portletLinkId, nextnode) {

	var label = getMsg('label');

	var tooltip = getMsg('tooltip');

	$(mw.util.addPortletLink(portletId, '#', label, portletLinkId, tooltip, '', nextnode))

		.children().on('click', function (e) {

			e.preventDefault();

			toggleMode();

		});

}



function togglePortlets() {

	var labelSelector;

	switch (mw.config.get('skin')) {

		case 'vector':

		case 'vector-2022':

		case 'minerva':

			labelSelector = '#pt-darkmode span:not(:empty), #pt-darkmode-sticky-header span:not(:empty)';

			break;

		default:

			labelSelector = '#pt-darkmode a';

	}

	$(labelSelector).text(getMsg('label'));

	$('#pt-darkmode a, #pt-darkmode-sticky-header a')

		.attr('title', getMsg('tooltip'));

}



function actuallyToggleDarkMode() {

	// 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 $gadgetsLink = $('link[rel="stylesheet"][href^="' + scriptPath + '?"][href*="ext.gadget."]');

	if ($gadgetsLink.length) {

		var uri = new mw.Uri($gadgetsLink.prop('href'));

		if (isOn) {

			uri.query.modules += ',dark-mode';

		} else {

			if (uri.query.modules === 'ext.gadget.dark-mode') {

				// dark-mode is the only module in this link

				$gadgetsLink.remove();

				return;

			}

			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

		}

		$gadgetsLink.prop('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);

	}

}



function savePreference() {

	new mw.Api().saveOption('gadget-dark-mode', isOn ? '1' : '0');

}



function savePreferenceLocally() {

	mw.user.options.set('gadget-dark-mode', Number(isOn));



	// In case the user navigates to another page too quickly

	mw.storage.session.set('dark-mode-toggled', isOn ? '1' : '0');

}



function notifyOtherTabs() {

	// Broadcast state change to other tabs

	broadcastChannel.postMessage(isOn);

}



function toggleMode(offline) {

	isOn = !isOn;

	if (!offline) {

		savePreference();

		notifyOtherTabs();

	}

	setHtmlClass();

	setThemeColor();

	savePreferenceLocally();

	togglePortlets();

	actuallyToggleDarkMode();

}



function toggleBasedOnSystemColourScheme() {

	var systemSchemeNow = matchMedia('(prefers-color-scheme: dark)').matches;

	var systemSchemeLast = mw.storage.get('dark-mode-system-scheme') === '1';



	if (systemSchemeNow !== systemSchemeLast) {

		if (systemSchemeNow !== isOn) {

			toggleMode();

		}

		mw.requestIdleCallback(function () {

			mw.storage.set('dark-mode-system-scheme', systemSchemeNow ? '1' : '0');

		});

	}

}





$.when($.ready, mw.loader.using(['mediawiki.util', 'mediawiki.api', 'mediawiki.Uri', 'mediawiki.storage'])).then(function () {

	setHtmlClass();

	setThemeColor();

	addPortlets();



	// Recover state if the navigation was too quick

	var storageState = mw.storage.session.get('dark-mode-toggled');

	if (storageState && Number(storageState) !== Number(isOn)) {

		toggleMode(true);

	}



	// Listen to dark mode state change made on other tabs

	broadcastChannel.onmessage = function (msg) {

		if (msg.data !== isOn) {

			toggleMode(true);

		}

	};



	if (window.wpDarkModeAutoToggle) {

		toggleBasedOnSystemColourScheme();



		// If system colour scheme changes while user is viewing, toggle immediately

		var mediaQuery = matchMedia('(prefers-color-scheme: dark)');

		if (mediaQuery.addEventListener) {

			mediaQuery.addEventListener('change', toggleBasedOnSystemColourScheme);

		} else if (mediaQuery.addListener) { // Safari 13 and older

			mediaQuery.addListener(toggleBasedOnSystemColourScheme);

		}

	}

});

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook