Jump to content

User:Andrybak/Scripts/Vectron.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Andrybak (talk | contribs) at 14:59, 11 June 2024 (Praise Vectron for this support of the "Appearance" menu in the sidebar!). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
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.
// <nowiki>
(function() {
	'use strict';

	const USERSCRIPT_NAME = 'Vectron';
	const config = {
		wikipage: '[[:en:User:Andrybak/${USERSCRIPT_NAME}|${USERSCRIPT_NAME}]]',
		version: '4'
	};
	const LOG_PREFIX = `[${USERSCRIPT_NAME} v${config.version}]:`;
	const mw = window.mw; // a hack to trick my JS editor into believing that `mw` exists

	// TODO: Not sure if still need to support the toggle button. Keep it for now.
	const TOGGLE_BUTTON_SELECTOR = '#p-dock-bottom button.vector-limited-width-toggle';
	// 
	const STANDARD_WIDTH_RADIO_BUTTON_SELECTOR = '#skin-client-pref-vector-feature-limited-width-value-1';
	const WIDE_WIDTH_RADIO_BUTTON_SELECTOR = '#skin-client-pref-vector-feature-limited-width-value-0';

	const ANY_CONTROL_SELECTOR = `${TOGGLE_BUTTON_SELECTOR}, ${STANDARD_WIDTH_RADIO_BUTTON_SELECTOR}, ${WIDE_WIDTH_RADIO_BUTTON_SELECTOR}`;

	function error(...toLog) {
		console.error(LOG_PREFIX, ...toLog);
	}

	function warn(...toLog) {
		console.warn(LOG_PREFIX, ...toLog);
	}

	function info(...toLog) {
		console.info(LOG_PREFIX, ...toLog);
	}

	function debug(...toLog) {
		console.debug(LOG_PREFIX, ...toLog);
	}

	function getLimitedWidthToggleButton() {
		return document.querySelector(TOGGLE_BUTTON_SELECTOR);
	}

	function isWideVector() {
		return document.querySelector('html').classList.contains('vector-feature-limited-width-clientpref-0');
	}

	function isNarrowVector() {
		return !isWideVector();
	}

	function maybeShowHashTarget() {
		/*
		 * Because we are messing with the layout of the page
		 * on the fly, we need to ensure that the user sees
		 * the linked section.
		 */
		if (document.location.hash === "") {
			return;
		}
		const targetId = document.location.hash.slice(1).replaceAll(' ', '_');
		document.getElementById(targetId)?.scrollIntoView();
	}

	function ensureWide() {
		if (isWideVector()) {
			debug('Already wide.');
			return;
		}
		info('Widening.');
		const control = document.querySelector(`${WIDE_WIDTH_RADIO_BUTTON_SELECTOR}, ${TOGGLE_BUTTON_SELECTOR}`);
		control.click();
		maybeShowHashTarget();
	}

	function ensureNarrow() {
		if (isNarrowVector()) {
			debug('Already narrow.');
			return;
		}
		info('Narrowing.');
		const control = document.querySelector(`${STANDARD_WIDTH_RADIO_BUTTON_SELECTOR}, ${TOGGLE_BUTTON_SELECTOR}`);
		control.click();
		maybeShowHashTarget();
	}

	/*
	 * The main function of the script.
	 */
	function runScript() {
		/*
		 * Reference documentation about keys and values in mw.config:
		 * https://www.mediawiki.org/wiki/Manual:Interface/JavaScript#mw.config
		 */
		if (!mw.config.get('wgIsArticle')) { // This variable is badly named -- it is not related to a page being a main namespace "article".
			info('Not a wiki page.');
			ensureWide();
			return;
		}
		if (mw.config.get('wgDiffNewId') != null || mw.config.get('wgDiffOldId') != null) {
			info('Diff view.');
			ensureWide();
			return;
		}
		const namespaceNumber = mw.config.get('wgNamespaceNumber');
		if (namespaceNumber === -1) {
			info('This is a "Special:" page.');
			ensureWide();
			return;
		}
		const contentModel = mw.config.get("wgPageContentModel");
		// ['javascript', 'css', 'sanitized-css', 'Scribunto'].includes(contentModel)
		if (contentModel !== 'wikitext') {
			info('Content model of the page is for source code (Lua, JS, CSS, etc).');
			ensureWide();
			return;
		}
		info('Assuming wiki page.');
		ensureNarrow();
	}

	function wait(message) {
		info(message);
		setTimeout(lazyLoadVectron, 200);
	}

	/*
	 * Infrastructure to ensure the script can run.
	 */
	function lazyLoadVectron() {
		debug('Loading...');
		const skinId = mw.config.get("skin");
		if (skinId === null) {
			wait('Skin is not loaded yet. Waiting...');
			return;
		}
		if (skinId !== 'vector-2022') {
			warn(`Skin ${skinId} is not supported by the script. Aborting.`);
			return;
		}
		const anyControl = document.querySelector(ANY_CONTROL_SELECTOR);
		if (anyControl === null) {
			wait('The UI controls are not loaded yet. Waiting...');
			return;
		}
		const button = getLimitedWidthToggleButton();
		if (button !== null) {
			const theAttribute = button.getAttribute('data-event-name');
			if (theAttribute === null) {
				wait('Attribute "data-event-name" of the toggle button is not loaded yet. Waiting...');
				return;
			}
		}
		runScript();
	}

	if (document.readyState !== 'loading') {
		lazyLoadVectron();
	} else {
		warn('Cannot load yet. Setting up a listener...');
		document.addEventListener('DOMContentLoaded', lazyLoadVectron);
	}
})();
// </nowiki>