查看“︁MediaWiki:Gadget-VariantAlly.js”︁的源代码
←
MediaWiki:Gadget-VariantAlly.js
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/**! * _________________________________________________________________________________ * | | * | === WARNING: GLOBAL GADGET FILE === | * | Changes to this page affect many users. | * | Please discuss changes on the talk page, [[WP:VPT]] or GitHub before editing. | * |_________________________________________________________________________________| * * Built from GitHub repository (https://github.com/wikimedia-gadgets/VariantAlly), you should not make * changes directly here. * * See https://github.com/wikimedia-gadgets/VariantAlly/blob/main/CONTRIBUTING.md for build instructions. */ // <nowiki> 'use strict'; // Including: // - w.wiki (preserve short link destination) const BLOCKED_REFERRER_HOST = /^w\.wiki$/i; function isLoggedIn() { return mw.user.isNamed(); } /** * Check whether referrer originates from the same domain. */ function isReferrerSelf() { try { return new URL(document.referrer).hostname === location.hostname; } catch (_a) { // Invalid URL return false; } } function isReferrerBlocked() { try { return BLOCKED_REFERRER_HOST.test(new URL(document.referrer).hostname); } catch (_a) { // Invalid URL return false; } } function isViewingPage() { return mw.config.get('wgAction') === 'view'; } /** * Check whether the current language (set in user preference or by ?uselang=xxx) * is Chinese or not. */ function isLangChinese() { return mw.config.get('wgUserLanguage').startsWith('zh'); } function isWikitextPage() { return mw.config.get('wgCanonicalNamespace') !== 'Special' && mw.config.get('wgPageContentModel') === 'wikitext'; } const LOCAL_VARIANT_KEY = 'va-var'; const OPTOUT_KEY = 'va-optout'; const VALID_VARIANTS = [ 'zh-cn', 'zh-sg', 'zh-my', 'zh-tw', 'zh-hk', 'zh-mo', ]; const VARIANTS = [ 'zh', 'zh-hans', 'zh-hant', ...VALID_VARIANTS, ]; const EXT_VARIANTS = [ 'zh-hans-cn', 'zh-hans-sg', 'zh-hans-my', 'zh-hant-tw', 'zh-hant-hk', 'zh-hant-mo', ...VARIANTS, ]; // Some browsers (e.g. Firefox Android) may return such languages const EXT_MAPPING = { 'zh-hans-cn': 'zh-cn', 'zh-hans-sg': 'zh-sg', 'zh-hans-my': 'zh-my', 'zh-hant-tw': 'zh-tw', 'zh-hant-hk': 'zh-hk', 'zh-hant-mo': 'zh-mo', }; function isVariant(str) { return VARIANTS.includes(str); } function isValidVariant(str) { return VALID_VARIANTS.includes(str); } function isExtVariant(str) { return EXT_VARIANTS.includes(str); } /** * Maps additional lang codes to standard variants. * * @returns standard variant */ function normalizeVariant(extVariant) { var _a; return (_a = EXT_MAPPING[extVariant]) !== null && _a !== void 0 ? _a : extVariant; } /** * Get current variant of the page (don't be misled by config naming). * @returns variant, null for non-wikitext page (but NOT all such pages returns null!) */ function getPageVariant() { const result = mw.config.get('wgUserVariant'); return result !== null && isExtVariant(result) ? normalizeVariant(result) : null; } /** * Get account variant. * @returns account variant, null for anonymous user */ function getAccountVariant() { if (isLoggedIn()) { const result = mw.user.options.get('variant'); return isExtVariant(result) ? normalizeVariant(result) : null; } return null; } function getLocalVariant() { const result = localStorage.getItem(LOCAL_VARIANT_KEY); if (result === null || !isExtVariant(result)) { return null; } return normalizeVariant(result); } /** * Return browser language if it's a Chinese variant. * @returns browser variant */ function getBrowserVariant() { var _a; return (_a = navigator.languages .map((lang) => lang.toLowerCase()) .filter(isExtVariant) .map(normalizeVariant) .find(isVariant)) !== null && _a !== void 0 ? _a : null; } /** * Get the "natural" variant inferred by MediaWiki for anonymous users * when the link doesn't specify a variant. * * Used in link normalization. * * FIXME: Old Safari is known to break this method. * User reported that on an iOS 14 device with Chinese language and Singapore region settings, * Accept-Language is zh-cn (thus inferred by MediaWiki) but this method returns zh-sg. * * @returns variant */ function getMediaWikiVariant() { var _a; return (_a = getAccountVariant()) !== null && _a !== void 0 ? _a : getBrowserVariant(); } /** * Calculate preferred variant from browser variant, local variant and account variant. * * Priority: account variant > browser variant > local variant * * @returns preferred variant */ function calculatePreferredVariant() { return [getAccountVariant(), getBrowserVariant(), getLocalVariant()] .map((variant) => variant !== null && isValidVariant(variant) ? variant : null) .reduce((prev, curr) => prev !== null && prev !== void 0 ? prev : curr); } function setLocalVariant(variant) { localStorage.setItem(LOCAL_VARIANT_KEY, variant); } function setOptOut() { localStorage.setItem(OPTOUT_KEY, ''); } function isOptOuted() { return localStorage.getItem(OPTOUT_KEY) !== null; } const REGEX_WIKI_URL = /^\/(?:wiki|zh(?:-\w+)?)\//i; const REGEX_VARIANT_URL = /^\/zh(?:-\w+)?\//i; const VARIANT_PARAM = 'va-variant'; function isEligibleForRewriting(link) { try { // No rewriting for empty links if (link === '') { return false; } const url = new URL(link, location.origin); // No rewriting if link itself has variant info if (REGEX_VARIANT_URL.test(url.pathname)) { return false; } if (url.searchParams.has('variant')) { return false; } // No rewriting for foreign origin URLs // Note that links like javascript:void(0) are blocked by this if (url.host !== location.host) { return false; } return true; } catch (_a) { return false; } } function rewriteLink(link, variant) { try { const normalizationTargetVariant = getMediaWikiVariant(); const url = new URL(link, location.origin); const pathname = url.pathname; const searchParams = url.searchParams; if (REGEX_WIKI_URL.test(pathname)) { url.pathname = `/${variant}/${url.pathname.replace(REGEX_WIKI_URL, '')}`; searchParams.delete('variant'); // For things like /zh-cn/A?variant=zh-hk } else { searchParams.set('variant', variant); } if (variant === normalizationTargetVariant) { // Normalize the link. // // For example, for link /zh-tw/Title and normalization variant zh-tw, the result is /wiki/Title, // while for the same link and normalization variant zh-cn, the result is /zh-tw/Title (unchanged). url.pathname = url.pathname.replace(REGEX_WIKI_URL, '/wiki/'); url.searchParams.delete('variant'); } const result = url.toString(); return result; } catch (_a) { return link; } } function redirect(preferredVariant, options = {}) { var _a; const origLink = (_a = options.link) !== null && _a !== void 0 ? _a : location.href; const newLink = rewriteLink(origLink, preferredVariant); // Prevent infinite redirects // This could happen occasionally, see getMediaWikiVariant()'s comments if (options.forced || newLink !== location.href) { // Use replace() to prevent navigating back location.replace(newLink); } } function checkThisPage(preferredVariant, pageVariant) { if (pageVariant === preferredVariant) { return; } const redirectionOrigin = mw.config.get('wgRedirectedFrom'); if (redirectionOrigin === null) { redirect(preferredVariant); return; } // If current page is redirected from another page, rewrite link to point to // the original redirect so the "redirected from XXX" hint is correctly displayed // Use URL to reserve other parts of the link const redirectionURL = new URL(location.href); redirectionURL.pathname = `/wiki/${redirectionOrigin}`; redirect(preferredVariant, { link: redirectionURL.toString() }); } function rewriteNavigation(variant) { ['click', 'auxclick', 'dragstart'].forEach((name) => { document.addEventListener(name, (ev) => { const target = ev.target; if (target instanceof Element) { // Do not write <a> with hash only href or no href // which is known to cause breakage in e.g. Visual Editor const anchor = target.closest('a[href]:not([href^="#"])'); if (anchor !== null) { const origLink = anchor.href; if (!isEligibleForRewriting(origLink)) { return; } const newLink = rewriteLink(origLink, variant); if (newLink === origLink) { return; } // Browser support: Safari < 14 // Fail silently when DragEvent is not present if (window.DragEvent && ev instanceof DragEvent && ev.dataTransfer) { // Modify drag data directly because setting href has no effect in drag event ev.dataTransfer.types.forEach((type) => { ev.dataTransfer.setData(type, newLink); }); } else { // Use a mutex to avoid being overwritten by overlapped handler calls if (anchor.dataset.vaMutex === undefined) { anchor.dataset.vaMutex = ''; } anchor.href = newLink; // HACK: workaround popups not working on modified links // Add handler to <a> directly so it was triggered before anything else ['mouseover', 'mouseleave', 'keyup'].forEach((innerName) => { anchor.addEventListener(innerName, (innerEv) => { if (anchor.dataset.vaMutex !== undefined) { anchor.href = origLink; delete anchor.dataset.vaMutex; } }, { once: true }); }); } } } }); }); // Alter <form> submission actions, especially for edit forms // to prevent a later refresh causing loss of the edit buffer document.addEventListener('submit', (ev) => { var _a; const target = ev.target; if (target instanceof HTMLFormElement) { // Use getAttribute & setAttribute to work around https://github.com/wikimedia-gadgets/VariantAlly/issues/14 const submitUrl = target.getAttribute('action'); if (submitUrl && isEligibleForRewriting(submitUrl)) { const method = (_a = target.getAttribute('method')) !== null && _a !== void 0 ? _a : 'get'; if (method === 'get') { // In GET forms, query parameters in action are striped, so add it via a hidden <input> // See https://stackoverflow.com/questions/1116019/when-submitting-a-get-form-the-query-string-is-removed-from-the-action-url // Remove existing variant <input>'s, should only be caused by bfcache due to the special // role of ?variant in MediaWiki target.querySelectorAll('input[name="variant"]').forEach((elem) => elem.remove()); const variantInput = document.createElement('input'); variantInput.type = 'hidden'; variantInput.name = 'variant'; variantInput.value = variant; // TODO: No normalization here, but should not be a big problem target.append(variantInput); } else { target.setAttribute('action', rewriteLink(submitUrl, variant)); } } } }); } function showVariantPrompt() { mw.loader.using('ext.gadget.VariantAllyDialog').then(function(require){return require("ext.gadget.VariantAllyDialog")}); } /** * Set local variant according to URL query parameters. * * e.g. a URL with ?va-variant=zh-cn will set local variant to zh-cn */ function applyURLVariant() { const variant = new URL(location.href).searchParams.get(VARIANT_PARAM); if (variant !== null && isValidVariant(variant)) { setLocalVariant(variant); } } /** * Collect metrics, visible at grafana.wikimedia.org * * @param name metric name * @param action action performed (metric label) */ function stat(name, action) { mw.track(`stats.mediawiki_gadget_VariantAlly_${name}_total`, 1, { action }); } function main() { // Manually opt outed users if (isOptOuted()) { return; } if (isLoggedIn()) { return; } // Non-Chinese pages/users if (!isLangChinese()) { return; } applyURLVariant(); const preferredVariant = calculatePreferredVariant(); if (preferredVariant !== null) { // Optimistically set local variant to be equal to browser variant // In case the user's browser language becomes invalid in the future, // this reduces the possibility to show prompt to disrupt users. setLocalVariant(preferredVariant); } const pageVariant = getPageVariant(); // Non-article page (JS/CSS pages, Special pages etc.) if (pageVariant === null || !isWikitextPage()) { // Such page can't have variant, but preferred variant may be available // So still rewrite links if (preferredVariant !== null) { rewriteNavigation(preferredVariant); } return; } // Preferred variant unavailable if (preferredVariant === null) { if (isViewingPage()) { showVariantPrompt(); return; } return; } if (isReferrerBlocked()) { rewriteNavigation(preferredVariant); return; } // On-site navigation to links ineligible for writing // The eligibility check is require because user may click on a link with variant intentionally // e.g. variant dropdown and {{Variant-cnhktwsg}} if (isReferrerSelf() && !isEligibleForRewriting(location.href)) { rewriteNavigation(preferredVariant); return; } checkThisPage(preferredVariant, pageVariant); rewriteNavigation(preferredVariant); } main(); exports.redirect = redirect; exports.setLocalVariant = setLocalVariant; exports.setOptOut = setOptOut; exports.stat = stat; // </nowiki>
返回
MediaWiki:Gadget-VariantAlly.js
。
导航菜单
个人工具
未登录
讨论
贡献
创建账号
登录
命名空间
系统消息
讨论
English
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息