MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
no edit summary
imported>Logoarto No edit summary |
imported>Logoarto No edit summary |
||
Line 323: | Line 323: | ||
/*Discord widget*/ | /*Discord widget*/ | ||
$( "#discord-widget" ).html('<iframe src="https://discord.com/widget?id=333345832059273216&theme=dark" width="100%" height="255px" allowtransparency="true" frameborder="0" sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"></iframe>'); | $( "#discord-widget" ).html('<iframe src="https://discord.com/widget?id=333345832059273216&theme=dark" width="100%" height="255px" allowtransparency="true" frameborder="0" sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"></iframe>'); | ||
/** | |||
* 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(.mw-ui-icon), #pt-darkmode-sticky-header span:not(.mw-ui-icon)'; | |||
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); | |||
} | |||
} | |||
}); |