Switch to Mobile Wikipedia/Wiktionary and Back, Autoload Mobile Page

Automatically loads Mobile Wikipedia if you visit the desktop version of Wikipedia from a different site; provides a shortcut to switch between the two and stays on the version you switched to.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Switch to Mobile Wikipedia/Wiktionary and Back, Autoload Mobile Page
// @namespace    http://tampermonkey.net/
// @version      0.11
// @description  Automatically loads Mobile Wikipedia if you visit the desktop version of Wikipedia from a different site; provides a shortcut to switch between the two and stays on the version you switched to.
// @author       https://greasyfork.org/en/users/728793-keyboard-shortcuts
// @icon         https://en.wikipedia.org/favicon.ico
// @match        https://*.wikipedia.org/*
// @match        https://*.wiktionary.org/*
// @match        https://*.wikimedia.org/*
// @match        https://*.wikiquote.org/*
// @match        https://*.wikibooks.org/*
// @license      MIT
// ==/UserScript==

/* jshint esversion: 6 */

// CONFIGURE THE SCRIPT HERE (set any of these to true or false, no other value):
const AUTOLOAD_MOBILE = true; // if set to true, loads the mobile page automatically when landing on a Wikimedia website.
const ENABLE_MOBILE_DESKTOP_SHORTCUT = true; // if set to true, lets you switch between mobile and non-mobile with ctrl-m on Windows or alt-m on Mac.
const ENABLE_EDIT_SHORTCUT = true; // if set to true, lets you edit an article with ctrl-e on Windows or alt-e on Mac.
const VIEW_HISTORY_IN_DESKTOP_MODE = true; // if set to true, view a wiki page's edit history in desktop mode. This is set to true by default since the history view on mobile is severely limited.
const LOG_DEBUG_MESSAGES = false; // if set to true, lets the script log debug information as it runs.
const REQUIRE_MODIFIER_FOR_SHORTCUTS = true;
// (END OF CONFIGURATION)

const WEBSITES = ['wikipedia', 'wiktionary', 'wikimedia', 'wikiquote', 'wikibooks'].join('|'); // in order to reuse this list underneath we have to use the RegExp constructor instead of the literal syntax.
const FULL_URL_REGEX = new RegExp('^(?<prefix>https?://[^/]*)(?<suffix>\\.(' + WEBSITES + ')\\.org/.*)');
const DOMAIN_REGEX = new RegExp('^(?<prefix>[^/]*)(?<suffix>\\.(' + WEBSITES + ')\\.org)');
const LANGUAGE_REGEX = new RegExp('^(https?://)(?<lang>[a-z]+)(\\.(' + WEBSITES + ')\\.org/.*)');
const DISABLED_ON_DOMAINS_REGEX = /^((cxserver|donate|dyna|foundation|lists|login|maps|outreach|phab|stats|toolsadmin|upload|wikitech|www)\.wikimedia.org)$/;

const EDIT_SUFFIX = 'action=edit';

function isMobile(match) {
    return match.groups.prefix.endsWith('.m');
}

function changeDomainToMobile(match) {
    return match.groups.prefix + '.m' + match.groups.suffix;
}

function changeDomainToDesktop(match) {
    return match.groups.prefix.substr(0, match.groups.prefix.length - 2) + match.groups.suffix;
}

function loadMobilePage(originalUrl, match) {
    const mobileUrl = new URL(changeDomainToMobile(match));
    location.href = mobileUrl.protocol + '//' + mobileUrl.host + mobileUrl.pathname + (originalUrl.search || '');
}

function switchToMobileOrBack(match) {
    const url = new URL(location.href);
    const altDomain = changeDomainToMobileOrBack(url);
    location.href = url.protocol + '//' + altDomain + url.pathname + (url.search || '');
}

function debugLog() {
    if (LOG_DEBUG_MESSAGES) {
        console.log.apply(null, arguments);
    }
}

function changeDomainToMobileOrBack(url) {
    const domain = url.hostname;
    const match = DOMAIN_REGEX.exec(domain);
    if (!match) {
        debugLog('Failed to convert domain:', domain);
        return domain;
    } else if (isMobile(match)) {
        return changeDomainToDesktop(match);
    } else {
        return changeDomainToMobile(match);
    }
}

function currentlyEditing() {
    const url = new URL(location.href);
    return (url.search.indexOf(EDIT_SUFFIX) !== -1 || url.hash.indexOf('#/editor/') != -1);
}

function switchToEditMode(match) {
    if (!currentlyEditing()) {
        const url = new URL(location.href);
        if (isMobile(match)) { // mobile: switch back to non-mobile page and add edit suffix
            location.href = url.protocol + '//' + changeDomainToMobileOrBack(url) + url.pathname + '?' + EDIT_SUFFIX;
        } else {
            location.href = url.protocol + '//' + url.host + url.pathname + '?' + EDIT_SUFFIX;
        }
    }
}

/**
 * Returns whether this is a history view of a page's changes, on a mobile Wiki.
 */
