打开主菜单
首页
随机
登录
设置
关于H萌娘
免责声明
H萌娘
搜索
点击此处会biu~的随机导向一个高级条目哦 ><
|
H萌娘上月访问数据报告
查看“MediaWiki:AxUserMsg.js”的源代码
←
MediaWiki:AxUserMsg.js
因为以下原因,您没有权限编辑本页:
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
//<nowiki> /** * https://commons.wikimedia.org/w/index.php?oldid=553484026 */ "use strict"; (async () => { if (window.AxUserMsg || !mw.config.get("wgUserGroups").includes("patroller") && !mw.config.get("wgUserGroups").includes("sysop")) { return; } class ClsUPC { constructor($userInputField, $outputField, stCallBack, callingObject, CBValidChange) { this.$userInputField = $userInputField; this.$outputField = $outputField; this.callingObject = callingObject; this.stCallBack = stCallBack; this.CBValidChange = CBValidChange; this.pendingCalls = 0; this.pendingSetTimeouts = 0; this.oldValue = ""; this.userNameExists = 2; const o = this; $userInputField.on("keyup", ( /* e*/) => { const tmpUNE = o.userNameExists; if (o.isValidIP($userInputField.val())) { o.setToIP(tmpUNE); } else { o.execApiCall(false, $userInputField.val()); } }); $userInputField.on("input", () => { $userInputField.keyup(); }); $userInputField.on("selected", () => { $userInputField.keyup(); }); } isValidIP(username) { if (mw.util.isIPv4Address(username)) { return true; } //IP v.4 return mw.util.isIPv6Address(username); //IP v.6 } setToIP(tmpUNE) { const o = this; o.userNameExists = -1; if ("function" === typeof o.CBValidChange && tmpUNE !== o.userNameExists) { o.$outputField.attr("src", o.callingObject.umImgUserIsIP); o.$outputField.attr("alt", "IP"); o.oldValue = o.callingObject.umCleanFileAndUser(o.$userInputField.val()); o.CBValidChange(o, o.callingObject); } } execApiCall(isTimeout, val) { if (isTimeout) { this.pendingSetTimeouts--; } if (this.oldValue !== this.callingObject.umCleanFileAndUser(val)) { if (this.pendingCalls > 0) { if (!this.pendingSetTimeouts) { this.pendingSetTimeouts++; const o = this; setTimeout(() => { o.execApiCall(true, o.$userInputField.val()); }, 1000); // do not use the old value, use the current instead } return; } const User = this.oldValue = this.callingObject.umCleanFileAndUser(val); const query = { action: "query", list: "allusers", aufrom: User, auto: User, }; this.callingObject.umCurrentUserQuery = this; this.pendingCalls++; this.callingObject.doAPICall(query, this.stCallBack); } } evalAPICall(result) { this.pendingCalls--; const uifval = this.$userInputField.val(); if (this.oldValue !== this.callingObject.umCleanFileAndUser(uifval)) { // Don't do anything if user updated the field in-between return; } if (this.isValidIP(uifval)) { return; } if ("object" === typeof result.query && "object" === typeof result.query.allusers) { const tmpUNE = this.userNameExists; if (!result.query.allusers.length) { this.$outputField.attr("src", this.callingObject.umImgUserNotExists); this.$outputField.attr("alt", "!! invalid !!"); this.userNameExists = false; } else { if (this.callingObject.umCleanFileAndUser(this.$userInputField.val()) === result.query.allusers[0].name) { this.$outputField.attr("src", this.callingObject.umImgUserExists); this.$outputField.attr("alt", "OK"); this.userNameExists = true; } else { if (!this.pendingSetTimeouts) { // Only overwrite if there is nothing pending this.$outputField.attr("src", this.callingObject.umImgUserUndefined); this.$outputField.attr("alt", "?"); this.userNameExists = 2; } } } if ("function" === typeof this.CBValidChange && tmpUNE !== this.userNameExists) { this.CBValidChange(this, this.callingObject); } } } } const umsg = window.AxUserMsg = { umInstall: () => { if ($("#t-AjaxUserMessage").length === 0) { const $LODLinkNode = $("#t-AjaxUserMessageLOD"); const $Href = $LODLinkNode.length ? $LODLinkNode.eq(0) : $(mw.util.addPortletLink("p-tb", "#", "警告用户", "t-AjaxUserMessage", "加载 UserMessages 小工具")); $Href.on("click", (e) => { e.preventDefault(); umsg.fireImmediately = false; umsg.umNotifyUser(); }); } }, umInstallOldLinks: () => { // written for Herby, who needs this for working on Commons umsg.umTemplate.forEach((ti, id) => { // Create portlet link const portletLink = mw.util.addPortletLink("p-tb", `#${id}`, ti[1], `t-gadgetUserMessage${id}`, ti[2]); // Bind click handler $(portletLink).on("click", (e) => { e.preventDefault(); window.AxUserMsgPreSelect = $(portletLink).find("a").attr("href").split("#")[1]; if (window.AxUserMsgFireAsYouClick) { const umType = umsg.umTemplate[umsg.umSelect][3]; if (!(umType & umsg.umFlagUQ) && !(umType & umsg.umFlagReq)) { umsg.fireImmediately = true; } else { umsg.fireImmediately = false; } } umsg.umNotifyUser(); }); }); }, umNotifyUser: () => { // mw.util.addCSS('a.new{color:#B00 !important;}'); ?? umsg.umUser = ""; umsg.editToken = ""; umsg.umDlgPresent = false; umsg.umExecuting = false; umsg.umPendingParser = 0; umsg.umPendingParserTimeouts = 0; umsg.umParserTimerID = 0; umsg.umDelay = window.AxUserMsgDelay || 100; umsg.umUserCache = {}; umsg.umFileCache = {}; umsg.umParserCache = {}; umsg.focusOwner = ""; umsg.umObtainEditToken(); umsg.umUser = mw.libs.commons.guessUser(); umsg.umDlg(); }, umFillSelect: (caller, o) => { const userstate = caller.userNameExists; o.umTemplate.forEach((currentTag, id) => { if ($(`#umOpt${id}`, o.$tagSelect).length === 0) { // check wether to add if (-1 === userstate && !(currentTag[3] & o.umFlagUM) || true === userstate && !(currentTag[3] & o.umFlagIP)) { o.$tagSelect.append(`<option id="umOpt${id}" value="${id}">${mw.html.escape(`${currentTag[1]} - ${currentTag[2]}`)}</option>`); return; } } else { // check wether to remove if (-1 === userstate && currentTag[3] & o.umFlagUM || true === userstate && currentTag[3] & o.umFlagIP) { $(`#umOpt${id}`, o.$tagSelect).remove(); return; } } }); if (-1 === userstate) { if (window.AxUserMsgPreSelectIP) { o.$tagSelect.val(window.AxUserMsgPreSelectIP); } } else { o.$tagSelect.val(umsg.umSelect); } o.umValidateInput(o); o.$tagSelect.change(); }, umDlg: () => { const $win = $(window); umsg.dlg = $("<div>").html('<div id="AjaxUmContainer"></div>').dialog({ modal: true, closeOnEscape: true, position: [Math.round(($win.width() - Math.min($win.width(), 850)) / 2), Math.round(($win.height() - Math.min($win.height(), 800)) / 2)], title: '警告用户 - <span class="mw-parser-output"><a href="//commons.wikimedia.org/wiki/MediaWiki_talk:Gadget-UserMessages.js" target="_blank" rel="nofollow noreferrer noopener" class="external text">去维基共享报告错误和建议</a> | <a href="https://zh.moegirl.org.cn/Help:UserMessages%E5%B0%8F%E5%B7%A5%E5%85%B7" target="_blank" class="external text">使用帮助</a></span>', height: Math.min($win.height(), 800), width: Math.min($win.width(), 850), buttons: { [umsg.i18n.submitButtonLabel]: () => { try { if (umsg.umIsValid) { umsg.umNotifyUserExecute(); } } catch (ex) { umsg.fail(ex); } }, [umsg.i18n.cancelButtonLabel]: function () { $(this).dialog("close"); console.info("[this.i18n.cancelButtonLabel]", this, umsg.dlg); }, }, close: function () { console.info("close", this, umsg.dlg); $(this).dialog("destroy"); $(this).remove(); umsg.umDlgPresent = false; }, open: function () { const $dlg = $(this); // 不可去除 $dlg.parents(".ui-dialog").css({ position: "fixed", top: `${Math.round(($win.height() - Math.min($win.height(), 800)) / 2)}px`, }); }, }); umsg.umDlgPresent = true; if (umsg.dlg) { const $AjaxUmContainer = $("#AjaxUmContainer"); $AjaxUmContainer.append(`<label for="umUser">${mw.html.escape(umsg.i18n.umFillInUser)}</label><br><input type="text" id="umUser" style="width: 95%;" value="${mw.html.escape(umsg.umUser)}"/>${umsg.umInitImgUserExists.replace("%ID%", "umUserExists")}<br><br>`); umsg.$tagSelect = $("<select>", { size: "1", id: "umTagToInsert", style: "width: 99%;", }); $AjaxUmContainer.append([ `<label for="umTagToInsert">${mw.html.escape(umsg.i18n.umSelectTag)}</label><br>`, umsg.$tagSelect, "<br><br>", `<span id="umMediaWrapper"><label for="umMedia">${mw.html.escape(umsg.i18n.umFillInMedia)}</label><br><input type="text" id="umMedia" style="width: 95%;" value="File:"/><br><br></span>`, `<span id="umP2Wrapper"><label for="umP2">${mw.html.escape(umsg.i18n.umFillInAdditional)}</label><br><input type="text" id="umP2" style="width: 95%;"/><br><br></span>`, `<span id="umP3Wrapper"><label for="umP3">${mw.html.escape(umsg.i18n.umFillInAdditional)}</label><br><input type="text" id="umP3" style="width: 95%;"/><br><br></span>`, `<span id="umRelatedUserWrapper"><label for="umRelatedUser">${mw.html.escape(umsg.i18n.umFillInRelUser)}</label><br><input type="text" id="umRelatedUser" style="width: 95%;" value="User:"/>${umsg.umInitImgUserExists.replace("%ID%", "umRelatedUserExists")}<br><br></span>`, `<span id="umSummaryWrapper"><label for="umSummary">${mw.html.escape(umsg.i18n.umFillInSummary)}</label><br><input type="text" id="umSummary" style="width: 95%;" value="摘要"/><br><br></span>`, `<label for="umAddText">${mw.html.escape(umsg.i18n.umAddText)}</label><br><textarea id="umAddText" style="width: 95%; height: 5em;">${mw.html.escape(window.AxUserMsgCustomText || "")}</textarea><br><br>`, ]); umsg.talkTag = ""; const $umMedia = $("#umMedia"), $umP2 = $("#umP2"), $umP3 = $("#umP3"), $umUser = $("#umUser"), $umRelatedUser = $("#umRelatedUser"), $umSummary = $("#umSummary"), $umAddText = $("#umAddText"); umsg.uUPC = new ClsUPC($umUser, $("#umUserExists"), "umUserExistsCB", umsg, umsg.umFillSelect); umsg.ouUPC = new ClsUPC($umRelatedUser, $("#umRelatedUserExists"), "umUserExistsCB", umsg, umsg.umUserValidChange); const submitButton = $(".ui-dialog-buttonpane button:first"); // guessing the related file thanks User:Platonides const guessFile = () => { let f = mw.util.getParamValue("title", document.referrer); if (f && /File:/.test(f)) { return f; } f = mw.util.getParamValue("page", document.referrer); if (f && /File:/.test(f)) { return f; } f = mw.util.getParamValue("target", document.referrer); if (f && /File:/.test(f)) { return f; } const m = document.referrer.match(/File:(.+)/); try { if (m) { if (/&.+=/.test(m[1])) { return `File:${decodeURI(m[1]).match(/^(.+)&/)[1]}`; } return `File:${m[1]}`; } } catch { } }; const umFile = guessFile(); if (umFile) { $umMedia.val(decodeURIComponent(umFile).replace(/_/g, " ")); } $umUser.on("keyup", (event) => { $umUser.val($umUser.val().replace(/<|>|\^/g, "")); }); $umUser.autocomplete({ minLength: 1, source: (request, callback) => { umsg.umSeekUsers(request, callback); }, close: () => { $umUser.triggerHandler("selected"); }, }); $umMedia.on("change", () => { umsg.umValidateInput(umsg); }); $umMedia.on("input", () => { $umMedia.val($umMedia.val().replace(/<|>|\^/g, "")); umsg.umValidateInput(umsg); }); $umMedia.on("keyup", (e) => { $umMedia.val($umMedia.val().replace(/<|>|\^/g, "")); }); $umMedia.autocomplete({ minLength: 1, source: (request, callback) => { umsg.umSeekFiles(request, callback); }, close: () => { $umMedia.triggerHandler("input"); }, }); $umRelatedUser.on("keyup", (event) => { $umRelatedUser.val($umRelatedUser.val().replace(/<|>|\^/g, "")); umsg.umValidateInput(umsg); }); $umRelatedUser.autocomplete({ minLength: 1, source: (request, callback) => { umsg.umSeekUsers(request, callback); }, close: () => { $umRelatedUser.triggerHandler("selected"); }, }); $umP2.on("change", () => { umsg.umValidateInput(umsg); }); $umP2.on("input", () => { umsg.umValidateInput(umsg); }); $umP3.on("change", () => { umsg.umValidateInput(umsg); }); $umP3.on("input", () => { umsg.umValidateInput(umsg); }); $umAddText.on("change", () => { umsg.umValidateInput(umsg); }); $umAddText.on("input", () => { umsg.umValidateInput(umsg); }); submitButton.focus(); $AjaxUmContainer.append(umsg.umInstPrevContainer.clone().text("即时预览为空")); umsg.$tagSelect.on("change", () => { const umType = umsg.umTemplate[$(umsg.$tagSelect).val()][3]; $umSummary.val(umsg.umTemplate[$("#umTagToInsert").val()][4] ? umsg.umTemplate[$("#umTagToInsert").val()][4] : `${umsg.umTemplate[$("#umTagToInsert").val()][2]}.`); umsg.umValidateInput(umsg); umsg.$tagSelect.combobox({ displaytext: umsg.$tagSelect.val() ? umsg.$tagSelect.children(":selected").text() : "", }); if (umType & umsg.umFlagP2) { $("#umP2Wrapper").show(); if (document.activeElement && $umUser.attr("id") !== document.activeElement.id) { $("#umP2").select(); } } else { $("#umP2Wrapper").hide(); } if (umType & umsg.umFlagP3) { $("#umP3Wrapper").show(); if (document.activeElement && $umUser.attr("id") !== document.activeElement.id) { $("#umP3").select(); } } else { $("#umP3Wrapper").hide(); } if (umType & umsg.umFlagMQ) { $("#umMediaWrapper").show(); if (document.activeElement && $umUser.attr("id") !== document.activeElement.id) { $("#umMedia").select(); } } else { $("#umMediaWrapper").hide(); } if (umType & umsg.umFlagUQ) { $("#umRelatedUserWrapper").show(); if (document.activeElement && $umUser.attr("id") !== document.activeElement.id) { $("#umMedia").select(); } } else { $("#umRelatedUserWrapper").hide(); } }); umsg.$tagSelect.val(umsg.umSelect); $("#umUser").keyup(); $("#umTagToInsert").combobox(); } }, umSeekUsers: (request, pCallback) => { const query = { action: "query", list: "allusers", auprefix: request.term.replace(/^(?:User):/, ""), }; umsg.doGetApiCall(query, "umSeekUsersCB", pCallback); }, umSeekUsersCB: (result, pCallback) => { const searchTerms = []; result.forEach((usi) => { searchTerms.push({ id: usi.userid, value: usi.name, }); }); if ("function" === typeof pCallback) { pCallback(searchTerms); } }, umSeekFiles: (request, pCallback) => { const query = { action: "query", list: "allimages", aiprefix: request.term.replace(/^(?:File|Image):/, ""), }; umsg.doGetApiCall(query, "umSeekFilesCB", pCallback); }, umSeekFilesCB: (result, pCallback) => { const searchTerms = []; result.forEach((fii) => { searchTerms.push({ id: fii.timestamp, value: `File:${fii.name}`, }); }); if ("function" === typeof pCallback) { pCallback(searchTerms); } }, umUserExistsCB: (result) => { umsg.umCurrentUserQuery.evalAPICall(result); }, umShowInfo: (info, o) => { $("#umInstantPreviewContainer").empty().html(`<p class="center"><img src="${o.umImgInfo}" width="64" height="64"/><br>${info}</p>`); }, umValidateInput: (o) => { umsg.umIsValid = true; const umType = umsg.umTemplate[$("#umTagToInsert").val()][3]; const submitButton = $(".ui-dialog-buttonpane button:first"); const validRelatedUser = () => { if (umType & o.umFlagUQ) { if (o.umCleanFileAndUser($("#umRelatedUser").val()).length < 1) { o.umShowInfo("未指定相关用户", o); return false; } if (!o.ouUPC.userNameExists) { o.umShowInfo("所指定的相关用户不存在", o); return false; } } return true; }; const validMedia = () => { if (umType & o.umFlagMQ) { if (o.umCleanFileAndUser($("#umMedia").val()).length < 5 && umType & o.umFlagReq) { o.umShowInfo("未指定文件,且强制检查已开启", o); return false; } } return true; }; const validUser = () => { if (o.umCleanFileAndUser($("#umUser").val()).length < 1) { o.umShowInfo("未指定用户", o); return false; } if (!o.uUPC.userNameExists) { o.umShowInfo("所指定的用户不存在", o); return false; } return true; }; umsg.umIsValid = umsg.umIsValid && validRelatedUser() && validMedia() && validUser(); if (umsg.umIsValid) { submitButton.removeClass("ui-state-disabled"); if (umType & umsg.umFlagMQ) { umsg.talkTag = `\n{{${umsg.umTemplate[$("#umTagToInsert").val()][0]}${umsg.umCleanFileAndUser($("#umMedia").val()) ? `|1=${umType & umsg.umFlagNS ? `File:${umsg.umCleanFileAndUser($("#umMedia").val())}` : $("#umMedia").val()}` : ""}`; } else if (umType & umsg.umFlagUQ) { umsg.talkTag = `\n{{${umsg.umTemplate[$("#umTagToInsert").val()][0]}|1=${umsg.umCleanFileAndUser($("#umRelatedUser").val())}`; } else { umsg.talkTag = `\n{{${umsg.umTemplate[$("#umTagToInsert").val()][0]}`; } let paramCount = (umType & umsg.umFlagUQ ? 1 : 0) + (umType & umsg.umFlagMQ ? 1 : 0); // cut of extra white space const sigText = "——~~~~"; if (umType & umsg.umFlagP2) { paramCount++; umsg.talkTag += `|${paramCount}=${$("#umP2").val()}`; } if (umType & umsg.umFlagP3) { paramCount++; umsg.talkTag += `|${paramCount}=${$("#umP3").val()}`; } umsg.talkTag += "}}"; if ("\n{{}}" === umsg.talkTag) { umsg.talkTag = "\n"; } umsg.talkTag += `\n${$("#umAddText").val().replace(/~{3,5}$/, "")}${sigText}\n`; umsg.umParseTemplate(false); // If the user wants the old behaviour back, we fire immediately if (umsg.fireImmediately) { umsg.umNotifyUserExecute(); } } else { submitButton.addClass("ui-state-disabled"); } }, umUserValidChange: (_, o) => { o.umValidateInput(o); }, umCleanFileAndUser: (input) => { let output = ""; if (input) { output = input.replace(/_/g, " ").replace(/File:/g, "").replace(/Image:/g, "").replace(/User:/g, "").replace(/^\s+|\s+$/g, ""); output = output.substring(0, 1).toUpperCase() + output.substring(1); } return output; }, umParseTemplate: (viaSetTimeout) => { if (window.AxUserMsgNoParse) { return; } if (viaSetTimeout) { umsg.umPendingParserTimeouts--; } if (umsg.umPendingParser > 0) { if (!umsg.umPendingParserTimeouts) { // call me later const o = umsg; umsg.umPendingParserTimeouts++; setTimeout(() => { o.umParseTemplate(true); }, 300); } return; } const maybeParse = () => { umsg.umPendingParser++; const action = { action: "parse", uselang: mw.config.get("wgUserLanguage"), redirects: true, prop: "text", pst: true, title: umsg.umUserTalkPrefix + $("#umUser").val(), text: umsg.talkTag, }; umsg.umDelay = Math.min(umsg.umDelay + 30, 1500); // Save server resources. umsg.doAPICall(action, "umParsedTemplate"); }; if (umsg.umParserTimerID) { clearTimeout(umsg.umParserTimerID); } umsg.umParserTimerID = setTimeout(maybeParse, umsg.umDelay); }, umParsedTemplate: (result) => { umsg.umPendingParser--; if ("object" === typeof result.parse && "object" === typeof result.parse.text && umsg.umDlgPresent && !umsg.umExecuting && umsg.umIsValid) { let $containerText = result.parse.text["*"].replace(" API", ` ${umsg.umCleanFileAndUser($("#umUser").val())}`).replace(">API", `>${umsg.umCleanFileAndUser($("#umUser").val())}`); $containerText = $($containerText); $(".editsection", $containerText).remove(); $("a", $containerText).attr("target", "_blank"); $("#umInstantPreviewContainer").empty().append($containerText).resizable({ alsoResize: "#AjaxUmContainer", }); } }, umObtainEditToken: () => { if (mw.user && mw.user.tokens) { umsg.editToken = mw.user.tokens.get("csrfToken"); } umsg.editToken = umsg.editToken || (mw.user.isAnon() ? "+\\" : ""); if (umsg.editToken) { return; } const query = { action: "query", prop: "info", intoken: "edit", titles: "FAQ", // Random title }; umsg.doAPICall(query, "umObtainEditTokenCB"); }, umObtainEditTokenCB: (result) => { const pages = result.query.pages; for (const id in pages) { // there should be only one, but we don't know its ID if (Object.hasOwnProperty.bind(pages)(id)) { umsg.editToken = pages[id].edittoken; } } }, umNotifyUserExecute: () => { if (umsg.umExecuting) { return; } umsg.pageName = umsg.umUserTalkPrefix + $("#umUser").val(); umsg.talkSummary = $("#umSummary").val(); umsg.appendTemplate(); }, appendTemplate: () => { const page = []; page.title = umsg.pageName; page.text = umsg.talkTag; page.editType = "appendtext"; page.redirect = true; if (window.AjaxDeleteWatchFile) { page.watchlist = "watch"; } umsg.umExecuting = true; $("#umInstantPreviewContainer").empty().html('<p class="center"><img src="https://img.moegirl.org.cn/common/d/d1/Windows_10_loading.gif"/></p>'); umsg.savePage(page, umsg.talkSummary, "umNotifyUserExecuteCB"); }, savePage: (page, summary, callback) => { const edit = { action: "edit", summary: summary, watchlist: page.watchlist || "preferences", title: page.title, }; if (page.redirect) { edit.redirect = ""; } edit[page.editType] = page.text; edit.token = umsg.editToken; umsg.doAPICall(edit, callback); }, umNotifyUserExecuteCB: (/* result*/) => { let encTitle = umsg.umUserTalkPrefix + $("#umUser").val(); encTitle = encodeURIComponent(encTitle.replace(/ /g, "_")).replace(/%2F/ig, "/").replace(/%3A/ig, ":"); const newLoc = mw.config.get("wgServer") + mw.config.get("wgArticlePath").replace("$1", encTitle); if (window.location.pathname === mw.config.get("wgArticlePath").replace("$1", encTitle)) { window.location.hash = "#footer"; window.location.reload(); } else { window.location.href = `${newLoc}#footer`; } umsg.umExecuting = false; }, doGetApiCall: (params, callback, pCallback) => { // Local Cache if (params.list) { if ("allusers" === params.list) { if (params.auprefix in umsg.umUserCache) { umsg[callback](umsg.umUserCache[params.auprefix], pCallback); return; } } else if ("allimages" === params.list) { if (params.aiprefix in umsg.umFileCache) { umsg[callback](umsg.umFileCache[params.aiprefix], pCallback); return; } } } params.format = "json"; $.ajax({ url: umsg.apiURL, cache: true, dataType: "json", data: params, type: "GET", async: true, success: (result) => { if (!result) { if ("function" === typeof pCallback) { pCallback(); } return; } try { if (params.list) { if ("allusers" === params.list) { // cache the result umsg.umUserCache[params.auprefix] = result.query.allusers; umsg[callback](result.query.allusers, pCallback); return; } } if (params.list) { if ("allimages" === params.list) { // cache the result umsg.umFileCache[params.aiprefix] = result.query.allimages; umsg[callback](result.query.allimages, pCallback); return; } } // This is a "must", the doc sais if ("function" === typeof pCallback) { pCallback(); } umsg[callback](result); } catch (e) { return umsg.fail(e); } }, error: () => { // This is a "must", the doc sais if ("function" === typeof pCallback) { pCallback(); } }, }); }, doAPICall: (params, callback) => { if (params.action) { if ("parse" === params.action) { if (params.text in umsg.umParserCache) { umsg[callback](umsg.umParserCache[params.text]); return; } } } params.format = "json"; $.ajax({ url: umsg.apiURL, cache: false, dataType: "json", data: params, type: "POST", success: (result, _, x) => { if (!result) { return umsg.fail(`API 响应为空:\n${x.responseText}`); } // In case we get the mysterious 231 unknown error, just try again if (result.error && result.error.info.includes("231")) { return setTimeout(() => { umsg.doAPICall(params, callback); }, 500); } if (result.error) { return umsg.fail(`API 请求返回失败结果 (${result.error.code}):${result.error.info}`); } if (result.edit && result.edit.spamblacklist) { return umsg.fail(`此次编辑因 ${result.edit.spamblacklist} 被列入黑名单而失败`); } if (params.action) { if ("parse" === params.action) { umsg.umParserCache[params.text] = result; } } try { umsg[callback](result); } catch (e) { return umsg.fail(e); } }, error: (x, status, error) => { return umsg.fail(`API 请求遭遇网络错误:状态码为 【${x.status}】,状态文本为 【${status}】,错误信息为 【${error}】`); }, }); }, fail: (_err) => { let err; if ("object" === typeof _err) { let stErr = `${mw.html.escape(_err.message)}<br>${_err.name}`; if (_err.lineNumber) { stErr += ` @line${_err.lineNumber}`; } if (_err.line) { stErr += ` @line${_err.line}`; } err = stErr; } else { err = mw.html.escape(_err.toString()); } if (umsg.umDlgPresent) { $("#umInstantPreviewContainer").empty().html(`<p class="center"><img src="${umsg.umImgErr}" width="64" height="64"/></p><br>小工具发生错误:<br>${mw.html.escape(err)}`); } else { mw.notify(`小工具发生错误:${err}`); } }, i18n: { umFillInUser: "被警告的用户:", umSelectTag: "警告类型:", umFillInMedia: "相关图片文件", umFillInAdditional: "用户违规的页面:", umFillInRelUser: "被警告的相关用户:", umFillInSummary: "编辑摘要:", umAddText: "额外补充的信息:", submitButtonLabel: "留言", cancelButtonLabel: "取消", }, umInstPrevContainer: $("<div>", { id: "umInstantPreviewContainer", style: "background-color:#EFD;min-height:250px;vertical-align:middle;", }), umInitImgUserExists: '<img id="%ID%" src="https://img.moegirl.org.cn/common/thumb/4/42/P_no.svg/20px-P_no.svg.png" alt="?"/>', umImgUserUndefined: "https://img.moegirl.org.cn/common/thumb/4/42/P_no.svg/20px-P_no.svg.png", umImgUserNotExists: "https://img.moegirl.org.cn/common/thumb/4/42/P_no.svg/20px-P_no.svg.png", umImgUserExists: "https://img.moegirl.org.cn/common/thumb/b/be/P_yes.svg/20px-P_yes.svg.png", umImgUserIsIP: "https://img.moegirl.org.cn/common/thumb/7/7e/OOjs_UI_icon_userAnonymous.svg/20px-OOjs_UI_icon_userAnonymous.svg.png", umImgErr: "https://img.moegirl.org.cn/common/7/7f/Dialog-error.svg", umImgWarn: "https://img.moegirl.org.cn/common/b/bc/Commons-emblem-issue.svg", umImgInfo: "https://img.moegirl.org.cn/common/2/28/Commons-emblem-notice.svg", umFlagMQ: 1, // Media Query umFlagUQ: 2, // Username Query umFlagReq: 4, // Required - must filled in umFlagNS: 8, // Add Namespace umFlagP2: 16, // add a universal parameter umFlagP3: 32, // add a universal parameter umFlagIP: 64, // Message for IP only umFlagUM: 128, // User message only umFlagReqMqNs: 13, // Combination of (umFlagReq | umFlagMQ | umFlagNS) umUserTalkPrefix: `${mw.config.get("wgFormattedNamespaces")[3]}:`, apiURL: mw.util.wikiScript("api"), }; /** * A custom widget built by composition of Autocomplete and Button. * You can either type something into the field to get filtered suggestions based on your input, * or use the button to get the full list of selections. * * The input is read from an existing select-element for progressive enhancement, * passed to Autocomplete with a customized source-option. * * Autor: someone from the jQuery UI-Team? * slightly altered **/ const initCombobox = ($) => { $.widget("ui.combobox", { // These options will be used as defaults options: { displaytext: "", emptyMessage: 42, passEnter: true, shutOff: window.AxUserMsgUseSelect, }, // Use the _setOption method to respond to changes to options _setOption: function (key, value, ...args) { if (this.options.shutOff) { return; } switch (key) { case "displaytext": this.input.val(value); break; case "passEnter": this.options.passEnter = value; break; } // In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget $.Widget.prototype._setOption.apply(this, [key, value, ...args]); }, _create: function () { if (this.options.shutOff) { return; } const self = this, select = this.element.hide(), selectWidth = select.width(), selectId = select.attr("id"), selected = select.children(":selected"), value = selected.val() ? selected.text() : "", ownId = `j${Math.floor(Math.random() * 10000000000)}`; let selectLabels, isOpen = false, valid = true; if (selectId) { selectLabels = $(`label[for="${selectId}"]`); } const portMessure = this.portMessure = $("<div>", { id: `${ownId}vp`, }).css({ position: "fixed", top: "0", height: "0", }); $("body").append(portMessure); const input = this.input = $("<input>", { id: ownId, }).insertAfter(select).val(value).autocomplete({ delay: 0, minLength: 0, source: (request, response) => { let i = 0; const matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i"); response(select.children("option").map((_, ele) => { if (i > (window.AxUserMsgMaxSelect || 20) && request.term) { return; } const text = $(ele).text(); if (ele.value && (!request.term || matcher.test(text))) { i++; return { label: text.replace( new RegExp( `(?![^&;]+;)(?!<[^<>]*)(${$.ui.autocomplete.escapeRegex(request.term) })(?![^<>]*>)(?![^&;]+;)`, "gi", ), "<b>$1</b>"), value: text, option: ele, }; } })); }, select: (event, ui) => { ui.item.option.selected = true; self._trigger("selected", event, { item: ui.item.option, }); select.triggerHandler("change"); }, change: function (_, ui) { setTimeout(() => { console.info("change", input, this, ui); }, 16); if (!ui.item) { const matcher = new RegExp(`^${$.ui.autocomplete.escapeRegex($(this).val())}$`, "i"); valid = false; select.children("option").each((_, ele) => { if ($(ele).text().match(matcher)) { ele.selected = valid = true; return false; } }); if (!valid) { // remove invalid value, as it didn't match anything $(this).val(""); input.data("autocomplete").term = ""; select.val(self.options.emptyMessage); select.triggerHandler("change"); return false; } select.triggerHandler("change"); } }, create: function () { const $this = $(this); // 不可去除 const t_top = $this.offset().top - portMessure.offset().top; $(".ui-autocomplete.ui-menu").css({ position: "fixed", overflow: "auto", "max-height": `${Math.round($(window).height() - t_top - $this.height() - 20)}px`, }); }, close: () => { setTimeout(() => { isOpen = false; }, 1); }, open: function () { setTimeout(() => { console.info("open", input, this); }, 16); isOpen = true; const _t = $(this), t_top = _t.offset().top - portMessure.offset().top; $(".ui-autocomplete.ui-menu").css({ position: "fixed", "max-height": `${Math.round($(window).height() - t_top - _t.height() - 20)}px`, }); }, }).addClass("ui-widget ui-widget-content ui-corner-left").css("width", `${selectWidth - 70}px`).on("click", () => { $(input).select(); }).on("keydown", (e) => { if (self.options.passEnter && 13 === e.which && !isOpen && valid) { const kup = $.Event("keyup"); kup.ctrlKey = false; kup.keyCode = kup.which = 13; select.triggerHandler(kup); } }); if (selectLabels) { selectLabels.attr("for", ownId); } input.data("autocomplete")._renderItem = (ul, item) => { return $("<li>").data("item.autocomplete", item).append(`<a>${item.label}</a>`).appendTo(ul); }; this.button = $("<button>", { tabIndex: -1, type: "button", text: " ", title: "Show All Items", style: "height:1.5em;padding:0!important;width:20px;margin:0!important;position:relative;top:-2px;", }).insertAfter(input).button({ icons: { primary: "ui-icon-triangle-1-s", }, text: false, }).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").on("click", () => { // close if already visible if (input.autocomplete("widget").is(":visible")) { input.autocomplete("close"); return; } // work around a bug (likely same cause as #5265) this.button.blur(); // pass empty string as value to search for, displaying all results input.autocomplete("search", ""); input.focus(); }); }, destroy: function () { if (this.options.shutOff) { return; } this.input.remove(); this.portMessure.remove(); this.button.remove(); this.element.show(); $.Widget.prototype.destroy.call(this); }, }); }; if ([-1, 2, 3].includes(mw.config.get("wgNamespaceNumber"))) { // alternative for jQuery UI autocomplete: jquery.suggestions // http://jqueryui.com/demos/autocomplete/ http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/resources/jquery/jquery.suggestions.js?view=markup await mw.loader.using([ "ext.gadget.jquery.ui", "mediawiki.util", "mediawiki.user", "user.options", // for sig "ext.gadget.libUtil", "ext.gadget.libJQuery", ]); const builtinTemplate = [ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * Append new messages at the bottom. Otherwise pre-selection for users will break. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ // ['Template name', "Name in Sidebar", "Detailed text", Type/Prompt statement, 'Talk summary']; ["模板:预加载警告/繁简输入", "用户进行了错误的繁体输入", "用户在简体模式下输入繁体编辑条目", umsg.umFlagUM, "用户违反编辑规则警告", 0], ["模板:预加载警告/针对条目的评论违规", "用户针对条目的评论违规", "用户认为条目不客观,并嘲讽攻击本站或编辑者", umsg.umFlagUM, "用户违反评论规则警告", umsg.umFlagP2], ["模板:预加载警告/针对用户的评论违规", "用户回复其他用户的评论违规", "用户在评论区辱骂攻击其他用户", umsg.umFlagUM, "用户违反评论规则警告", umsg.umFlagP2], ["模板:预加载警告/忍耐是有限的", "对用户的忍耐已达极限", "用户进行了相当数量的违反编辑规范的操作", umsg.umFlagUM, "用户违反编辑规范警告", 0], ]; const placeholderTemplate = ["", "请选择警告类型", "其他类型", umsg.umFlagUM, " ", 0]; Object.defineProperties(umsg, { umTemplate: { get: () => { if (!Array.isArray(window.AxUserMsgCustomTemplate)) { window.AxUserMsgCustomTemplate = []; } const result = [ ...window.AxUserMsgUseBuiltinTemplate !== false ? builtinTemplate : [], ...window.AxUserMsgCustomTemplate, placeholderTemplate, ]; result.push = (...args) => window.AxUserMsgCustomTemplate.push(...args); return result; }, configurable: false, enumerable: true, }, umSelect: { get: () => { if (Number.isSafeInteger(window.AxUserMsgPreSelect) && window.AxUserMsgPreSelect >= 0 && window.AxUserMsgPreSelect < umsg.umTemplate.length) { return window.AxUserMsgPreSelect; } return umsg.umTemplate.indexOf(placeholderTemplate); }, configurable: false, enumerable: true, }, }); $(() => { initCombobox($); umsg.umInstall(); if (window.installOldLinks) { umsg.umInstallOldLinks(); } $(document).triggerHandler("scriptLoaded", ["AxUserMsg", umsg]); }); } })(); //</nowiki>
返回
MediaWiki:AxUserMsg.js
。