User:Arashiryuu0/global.js

/** * Testing out UCP global JS. * @namespace UCPGlobal */ // jshint browser: true, devel: true, jquery: true // jshint strict: true, freeze: true, eqeqeq: true, futurehostile: true // jshint newcap: true, noarg: true, quotmark: single, shadow: outer // jshint latedef: true, undef: true, unused: true /* global mw, Promise, Symbol, requestIdleCallback */ 'use strict'; window.CodeblockLinesConfig = { ready: false }; jsScope: { if (window.UCP && window.UCP.globalJS) break jsScope; const has = Object.prototype.hasOwnProperty; const slice = Array.prototype.slice; const toString = Object.prototype.toString; const pages = ['js', 'css', 'json', 'javascript']; const levels = ['log', 'info', 'warn', 'debug', 'error']; const extension = window.location.pathname.split('.').pop; const Logger = Object.create(null); const Utils = Object.create(null); Object.defineProperty(Logger, Symbol.toStringTag, { value: 'Logger' }); Object.defineProperty(Utils, Symbol.toStringTag, { value: 'Tools' }); const applyBinds = function (n) { const fns = Object.getOwnPropertyNames(n).filter(function (method) {			return typeof n[method] === 'function';		}); fns.forEach(function (f) {			n[f] = n[f].bind(n);		}); };	loggerScope: { const getParts = function (name) { return [ '%c[' + name + ']%c \u2014 %s', 'color: #C3E88D;', '',				new Date.toUTCString ];		};		const getLevel = function (level) { return levels.includes(level) ? level : 'log'; };		const _log = function (props) { if (toString.call(props) !== '[object Object]') return null; const name = 'Logger|' + getLevel(props.type); return function { console.groupCollapsed.apply(null, getParts(name)); console[props.type].apply(null, arguments); console.groupEnd; };		};		levels.forEach(function (level) {			Logger[level] = _log({ type: level });		}); applyBinds(Logger); Object.freeze(Logger); }	const useRef = function (v) { return { current: v }; };	const preloads = useRef(2); const isNil = function (n) { return n === undefined || n === null; };	const create = function (type, props) { if (typeof type !== 'string') return null; const e = document.createElement(type); if (!isNil(props) && toString.call(props) === '[object Object]') { Object.assign(e, props); if (props.style) Object.assign(e.style, props.style); if (has.call(props, 'children') && !Array.isArray(props.children)) props.children = [props.children]; e.append.apply(e, props.children); }		return e;	}; const queryTree = function (tree, query, options) { if (isNil(options)) options = {}; options.walkable = isNil(options.walkable) ? Object.keys(tree) : options.walkable; options.ignore = isNil(options.ignore) ? [] : options.ignore; if (typeof query === 'string') { if (has.call(tree, query)) return tree[query]; } else if (query(tree)) { return tree; }		if (isNil(tree)) return null; var ret = null, len, i; if (Array.isArray(tree)) { for (i = 0, len = tree.length; i < len; i++) { const value = tree[i]; ret = queryTree(value, query, options); if (!isNil(ret)) return ret; }		} else { for (i = 0, len = options.walkable.length; i < len; i++) { const key = options.walkable[i]; if (!has.call(tree, key) || options.ignore.includes(key)) continue; ret = queryTree(tree[key], query, options); if (!isNil(ret)) return ret; }		}		return ret; };	const getFromHook = function (hookName) { if (typeof hookName !== 'string') return Promise.reject('Invalid hook name, hook names must be strings.'); return new Promise(function (resolve) {			mw.hook(hookName).add(resolve);		}); };	const getHookValues = function { const args = slice.call(arguments); const mapHooks = function (hookName) { return getFromHook(hookName); };		if (!args.length) return []; return args.map(mapHooks); };	const run = function { const myHook = mw.hook('window.ready'); hlScope: { if (window.hljs) break hlScope; [				'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.2.0/styles/atom-one-dark.min.css', 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.2.0/highlight.min.js' ].forEach(function (url, index) {				const isCss = index === 0;				const type = isCss ? 'text' : 'script';				$.get(url, void 0, $.noop, type).then(function { if (isCss) { const link = create('link', {							href: url,							rel: 'stylesheet'						}); document.head.appendChild(link); } else { mw.hook('ext.hljs').fire(window.hljs); }					--preloads.current; }, Logger.error);			}); }		/**		 * Change source editor theme. */		aceScope: { const isEditPage = window.location.search === '?action=edit'; if (!isEditPage || !pages.includes(extension)) break aceScope; mw.hook('codeEditor.configure').add(function {				const editor = window.ace.edit(document.querySelector('.editor.ace_editor'));				requestAnimationFrame(function  { editor.setTheme('ace/theme/tomorrow_night'); });			});		}		/**		 * Codeblock theme buttons */		tbScope: { if (!pages.includes(extension)) break tbScope; const base = 'https://dev.fandom.com/wiki/MediaWiki:Highlight-js/styles/'; const themes = [ 'atom-one-dark', 'tomorrow-night', 'solarized-dark', 'monokai-sublime', 'dracula', 'vs2015', 'nord' ];			const buttons = []; const container = create('div'); container.setAttribute('id', 'code-button-container'); container.setAttribute('style', 'display: block; padding: 5px 0 10px 0; text-align: center;'); const handleLinks = function (links, activeTheme) { const found = links.find(function (link) {					return link.getAttribute('href').includes(activeTheme);				}); links.forEach(function (link) {					if (link.getAttribute('disabled') !== null) return;					link.setAttribute('disabled', '');				}); if (!found) { const fresh = create('link', {						href: base + activeTheme + '.css?action=raw&ctype=text/css',						rel: 'stylesheet'					}); document.head.appendChild(fresh); return; }				found.removeAttribute('disabled'); };			const setTheme = function (theme) { const links = slice.call(document.querySelectorAll('link[href*="' + base + '"]')); requestAnimationFrame(function {					handleLinks(links, theme);				}); };			const buttonClick = function (button) { const theme = button.getAttribute('data-theme'); return function { if (!theme) return; setTheme(theme); };			};			const addButtons = function { if (buttons.length || document.contains(container)) return; const target = document.getElementById('mw-clearyourcache'); if (!target) return; themes.forEach(function (theme, idx) {					if (idx === 4) {						const n = create('hr', { style: { visibility: 'hidden', margin: '0' }						});						buttons.push(n);					}					const btn = create('div', { className: 'wds-button', textContent: theme });					btn.setAttribute('data-theme', theme);					btn.setAttribute('style', 'margin-right: 2px;');					btn.addEventListener('click', buttonClick(btn));					buttons.push(btn);				}); container.append.apply(container, buttons); target.appendChild(container); };			mw.hook('wikipage.content').add(addButtons); }		const ready = function (modules) { if (preloads.current > 0) return setTimeout(ready, 1000, modules); const toasts = modules[1]; const lines = modules[2]; Object.assign(Utils, {				'$': $,				'mw': mw,				'pull': window.importArticles,				'lines': lines,				'logger': Logger,				'toasts': toasts,				'queryTree': queryTree			}); applyBinds(Utils); Object.freeze(Utils); myHook.fire(Utils); };		myHook.add(function (utils) {			const highlightTheme = document.head.querySelector('link[href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.2.0/styles/atom-one-dark.min.css"]');			const href = highlightTheme && highlightTheme.getAttribute('href');			// if (utils.lines) utils.lines.process;			if (utils.logger) utils.logger.log('Tools:', utils);			if (href) {				requestAnimationFrame(function { const hrefN = href.replace(/atom-one-(light|dark)/, 'vs2015'); highlightTheme.setAttribute('href', hrefN); });			}			window.UCP.tools = utils;		}); const all = function (promises, callback) { return Promise.all(promises).then(callback, Logger.error); };		const useHljs = function (deps) { const hljs = deps[0]; const lines = deps[2]; if (!hljs || !lines) return; const paint = function (element) { requestAnimationFrame(function {					hljs.highlightBlock(element);					requestAnimationFrame(function  { if (pages.includes(extension)) { element.classList.add(hljs.getLanguage(extension).name.toLowerCase); }						requestAnimationFrame(function {							lines.process;						}); });				});			};			document.querySelectorAll('.mw-highlight pre').forEach(paint); };		all(getHookValues('ext.hljs', 'dev.toasts', 'dev.CodeblockLineNumbers'), function (deps) {			ready(deps);			useHljs(deps);		}); };	mw.hook('dev.preact').add(function (Preact) {		const h = Preact.h;		const render = Preact.render;		const useMemo = Preact.useMemo; // jshint ignore: line		const useState = Preact.useState;		const useEffect = Preact.useEffect;		const useReducer = Preact.useReducer; // jshint ignore: line		const useCallback = Preact.useCallback;		const useLayoutEffect = Preact.useLayoutEffect;		const useAnimationFrame = function (callback) {			const fn = useRef(callback);			const frame = useRef;			const animate = useCallback(function (now) { fn.current(now); frame.current = requestAnimationFrame(animate); }, []);			useLayoutEffect(function { frame.current = requestAnimationFrame(animate); return function { if (frame.current) cancelAnimationFrame(frame.current); };			}, []);		};		const useInterval = function (callback, delay) { // jshint ignore: line			const ref = useRef(callback);			const tick = useCallback(function { ref.current; }, []);			useLayoutEffect(function { ref.current = callback; }, [callback]);			useEffect(function { const id = setInterval(tick, delay); return function { clearInterval(id); };			}, [delay]);		};		const getClockState = function {			const date = new Date;			const lang = mw.user.options.get('language') || 'en-gb';			return {				day: date.toLocaleDateString(lang, { weekday: 'long' }),				time: date.toLocaleTimeString(lang, { hour12: false })			};		};		const Clock = function  {			const _d = useState(function  { return getClockState; });			const hovered = useState(false);			const update = useCallback(function { _d.set(getClockState); }, []);			useAnimationFrame(update);			return h('span', { className: 'clock', children: [ h('span', {						key: 'ClockDay',						className: 'clock-day',						children: _d.value.day					}), h('span', {						key: 'ClockSeparator',						className: 'clock-separator',						children: String.fromCodePoint(160)					}), h('span', {						key: 'ClockTime',						className: 'clock-time',						children: _d.value.time					}) ],				onMouseEnter: function (e) { if (hovered.value) return; e.target.classList.add('hovered'); hovered.set(true); },				onMouseLeave: function (e) { if (!hovered.value) return; e.target.classList.remove('hovered'); hovered.set(false); },				onClick: function { location.href = location.href; }			});		};		const addClock = function {			if (document.getElementById('DisplayClock')) return;			const timeRoot = create('div', { id: 'DisplayClock' });			const target = document.querySelector('.fandom-community-header__top-container + .fandom-community-header__local-navigation');			target.appendChild(timeRoot);			render(h(Clock), timeRoot);		};		addClock;	}); window.UCP = window.UCP || {}; window.UCP.globalJS = { version: '1.0.0' };	window.importArticles.apply(null, [		{			type: 'script',			articles: [				'u:dev:MediaWiki:Toasts.js',				'u:dev:MediaWiki:Preact.js',				'u:dev:MediaWiki:View_Source/code.js',				'u:dev:MediaWiki:CodeblockLineNumbers/code.js'			]		},		{			type: 'style',			articles: [				'u:dev:MediaWiki:CodeblockLineNumbers.css'			]		}	]); requestIdleCallback(run); } /*@end@*/