function isMobileSpecialHistoryPage(currentWiki) {
    return isMobile(currentWiki) && (location.href.indexOf('/Special:History/') !== -1);
}

/**
 * For a Special:History page, return the name of the Wiki page being examined.
 */
function extractPageNameFromSpecialHistoryPage(pathname) {
    const regex = /\/wiki\/Special:History\/(?<pagename>[^\/]+)\/?.*$/;
    const match = regex.exec(pathname);
    return match ? match.groups.pagename : null;
}

/**
 * An additional regex lets us disable the auto-switch behavior for some domains, like upload.wikimedia.org which doesn't have a .m version.
 */
function isMobileDisabledForThisDomain() {
    const url = new URL(location.href);
    const match = DISABLED_ON_DOMAINS_REGEX.exec(url.hostname);
    debugLog(`isMobileDisabledForThisDomain(${url.hostname}) -> ${!!match}`);
    return !!match;
}

(function() {
    'use strict';

    const url = new URL(location.href);
    const previousHref = document.referrer || '';
    const referrerWiki = FULL_URL_REGEX.exec(previousHref); // match object for the referrer
    const currentWiki = FULL_URL_REGEX.exec(location.href); // match object for the current address
    const disabledForDomain = isMobileDisabledForThisDomain(); // make sure we don't have an exclusion rule for this domain


    if (VIEW_HISTORY_IN_DESKTOP_MODE && isMobileSpecialHistoryPage(currentWiki)) { // extract domain and page, and redirect to full equivalent desktop page
        const nonMobileDomain = changeDomainToMobileOrBack(url);
        const pageName = extractPageNameFromSpecialHistoryPage(url.pathname);
        if (nonMobileDomain && pageName) {
            debugLog(`VIEW_HISTORY_IN_DESKTOP_MODE enabled, going to ${nonMobileDomain} for ${pageName} history`);
            const newUrl = `https://${nonMobileDomain}/w/index.php?title=${pageName}&action=history`;
            location.href = newUrl;
            return;
        }
    }

    if (AUTOLOAD_MOBILE) {
        const willSwitch = (currentWiki && !isMobile(currentWiki) && !disabledForDomain);
        if (!referrerWiki) { // referrer is *not* Wikimedia: make sure we hit the mobile website first
            if (willSwitch) { // First visit: switch to mobile by default
                loadMobilePage(url, currentWiki);
            }
        } else { // referrer is a Wikimedia site; check if it's a different language and switch to mobile if so
            const curLangMatch = LANGUAGE_REGEX.exec(location.href);
            const prevLangMatch = LANGUAGE_REGEX.exec(previousHref);
            if (curLangMatch && prevLangMatch && curLangMatch.groups.lang !== prevLangMatch.groups.lang) {
                debugLog(`Referrer is a Wikimedia site, but language went from ${ prevLangMatch.groups.lang } to ${ curLangMatch.groups.lang }. Will switch: ${ (willSwitch ? 'YES' : 'NO') }`);
                if (willSwitch) { // Language change: switch to mobile as if we came from a third-party website
                    loadMobilePage(url, currentWiki);
                }
            }
        }
    }

    /**
     * Validates that the event has either Alt or Ctrl set (but not both), but only if REQUIRE_MODIFIER_FOR_SHORTCUTS is set to true.
     * If it's false, validates that neither are set.
     */
    function hasModifierIfRequired(e) {
        if (REQUIRE_MODIFIER_FOR_SHORTCUTS) {
            return ((e.altKey || e.ctrlKey) && (e.altKey ^ e.ctrlKey)); // either, but not both.
        } else {
            return !(e.altKey || e.ctrlKey);
        }
    }

    function fieldAllowsInput(e) {
        const field = e.target;
        return (field.getAttribute("contenteditable") == "true") ||
               (field.tagName !== undefined && (field.tagName === 'TEXTAREA' || field.tagName === 'INPUT'));
    }

    function handleEvent(e) {
        if (!currentWiki) { // not on a Wikimedia website
            return;
        }
        if(currentlyEditing() || fieldAllowsInput(e)) { // not for edit modes, and not if the field is a text input
            return;
        }
        if (ENABLE_MOBILE_DESKTOP_SHORTCUT && hasModifierIfRequired(e) && e.code === 'KeyM') { // (ctrl-m or alt-m with modifiers, just "m" otherwise)
            switchToMobileOrBack(currentWiki);
        } else if (ENABLE_EDIT_SHORTCUT && hasModifierIfRequired(e) && e.code === 'KeyE') { // (ctrl-e or alt-e with modifiers, just "e" otherwise)
            debugLog('switching to edit mode');
            switchToEditMode(currentWiki);
        }
    }

    if (ENABLE_MOBILE_DESKTOP_SHORTCUT || ENABLE_EDIT_SHORTCUT) {
        addEventListener("keydown", handleEvent); // use keydown to catch shortcuts using modifier keys like ctrl or alt
    }

})();