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: '[[w:User:Andrybak/Scripts/${USERSCRIPT_NAME}|${USERSCRIPT_NAME}]]',
version: '6'
};
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}`;
/*
* MediaWiki has automatic scrolling to (and highlighting of) messages
* with mentions. This hash disappears quickly from document.location,
* so we have to remember it separately from function maybeShowHashTarget().
*/
let mentionHash = null;
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();
}
/*
* Because we are messing with the layout of the page
* on the fly, we need to ensure that the user sees
* the linked section or linked mention on a discussion page.
*/
function maybeShowHashTarget() {
/*
* These aren't regular #Section_heading anchors, but rather special
* tags used by MediaWiki to highlight mentions.
*/
if (mentionHash !== null) {
/*
* MediaWiki adds an empty <span> at the _start_ of a message with the
* corresponding `id`.
* This id also corresponds to the attribute `data-mw-thread-id` stored
* in an empty <span> at the _end_ of the same message after the "Reply"
* button ([[mw:Extension:DiscussionTools]]), right after the signature.
*/
const maybeMentionMessage = document.getElementById(mentionHash.slice(1));
/*
* `null` will be returned in following cases:
* - when the message was removed (e.g. into an archive)
* - when the timestamp in the signature was re-generated (e.g. [[:en:Special:Diff/1222421941]])
*/
if (maybeMentionMessage !== null) {
maybeMentionMessage.scrollIntoView();
return;
}
}
/*
* If a mention wasn't highlighted, try to scroll to a regular
* anchor of a section.
*/
if (document.location.hash === "") {
return;
}
const targetId = document.location.hash.slice(1).replaceAll(' ', '_');
document.getElementById(targetId)?.scrollIntoView();
}
function ensureNeededWidth(checkFn, adjective, verb, controlClass) {
if (checkFn()) {
debug(`Already ${adjective}.`);
return;
}
info(verb);
const control = document.querySelector(controlClass);
control.click();
maybeShowHashTarget();
}
function ensureWide() {
ensureNeededWidth(
isWideVector,
'wide',
'Widening.',
`${WIDE_WIDTH_RADIO_BUTTON_SELECTOR}, ${TOGGLE_BUTTON_SELECTOR}`
);
}
function ensureNarrow() {
ensureNeededWidth(
isNarrowVector,
'narrow',
'Narrowing.',
`${STANDARD_WIDTH_RADIO_BUTTON_SELECTOR}, ${TOGGLE_BUTTON_SELECTOR}`
);
}
/*
* 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);
}
function rememberMentionHash() {
const params = new URLSearchParams(document.location.search);
if (params.get('markasread') !== null) {
mentionHash = document.location.hash;
info('Remembered comment hash:', mentionHash);
}
}
/*
* 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();
}
rememberMentionHash();
if (document.readyState !== 'loading') {
lazyLoadVectron();
} else {
warn('Cannot load yet. Setting up a listener...');
document.addEventListener('DOMContentLoaded', lazyLoadVectron);
}
})();
// </nowiki>
You must be logged in to post a comment.