跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
中医百科
搜索
搜索
登录
个人工具
登录
深色模式
查看“MediaWiki:Gadget-DisamAssist.js”的源代码
系统消息
讨论
English
阅读
查看源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
查看源代码
查看历史
清除缓存
常规
链入页面
相关更改
特殊页面
页面信息
页面值
←
MediaWiki:Gadget-DisamAssist.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您必须确认您的电子邮件地址才能编辑页面。请通过
参数设置
设置并确认您的电子邮件地址。
您可以查看和复制此页面的源代码。
/** * SPDX-License-Identifier: CC-BY-SA-4.0 * _addText: '{{Gadget Header|license=CC-BY-SA-4.0}}' * * @base {@link https://zh.wikipedia.org/wiki/User:Peacearth/DisamAssist.js} * @base {@link https://es.wikipedia.org/wiki/Usuario:Qwertyytrewqqwerty/DisamAssist.js} * @base {@link https://es.wikipedia.org/wiki/Usuario:Qwertyytrewqqwerty/DisamAssist.css} * @source {@link https://git.qiuwen.net.cn/InterfaceAdmin/QiuwenGadgets/src/branch/master/src/DisamAssist} * @license CC-BY-SA-4.0 {@link https://www.qiuwenbaike.cn/wiki/H:CC-BY-SA-4.0} */ /** * +------------------------------------------------------------+ * | === WARNING: GLOBAL GADGET FILE === | * +------------------------------------------------------------+ * | All changes should be made in the repository, | * | otherwise they will be lost. | * +------------------------------------------------------------+ * | Changes to this page may affect many users. | * | Please discuss changes by opening an issue before editing. | * +------------------------------------------------------------+ */ /* <nowiki> */ (() => { "use strict"; // dist/DisamAssist/DisamAssist.js function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var n = 0, F = function() { }; return { s: F, n: function() { return n >= r.length ? { done: true } : { done: false, value: r[n++] }; }, e: function(r2) { throw r2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = true, u = false; return { s: function() { t = t.call(r); }, n: function() { var r2 = t.next(); return a = r2.done, r2; }, e: function(r2) { u = true, o = r2; }, f: function() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } //! src/DisamAssist/modules/api.ts var import_ext_gadget = require("ext.gadget.Util"); var api = (0, import_ext_gadget.initMwApi)("DisamAssist/1.1"); //! src/DisamAssist/modules/config.ts var cfg = { /* Categories where disambiguation pages are added (usually by a template like {{Disambiguation}} */ disamCategories: ["全部消歧义页面"], /* "Canonical names" of the templates that may appear after ambiguous links and which should be removed when fixing those links */ disamLinkTemplates: ["Disambiguation needed", "Ambiguous link", "Amblink", "Dab needed", "Disamb-link", "Disambig needed", "Disambiguate", "Dn", "Needdab"], /* "Canonical names" of the templates that designate intentional links to disambiguation pages */ disamLinkIgnoreTemplates: ["R from ambiguous page", "R to disambiguation page", "R from incomplete disambiguation"], /* Format string for "Foo (disambiguation)"-style pages */ disamFormat: "$1(消歧义)", /* Regular expression matching the titles of disambiguation pages (when they are different from the titles of the primary topics) */ disamRegExp: "^(.*)((消歧义|消歧義))$", /* Text that will be inserted after the link if the user requests help. If the value is null, the option to request help won't be offered */ disamNeededText: "{{dn|date={{".concat("subst:", "CURRENTMONTHNAME", "}} {{", "subst:", "CURRENTYEAR}}}}"), /* Content of the "Foo (disambiguation)" pages that will be created automatically when using DisamAssist from a "Foo" page */ redirectToDisam: "#重定向 [[$1]]".concat("{{R to disambiguation page}}"), /* Whether intentional links to disambiguation pages can be explicitly marked by adding " (disambiguation)" */ intentionalLinkOption: false, /* Namespaces that will be searched for incoming links to the disambiguation page (pages in other namespaces will be ignored) */ targetNamespaces: [6, 10, 14, 118, 0], /* Number of backlinks that will be downloaded at once When using blredirect, the maximum limit is supposedly halved (see http://www.mediawiki.org/wiki/API:Backlinks) */ backlinkLimit: 250, /* Number of titles we can query for at once */ queryTitleLimit: 50, /* Number of characters before and after the incoming link that will be displayed */ radius: 300, /* Height of the context box, in lines */ numContextLines: 4, /* Number of pages that will be stored before saving, so that changes to them can be undone if need be */ historySize: 2, /* Minimum time in seconds since the last change was saved before a new edit can be made. A negative value or 0 disables the cooldown. Users with the "bot" right won't be affected by the cooldown */ editCooldown: 0, /* Specify how the watchlist is affected by DisamAssist edits. Possible values: "watch", "unwatch", "preferences", "nochange" */ watch: "nochange" }; //! src/DisamAssist/modules/messages.js var messages = { start: "为链接消歧义", startMain: "为链至主条目的链接消歧义", startSame: "为链至消歧义页的链接消歧义", close: "关闭", undo: "复原", omit: "跳过", refresh: "重新整理", titleAsText: "其它目标", disamNeeded: "标示{{dn}}", intentionalLink: "有意链到消歧义页的链接", titleAsTextPrompt: "请输入新的链接目标:", removeLink: "去除链接", optionMarker: " [链接到这里]", targetOptionMarker: " [当前目标]", redirectOptionMarker: " [当前目标(重定向)]", pageTitleLine: '<a href="$1">$2</a>:', noMoreLinks: "没有需要消歧义的链接了。", pendingEditCounter: "已保存$1个,已编辑$2个", pendingEditBox: "DisamAssist正在储存您的编辑($1)。", pendingEditBoxTimeEstimation: "$1;剩余时间:$2", pendingEditBoxLimited: "在所有更改保存前,请不要关闭页面;你可以在另一个页面编辑求闻百科,但是请勿同时使用多个DisamAssist。", error: "错误:$1", fetchRedirectsError: '获取重定向失败:"$1".', getBacklinksError: '下载反向链接失败:"$1".', fetchRightsError: '获取用户权限失败:"$1",', loadPageError: '加载$1失败:"$2".', savePageError: '保存至$1失败:"$2".', dismissError: "Dismiss", pending: "DisamAssist尚有未储存的编辑。如欲储存之,请按“关闭”。", editInProgress: "DisamAssist正在进行编辑。若您将本分页关闭,可能会丧失您的编辑。", ellipsis: "……", notifyCharacter: "✔", summary: "使用[[MediaWiki:Gadget-DisamAssist.js|DisamAssist]]清理[[QW:DAB|消歧义]]链接:[[$1]]($2)。", summaryChanged: "改链接至[[$1]]", summaryOmitted: "链接已跳过", summaryRemoved: "链接已移除", summaryIntentional: "刻意链接至消歧义页面", summaryHelpNeeded: "需要帮助", summarySeparator: "; ", redirectSummary: "使用[[MediaWiki:Gadget-DisamAssist.js|DisamAssist]]创建目标为[[$1]]的重定向。" }; //! src/DisamAssist/modules/core.js var startLink; var ui; var links; var pageChanges; var currentPageTitle; var currentPageParameters; var currentLink; var possibleBacklinkDestinations; var forceSamePage = false; var running = false; var choosing = false; var canMarkIntentionalLinks = false; var displayedPages = {}; var editCount = 0; var editLimit; var pendingSaves = []; var pendingEditBox; var pendingEditBoxText; var lastEditMillis = 0; var runningSaves = false; var install = () => { const { wgAction } = mw.config.get(); if (wgAction !== "view" || !isDisam()) { return; } $(() => { const portletId = document.querySelector("#p-cactions") ? "p-cactions" : "p-tb"; if (new RegExp(cfg.disamRegExp).test(getTitle())) { const startMainLink = $(mw.util.addPortletLink(portletId, "#", messages.startMain, "ca-disamassist-main")).on("click", startMain); const startSameLink = $(mw.util.addPortletLink(portletId, "#", messages.startSame, "ca-disamassist-same")).on("click", startSame); startLink = startMainLink.add(startSameLink); } else { startLink = $(mw.util.addPortletLink(portletId, "#", messages.start, "ca-disamassist-page")).on("click", start); } }); }; var start = () => { if (running) { return; } running = true; links = []; pageChanges = []; displayedPages = {}; ensureDABExists().then((canMark) => { canMarkIntentionalLinks = canMark; createUI(); addUnloadConfirm(); markDisamOptions(); checkEditLimit().then(() => { togglePendingEditBox(false); doPage(); }); }); }; var startSame = () => { forceSamePage = true; start(); }; var startMain = () => { forceSamePage = false; start(); }; var createUI = () => { const $body = $("body"); ui = { display: $("<div>").addClass("disamassist-box disamassist-mainbox"), finishedMessage: $("<div>").text(messages.noMoreLinks).hide(), pageTitleLine: $("<span>").addClass("disamassist-pagetitleline"), pendingEditCounter: $("<div>").addClass("disamassist-editcounter"), context: $("<span>").addClass("disamassist-context"), undoButton: createButton(messages.undo, undo), omitButton: createButton(messages.omit, omit), endButton: createButton(messages.close, saveAndEnd), refreshButton: createButton(messages.refresh, refresh), titleAsTextButton: createButton(messages.titleAsText, chooseTitleFromPrompt), intentionalLinkButton: canMarkIntentionalLinks ? createButton(messages.intentionalLink, chooseIntentionalLink) : $("<span>"), disamNeededButton: cfg.disamNeededText ? createButton(messages.disamNeeded, chooseDisamNeeded) : $("<span>"), removeLinkButton: createButton(messages.removeLink, chooseLinkRemoval) }; const top = $("<div>").addClass("disamassist-top").append([ui.pendingEditCounter, ui.finishedMessage, ui.pageTitleLine]); const leftButtons = $("<div>").addClass("disamassist-leftbuttons").append([ui.titleAsTextButton, ui.removeLinkButton, ui.intentionalLinkButton, ui.disamNeededButton, ui.omitButton]); const rightButtons = $("<div>").addClass("disamassist-rightbuttons").append([ui.undoButton, ui.refreshButton, ui.endButton]); const allButtons = $("<div>").addClass("disamassist-allbuttons").append([leftButtons, rightButtons]); ui.display.append([top, ui.context, allButtons]); updateEditCounter(); toggleActionButtons(false); $body.find("#mw-content-text").before(ui.display); ui.display.hide().fadeIn(); }; var addUnloadConfirm = () => { $(window).on("beforeunload", () => { if (running && checkActualChanges()) { return messages.pending; } else if (editCount !== 0) { return messages.editInProgress; } }); }; var markDisamOptions = () => { const optionPageTitles = []; const optionMarkers = []; getDisamOptions().each((_index, element) => { const link = $(element); const title = extractPageName(link); const optionMarker = $("<a>").attr("href", "#").addClass("disamassist-optionmarker").text(messages.optionMarker).on("click", (ev) => { ev.preventDefault(); chooseReplacement(title); }); link.after(optionMarker); optionMarkers[optionMarkers.length] = optionMarker; optionPageTitles[optionPageTitles.length] = title; }); const targetPage = getTargetPage(); fetchRedirects([...optionPageTitles, ...targetPage]).done((redirects) => { const endTargetPage = resolveRedirect(targetPage, redirects); var _iterator = _createForOfIteratorHelper(optionPageTitles.entries()), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done; ) { const [ii, optionPageTitle] = _step.value; const endOptionTitle = resolveRedirect(optionPageTitle, redirects); if (isSamePage(optionPageTitle, targetPage)) { optionMarkers[ii].text(messages.targetOptionMarker).addClass("disamassist-curroptionmarker"); } else if (isSamePage(endOptionTitle, endTargetPage)) { optionMarkers[ii].text(messages.redirectOptionMarker).addClass("disamassist-curroptionmarker"); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } }).fail(error); }; var ensureDABExists = () => { const deferred = new $.Deferred(); const title = getTitle(); if (!cfg.intentionalLinkOption) { deferred.resolve(false); } else if (new RegExp(cfg.disamRegExp).exec(title)) { deferred.resolve(true); } else { const disamTitle = cfg.disamFormat.replace("$1", title); loadPage(disamTitle).done((page) => { if (page.missing) { page.content = cfg.redirectToDisam.replace("$1", title); const summary = messages.redirectSummary.replace("$1", title); savePage(disamTitle, page, summary, false, true).done(() => { deferred.resolve(true); }).fail((description) => { error(description); deferred.resolve(false); }); } else { deferred.resolve(true); } }).fail((description) => { error(description); deferred.resolve(false); }); } return deferred.promise(); }; var checkEditLimit = () => { const deferred = new $.Deferred(); if (cfg.editCooldown <= 0) { editLimit = false; deferred.resolve(); } else { fetchRights().done((rights) => { editLimit = !rights.includes("bot"); }).fail((description) => { error(description); editLimit = true; }).always(() => { deferred.resolve(); }); } return deferred.promise(); }; var doPage = () => { if (pageChanges.length > cfg.historySize) { applyChange(pageChanges.shift()); } if (links.length) { currentPageTitle = links.shift(); displayedPages[currentPageTitle] = true; toggleActionButtons(false); loadPage(currentPageTitle).done((data) => { currentPageParameters = data; currentLink = void 0; doLink(); }).fail(error); } else { const targetPage = getTargetPage(); getBacklinks(targetPage).done((backlinks, pageTitles) => { const pending = {}; for (var _i = 0, _pendingSaves = pendingSaves; _i < _pendingSaves.length; _i++) { const el = _pendingSaves[_i]; pending[el[0]] = true; } possibleBacklinkDestinations = pageTitles.filter((t) => { if (t === targetPage) { return true; } return removeDisam(t) !== targetPage; }); links = backlinks.filter((el) => { return !displayedPages[el] && !pending[el]; }); if (links.length) { doPage(); } else { updateContext(); } }).fail(error); } }; var doLink = () => { currentLink = extractLinkToPage(currentPageParameters.content, possibleBacklinkDestinations, currentLink ? currentLink.end : 0); if (currentLink) { updateContext(); } else { doPage(); } }; var chooseReplacement = (pageTitle, extra, summary) => { if (choosing) { choosing = false; summary || (summary = pageTitle ? messages.summaryChanged.replace("$1", pageTitle) : messages.summaryOmitted); addChange(currentPageTitle, currentPageParameters, currentPageParameters.content, currentLink, summary); if (pageTitle && (pageTitle !== getTargetPage() || extra)) { currentPageParameters.content = replaceLink(currentPageParameters.content, pageTitle, currentLink, extra || ""); } doLink(); } }; var chooseIntentionalLink = () => { const disamTitle = cfg.disamFormat.replace("$1", getTargetPage()); chooseReplacement(disamTitle, "", messages.summaryIntentional); }; var chooseTitleFromPrompt = () => { const title = prompt(messages.titleAsTextPrompt); if (title !== null) { chooseReplacement(title); } }; var chooseLinkRemoval = () => { if (choosing) { const summary = messages.summaryRemoved; addChange(currentPageTitle, currentPageParameters, currentPageParameters.content, currentLink, summary); currentPageParameters.content = removeLink(currentPageParameters.content, currentLink); doLink(); } }; var chooseDisamNeeded = () => { chooseReplacement(currentLink.title, cfg.disamNeededText, messages.summaryHelpNeeded); }; var undo = () => { if (pageChanges.length) { const lastPage = pageChanges.at(-1); if (currentPageTitle !== lastPage.title) { links.unshift(currentPageTitle); currentPageTitle = lastPage.title; } currentPageParameters = lastPage.page; currentPageParameters.content = lastPage.contentBefore.pop(); currentLink = lastPage.links.pop(); lastPage.summary.pop(); if (!lastPage.contentBefore.length) { pageChanges.pop(); } updateContext(); } }; var omit = () => { chooseReplacement(); }; var refresh = () => { saveAndEnd(); start(); }; var toggleActionButtons = (enabled) => { const affectedButtons = [ui.omitButton, ui.titleAsTextButton, ui.removeLinkButton, ui.intentionalLinkButton, ui.disamNeededButton, ui.undoButton]; for (var _i2 = 0, _affectedButtons = affectedButtons; _i2 < _affectedButtons.length; _i2++) { const button = _affectedButtons[_i2]; button.prop("disabled", !enabled); } }; var toggleFinishedMessage = (show) => { toggleActionButtons(!show); ui.undoButton.prop("disabled", !pageChanges.length); ui.finishedMessage.toggle(show); ui.pageTitleLine.toggle(!show); ui.context.toggle(!show); }; var togglePendingEditBox = (show) => { const $body = $("body"); if (!pendingEditBox) { pendingEditBox = $("<div>").addClass("disamassist-box disamassist-pendingeditbox"); pendingEditBoxText = $("<div>"); pendingEditBox.append(pendingEditBoxText).hide(); if (editLimit) { pendingEditBox.append($("<div>").text(messages.pendingEditBoxLimited).addClass("disamassist-subtitle")); } $body.find("#mw-content-text").before(pendingEditBox); updateEditCounter(); } if (show) { pendingEditBox.fadeIn(); } else { pendingEditBox.fadeOut(); } }; var notifyCompletion = () => { const $body = $("body"); const oldTitle = document.title; document.title = messages.notifyCharacter + document.title; $body.one("mousemove", () => { document.title = oldTitle; }); }; var updateContext = () => { updateEditCounter(); if (currentLink) { ui.pageTitleLine.html(messages.pageTitleLine.replace("$1", mw.util.getUrl(currentPageTitle, { redirect: "no" })).replace("$2", mw.html.escape(currentPageTitle))); const context = extractContext(currentPageParameters.content, currentLink); ui.context.empty().append($("<span>").text(context[0])).append($("<span>").text(context[1]).addClass("disamassist-inclink")).append($("<span>").text(context[2])); const numLines = Math.ceil(ui.context.height() / Number.parseFloat(ui.context.css("line-height"))); if (numLines < cfg.numContextLines) { ui.context.append(Array.from({ length: cfg.numContextLines - numLines + 2 }).join("<br>")); } toggleFinishedMessage(false); ui.undoButton.prop("disabled", !pageChanges.length); ui.removeLinkButton.prop("disabled", currentPageParameters.redirect); ui.intentionalLinkButton.prop("disabled", currentPageParameters.redirect); ui.disamNeededButton.prop("disabled", currentPageParameters.redirect || currentLink.hasDisamTemplate); choosing = true; } else { toggleFinishedMessage(true); } }; var updateEditCounter = () => { if (ui.pendingEditCounter) { ui.pendingEditCounter.text(messages.pendingEditCounter.replace("$1", editCount).replace("$2", countActuallyChangedFullyCheckedPages())); } if (pendingEditBox) { if (editCount === 0 && !running) { togglePendingEditBox(false); notifyCompletion(); } let textContent = editCount; if (editLimit) { textContent = messages.pendingEditBoxTimeEstimation.replace("$1", editCount).replace("$2", secondsToHHMMSS(cfg.editCooldown * editCount)); } pendingEditBoxText.text(messages.pendingEditBox.replace("$1", textContent)); } }; var applyChange = (pageChange) => { if (pageChange.page.content !== pageChange.contentBefore[0]) { editCount++; const changeSummaries = pageChange.summary.join(messages.summarySeparator); const summary = messages.summary.replace("$1", getTargetPage()).replace("$2", changeSummaries); const save = editLimit ? saveWithCooldown : savePage; save(pageChange.title, pageChange.page, summary, true, true).always(() => { if (editCount > 0) { editCount--; } updateEditCounter(); }).fail(error); updateEditCounter(); } }; var applyAllChanges = () => { var _iterator2 = _createForOfIteratorHelper(pageChanges), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) { const pageChange = _step2.value; applyChange(pageChange); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } pageChanges = []; }; var addChange = (pageTitle, page, oldContent, link, summary) => { if (!pageChanges.length || pageChanges.at(-1).title !== pageTitle) { pageChanges[pageChanges.length] = { title: pageTitle, page, contentBefore: [], links: [], summary: [] }; } const lastPageChange = pageChanges.at(-1); lastPageChange.contentBefore[lastPageChange.contentBefore.length] = oldContent; lastPageChange.links[lastPageChange.links.length] = link; lastPageChange.summary[lastPageChange.summary.length] = summary; }; var checkActualChanges = () => { return countActualChanges() !== 0; }; var countActualChanges = () => { let changeCount = 0; var _iterator3 = _createForOfIteratorHelper(pageChanges), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) { const pageChange = _step3.value; if (pageChange.page.content !== pageChange.contentBefore[0]) { changeCount++; } } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } return changeCount; }; var countActuallyChangedFullyCheckedPages = () => { let changeCount = countActualChanges(); if (pageChanges.length) { const lastChange = pageChanges.at(-1); if (lastChange.title === currentPageTitle && currentLink && lastChange.page.content !== lastChange.contentBefore[0]) { changeCount--; } } return changeCount; }; var getDisamOptions = () => { const $body = $("body"); return $body.find("#mw-content-text a").filter((_index, element) => { return !!extractPageName($(element)); }); }; var saveAndEnd = () => { applyAllChanges(); end(); }; var end = () => { const $body = $("body"); const currentToolUI = ui.display; choosing = false; running = false; startLink.removeClass("selected"); $body.find(".disamassist-optionmarker").remove(); currentToolUI.fadeOut({ complete() { currentToolUI.remove(); if (editCount) { togglePendingEditBox(true); } } }); }; var error = (errorDescription) => { const $body = $("body"); const errorBox = $("<div>").addClass("disamassist-box disamassist-errorbox"); errorBox.text(messages.error.replace("$1", errorDescription)); errorBox.append(createButton(messages.dismissError, () => { errorBox.fadeOut(); }).addClass("disamassist-errorbutton")); const uiIsInPlace = ui && $.contains(document.documentElement, ui.display[0]); const nextElement = uiIsInPlace ? ui.display : $body.find("#mw-content-text"); nextElement.before(errorBox); errorBox.hide().fadeIn(); }; var replaceLink = (text, title, link, extra) => { let newContent; if (isSamePage(title, link.description)) { newContent = link.description; } else { newContent = "".concat(title, "|").concat(link.description); } const linkStart = text.slice(0, Math.max(0, link.start)); const linkEnd = text.slice(Math.max(0, link.end)); return "".concat(linkStart, "[[").concat(newContent, "]]").concat(link.afterDescription).concat(extra || "").concat(linkEnd); }; var removeLink = (text, link) => { const linkStart = text.slice(0, Math.max(0, link.start)); const linkEnd = text.slice(Math.max(0, link.end)); return linkStart + link.description + link.afterDescription + linkEnd; }; var extractLink = (text, lastIndex) => { const titleRegex = /\[\[(.*?)(?:\|(.*?))?]]/g; const templateRegex = /^(\w*[\s!),.:;?}]*){{\s*([^{|}]+?)\s*(?:\|[^{]*?)?}}/; titleRegex.lastIndex = lastIndex; const match = titleRegex.exec(text); if (match && match.index !== -1) { var _match$; let possiblyAmbiguous = true; let hasDisamTemplate = false; let _end = match.index + 4 + match[1].length + (match[2] ? 1 + match[2].length : 0); let afterDescription = ""; const rest = text.slice(Math.max(0, _end)); const templateMatch = templateRegex.exec(rest); if (templateMatch) { const templateTitle = getCanonicalTitle(templateMatch[2]); const { disamLinkTemplates } = cfg; const { disamLinkIgnoreTemplates } = cfg; if (disamLinkTemplates.includes(templateTitle)) { _end += templateMatch[0].length; afterDescription = templateMatch[1].replace(/\s$/, ""); hasDisamTemplate = true; } else if (disamLinkIgnoreTemplates.includes(templateTitle)) { possiblyAmbiguous = false; } } return { start: match.index, end: _end, possiblyAmbiguous, hasDisamTemplate, title: match[1], description: (_match$ = match[2]) !== null && _match$ !== void 0 ? _match$ : match[1], afterDescription }; } }; var extractLinkToPage = (text, destinations, lastIndex) => { let link; let title; do { link = extractLink(text, lastIndex); if (link) { lastIndex = link.end; title = getCanonicalTitle(link.title); } } while (link && (!link.possiblyAmbiguous || !(destinations !== null && destinations !== void 0 && destinations.includes(title)))); return link; }; var getTargetPage = () => { const title = getTitle(); return forceSamePage ? title : removeDisam(title); }; var getTitle = () => { const { wgPageName } = mw.config.get(); return wgPageName.replace(/_/g, " "); }; var removeDisam = (title) => { var _match$2; const match = new RegExp(cfg.disamRegExp).exec(title); return (_match$2 = match === null || match === void 0 ? void 0 : match[1]) !== null && _match$2 !== void 0 ? _match$2 : title; }; var isSamePage = (title1, title2) => { return getCanonicalTitle(title1) === getCanonicalTitle(title2); }; var getCanonicalTitle = (title) => { try { title = new mw.Title(title).getPrefixedText(); } catch { } return title; }; var extractContext = (text, link) => { const contextStart = link.start - cfg.radius; const contextEnd = link.end + cfg.radius; let contextPrev = text.slice(contextStart, link.start); if (contextStart > 0) { contextPrev = messages.ellipsis + contextPrev; } let contextNext = text.slice(link.end, contextEnd); if (contextEnd < text.length) { contextNext += messages.ellipsis; } return [contextPrev, text.slice(link.start, link.end), contextNext]; }; var extractPageName = (link) => { let pageName = extractPageNameRaw(link); if (pageName) { const sectionPos = pageName.indexOf("#"); let section = ""; if (sectionPos !== -1) { section = pageName.slice(Math.max(0, sectionPos)); pageName = pageName.slice(0, Math.max(0, sectionPos)); } return getCanonicalTitle(pageName) + section; } }; var extractPageNameRaw = (link) => { const { wgScript, wgArticlePath } = mw.config.get(); if (!link.hasClass("image")) { const href = link.attr("href"); if (link.hasClass("new")) { if (href.includes(wgScript)) { return mw.util.getParamValue("title", href); } } else { const regex = wgArticlePath.replace("$1", "(.*)"); const regexResult = new RegExp("^".concat(regex, "$")).exec(href); if (Array.isArray(regexResult) && regexResult.length) { return decodeURIComponent(regexResult[1]); } } } }; var isDisam = () => { const { wgCategories } = mw.config.get(); const categories = wgCategories !== null && wgCategories !== void 0 ? wgCategories : []; var _iterator4 = _createForOfIteratorHelper(categories), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) { const category = _step4.value; const { disamCategories } = cfg; if (disamCategories.includes(category)) { return true; } } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } return false; }; var secondsToHHMMSS = (totalSeconds) => { let hhmmss = ""; const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor(totalSeconds % 3600 / 60); const seconds = Math.floor(totalSeconds % 3600 % 60); if (hours >= 1) { hhmmss = "".concat(pad(hours, "0", 2), ":"); } hhmmss += "".concat(pad(minutes, "0", 2), ":").concat(pad(seconds, "0", 2)); return hhmmss; }; var pad = (str, z, width) => { str = str.toString(); if (str.length >= width) { return str; } return Array.from({ length: width - str.length + 1 }).join(z) + str; }; var createButton = (text, onClick) => { const button = $("<input>").attr({ type: "button", value: text }); button.addClass("disamassist-button").on("click", onClick); return button; }; var resolveRedirect = (pageTitle, possibleRedirects) => { let appliedRedirect = true; const visitedPages = {}; let currentPage = getCanonicalTitle(pageTitle); while (appliedRedirect) { appliedRedirect = false; var _iterator5 = _createForOfIteratorHelper(possibleRedirects), _step5; try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) { const possibleRedirect = _step5.value; if (possibleRedirect.from === currentPage) { if (visitedPages[possibleRedirect.to]) { return pageTitle; } visitedPages[currentPage] = true; appliedRedirect = true; currentPage = possibleRedirect.to; } } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } } return currentPage; }; var getBacklinks = (page) => { const deferred = new $.Deferred(); const params = { action: "query", list: "backlinks", bltitle: page, blredirect: true, bllimit: cfg.backlinkLimit, blnamespace: cfg.targetNamespaces.join("|") }; api.get(params).done(({ query }) => { const backlinks = []; const linkTitles = [getCanonicalTitle(page)]; const backlinksQuery = query.backlinks; var _iterator6 = _createForOfIteratorHelper(backlinksQuery), _step6; try { for (_iterator6.s(); !(_step6 = _iterator6.n()).done; ) { const element = _step6.value; backlinks[backlinks.length] = element.title; if (!element.redirlinks) { continue; } linkTitles[linkTitles.length] = element.title; const { redirlinks } = element; var _iterator7 = _createForOfIteratorHelper(redirlinks), _step7; try { for (_iterator7.s(); !(_step7 = _iterator7.n()).done; ) { const { title } = _step7.value; backlinks[backlinks.length] = title; } } catch (err) { _iterator7.e(err); } finally { _iterator7.f(); } } } catch (err) { _iterator6.e(err); } finally { _iterator6.f(); } deferred.resolve(backlinks, linkTitles); }).fail((code) => { deferred.reject(messages.getBacklinksError.replace("$1", code)); }); return deferred.promise(); }; var fetchRedirects = (pageTitles) => { const deferred = new $.Deferred(); const currentTitles = pageTitles.slice(0, cfg.queryTitleLimit); const restTitles = pageTitles.slice(cfg.queryTitleLimit); const params = { action: "query", titles: currentTitles.join("|"), redirects: true }; api.get(params).done(({ query }) => { var _query$redirects; const theseRedirects = (_query$redirects = query.redirects) !== null && _query$redirects !== void 0 ? _query$redirects : []; if (restTitles.length) { fetchRedirects(restTitles).done((redirects) => { deferred.resolve([...theseRedirects, ...redirects]); }).fail((description) => { deferred.reject(description); }); } else { deferred.resolve(theseRedirects); } }).fail((code) => { deferred.reject(messages.fetchRedirectsError.replace("$1", code)); }); return deferred.promise(); }; var fetchRights = () => { const deferred = $.Deferred(); const params = { action: "query", meta: "userinfo", uiprop: "rights" }; api.get(params).done(({ query }) => { deferred.resolve(query.userinfo.rights); }).fail((code) => { deferred.reject(messages.fetchRightsError.replace("$1", code)); }); return deferred.promise(); }; var loadPage = (pageTitle) => { const deferred = new $.Deferred(); const params = { action: "query", format: "json", formatversion: "2", titles: pageTitle, prop: "revisions", rvprop: "timestamp|content", meta: "tokens", type: "csrf" }; api.get(params).done(({ query }) => { const [rawPage] = query.pages; const page = {}; page.redirect = rawPage.redirect !== void 0; page.missing = rawPage.missing !== void 0; if (rawPage.revisions) { page.content = rawPage.revisions[0].content; page.baseTimeStamp = rawPage.revisions[0].timestamp; } else { page.content = ""; page.baseTimeStamp = void 0; } page.startTimeStamp = rawPage.starttimestamp; page.editToken = query.tokens.csrftoken; deferred.resolve(page); }).fail((code) => { deferred.reject(messages.loadPageError.replace("$1", pageTitle).replace("$2", code)); }); return deferred.promise(); }; var saveWithCooldown = (...args) => { const deferred = new $.Deferred(); pendingSaves[pendingSaves.length] = { args, dfd: deferred }; if (!runningSaves) { checkAndSave(); } return deferred.promise(); }; var checkAndSave = function() { if (!pendingSaves.length) { runningSaves = false; return; } runningSaves = true; const millisSinceLast = Date.now() - lastEditMillis; if (millisSinceLast < cfg.editCooldown * 1e3) { setTimeout(checkAndSave, cfg.editCooldown * 1e3 - millisSinceLast); } else { const save = pendingSaves.shift(); savePage.apply(this, save.args).done(() => { checkAndSave(); save.dfd.resolve(); }).fail((description) => { checkAndSave(); save.dfd.reject(description); }); lastEditMillis = Date.now(); } }; var savePage = (pageTitle, { editToken, content, baseTimeStamp, startTimeStamp }, summary, minorEdit, botEdit) => { const deferred = new $.Deferred(); const params = { action: "edit", title: pageTitle, token: editToken, text: content, basetimestamp: baseTimeStamp, starttimestamp: startTimeStamp, summary, watchlist: cfg.watch, minor: minorEdit, bot: botEdit }; api.post(params).done(() => { deferred.resolve(); }).fail((code) => { deferred.reject(messages.savePageError.replace("$1", pageTitle).replace("$2", code)); }); return deferred.promise(); }; //! src/DisamAssist/DisamAssist.ts $(install); })();
该页面使用的模板:
Template:Disambiguation
(
查看源代码
)
Template:Dn
(
查看源代码
)
Template:Gadget Header
(
查看源代码
)
Template:R to disambiguation page
(
查看源代码
)
返回
MediaWiki:Gadget-DisamAssist.js
。
开关有限宽度模式