User:Monster Domosed/common.js: Difference between revisionsGive feedback
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
(function () { | |||
'use strict'; | |||
const CONFIG = { | |||
optionKey: 'gadget-theme', | |||
cookieKey: 'theme', | |||
className: 'theme-light', | |||
toggleId: 'pt-theme-toggle' | |||
}; | |||
// Sun = shown in dark mode (click to switch to light) | |||
// Moon = shown in light mode (click to switch to dark) | |||
const ICONS = { | |||
sun: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" /></svg>', | |||
moon: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" /></svg>' | |||
}; | |||
function Storage() { | |||
function loggedIn() { | |||
return mw.user.isNamed(); | |||
} | |||
// true = light theme, false = dark (default) | |||
function getState() { | |||
return mw.user.options.get(CONFIG.optionKey) == 1; | |||
} | |||
function save(value) { | |||
if (loggedIn()) { | |||
return new mw.Api().saveOption(CONFIG.optionKey, value ? 1 : 0); | |||
} | |||
mw.cookie.set(CONFIG.cookieKey, value ? '1' : '0', { | |||
expires: 365 * 86400, | |||
prefix: '' | |||
}); | |||
return $.Deferred().resolve().promise(); | |||
} | |||
function readCookieFallback(defaultValue) { | |||
if (loggedIn()) return defaultValue; | |||
return mw.cookie.get(CONFIG.cookieKey, '', defaultValue ? '1' : '0') === '1'; | |||
} | |||
return { | |||
loggedIn, | |||
getState, | |||
save, | |||
readCookieFallback | |||
}; | |||
} | |||
function View() { | |||
function iconFor(light) { | |||
return light ? ICONS.moon : ICONS.sun; | |||
} | |||
function labelFor(light) { | |||
return light ? 'Switch to dark theme' : 'Switch to light theme'; | |||
} | |||
function apply(light) { | |||
document.documentElement.classList.toggle(CONFIG.className, light); | |||
const a = document.querySelector('#' + CONFIG.toggleId + ' a'); | |||
if (a) { | |||
a.innerHTML = iconFor(light); | |||
a.setAttribute('aria-label', labelFor(light)); | |||
a.title = labelFor(light); | |||
} | |||
} | |||
function createToggle(onToggle, getState) { | |||
function findTarget() { | |||
return document.querySelector('#p-personal ul'); | |||
} | |||
const ul = findTarget(); | |||
if (!ul) { | |||
setTimeout(function () { | |||
createToggle(onToggle, getState); | |||
}, 300); | |||
return; | |||
} | |||
if (document.getElementById(CONFIG.toggleId)) return; | |||
const light = getState(); | |||
const li = document.createElement('li'); | |||
li.id = CONFIG.toggleId; | |||
const a = document.createElement('a'); | |||
a.href = '#'; | |||
a.innerHTML = iconFor(light); | |||
a.setAttribute('aria-label', labelFor(light)); | |||
a.title = labelFor(light); | |||
a.addEventListener('click', function (e) { | |||
e.preventDefault(); | |||
onToggle(); | |||
}); | |||
li.appendChild(a); | |||
ul.insertBefore(li, ul.firstChild); | |||
} | |||
return { | |||
apply, | |||
createToggle | |||
}; | |||
} | |||
function Controller() { | |||
const store = Storage(); | |||
const view = View(); | |||
let state = store.getState(); | |||
function set(next) { | |||
state = next; | |||
view.apply(state); | |||
store.save(state).fail(function () { | |||
mw.notify('Could not save theme preference.', { | |||
title: 'Theme toggle', | |||
type: 'warn', | |||
tag: 'themeToggle' | |||
}); | |||
}); | |||
} | |||
function toggle() { | |||
set(!state); | |||
} | |||
function init() { | |||
if (!store.loggedIn()) { | |||
state = store.readCookieFallback(state); | |||
} | |||
view.apply(state); | |||
view.createToggle(toggle, function () { | |||
return state; | |||
}); | |||
} | |||
return { | |||
init | |||
}; | |||
} | |||
$(function () { | |||
new Controller().init(); | |||
}); | |||
})(); | |||
/* Patch Formatter */ | /* Patch Formatter */ | ||
( function () { | ( function () { | ||