/**  * 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': 'আঁধার মোড', 		'darkmode-turn-on-tooltip': 'আঁধার মোড চালু করুন', 		'darkmode-turn-off-label': 'উজ্জ্বল মোড', 		'darkmode-turn-off-tooltip': 'আঁধার মোড বন্ধ করুন', 	}); }  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  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 		$('').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); 		} 	} });