MediaWiki:Gadget-AdvancedSiteNotices.js:修订间差异

删除的内容 添加的内容
创建页面,内容为“// <nowiki> /* * **************************************************************************** * * >>>>> 小工具导入者:导入前请阅读 <<<<< * * * 请确保通告页面 (Template:AdvancedSiteNotices/ajax) * * * 在您的维基上已受到适当保护。 * * * 虽然已尽力正确处理 JavaScript 表达式, * * *…”
 
无编辑摘要
 
第1行:
/**
// <nowiki>
* SPDX-License-Identifier: CC-BY-SA-4.0
/*
* _addText: '{{Gadget Header|license=CC-BY-SA-4.0}}'
* ****************************************************************************
* * >>>>> 小工具导入者:导入前请阅读 <<<<< *
* * 请确保通告页面 ([[Template:AdvancedSiteNotices/ajax]]) *
* * 在您的维基上已受到适当保护。 *
* * 虽然已尽力正确处理 JavaScript 表达式, *
* * 但它们未经充分的实战测试。 *
* ****************************************************************************
*
* @base {@link https://zh.wikipedia.org/wiki/MediaWiki:Gadget-AdvancedSiteNotices.js}
* @source {@link https://git.qiuwen.net.cn/InterfaceAdmin/QiuwenGadgets/src/branch/master/src/AdvancedSiteNotices}
* @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> */
 
(() => {
Promise.all([
$.ready
]).then(() => {
const geo = null; // 明确设为 null,兼容后续逻辑
if (
$("#siteNotice").length < 0 ||
mw.config.get("wgAction") === "edit" ||
mw.config.get("wgAction") === "submit"
) {
return;
}
 
"use strict";
const { conv } = require("ext.gadget.HanAssist");
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
 
// node_modules/.pnpm/broadcastchannel-polyfill@1.0.1/node_modules/broadcastchannel-polyfill/index.js
let customASNInterval = window.customASNInterval || 15;
var require_broadcastchannel_polyfill = __commonJS({
const COOKIE_NAME = "dismissASN";
"node_modules/.pnpm/broadcastchannel-polyfill@1.0.1/node_modules/broadcastchannel-polyfill/index.js"() {
let cookieVal = Number.parseInt(mw.cookie.get(COOKIE_NAME) || "-1", 10);
(function(global) {
let revisionId = 0;
let timeoutId var channels = null[];
function BroadcastChannel2(channel) {
 
var $this = this;
let $asnRoot = $("<div>", { id: "asn-dismissable-notice" });
let $asnBody channel = $String("<div>", {channel);
var id = "$BroadcastChannel$" + channel + "$";
id: "advancedSiteNotices",
class:channels[id] "mw-parser-output",= channels[id] || [];
channels[id].push(this);
});
this._name = channel;
let $asnClose = $("<button>", {
this._id = id;
title: conv({ hans: "关闭", hant: "關閉" }),
this._closed = false;
"aria-label": conv({ hans: "关闭", hant: "關閉" }),
class:this._mc "asn-close-button",= new MessageChannel();
this._mc.port1.start();
});
this._mc.port2.start();
 
global.addEventListener("storage", function(e) {
$asnRoot.append($asnBody, $asnClose);
if (e.storageArea !== global.localStorage) return;
$asnClose.click(() => {
if (e.newValue == null || e.newValue === "") return;
$asnClose.prop("disabled", true);
if (e.key.substring(0, id.length) !== id) return;
mw.cookie.set(COOKIE_NAME, revisionId, {
var data expires:= 60 * 60 * 24 * 30,JSON.parse(e.newValue);
path: "/",$this._mc.port2.postMessage(data);
secure: true,
});
}
clearTimeout(timeoutId);
$asnRootBroadcastChannel2.fadeOut(()prototype => {
// BroadcastChannel $asnRoot.remove();API
}get name(); {
return this._name;
});
},
 
postMessage: function(message) {
/**
var $this = this;
* @typedef {Object} TokenizeStatus
if (this._closed) {
* @property {string} expression
var e = new Error();
* @property {RegExp} startTokenRe
e.name = "InvalidStateError";
* @property {number} index
throw e;
* @property {((item: any) => void) & { __orig__?: (item: any) => void }} append
*/ }
var value = JSON.stringify(message);
 
var key = this._id + String(Date.now()) + "$" + String(Math.random());
/**
global.localStorage.setItem(key, value);
* 条件解析器。仅支持 JavaScript 的一个小子集。
setTimeout(function() {
*/
global.localStorage.removeItem(key);
class CriteriaExecutor {
/** }, 500);
channels[this._id].forEach(function(bc) {
* @param {Record<string, (...args: any[]) => any>} functions
*/ if (bc === $this) return;
bc._mc.port2.postMessage(JSON.parse(value));
constructor(functions = {}) {
this.functions = functions});
},
close: function() {
if (this._closed) return;
this._closed = true;
this._mc.port1.close();
this._mc.port2.close();
var index = channels[this._id].indexOf(this);
channels[this._id].splice(index, 1);
},
// EventTarget API
get onmessage() {
return this._mc.port1.onmessage;
},
set onmessage(value) {
this._mc.port1.onmessage = value;
},
addEventListener: function() {
return this._mc.port1.addEventListener.apply(this._mc.port1, arguments);
},
removeEventListener: function() {
return this._mc.port1.removeEventListener.apply(this._mc.port1, arguments);
},
dispatchEvent: function() {
return this._mc.port1.dispatchEvent.apply(this._mc.port1, arguments);
}
};
global.BroadcastChannel = global.BroadcastChannel || BroadcastChannel2;
})(self);
}
});
 
// dist/AdvancedSiteNotices/AdvancedSiteNotices.js
/**
require_broadcastchannel_polyfill();
* 将表达式解析为标记
function asyncGeneratorStep(n, t, e, r, o, a, c) {
*
try {
* @param {string} expression
var i = n[a](c), u *= @return {any[]}i.value;
} catch (n2) */{
return void e(n2);
_tokenizeExpression(expression) {
}
expression = expression.trim();
i.done ? t(u) : Promise.resolve(u).then(r, o);
if (!expression) {
}
return [];
function _asyncToGenerator(n) {
}
return function() {
 
var t = this, const resulte = []arguments;
return new Promise(function(r, o) {
/** @type {TokenizeStatus} */
var a = n.apply(t, const status = {e);
function _next(n2) {
expression,
asyncGeneratorStep(a, r, o, _next, _throw, "next", n2);
startTokenRe: /\|\||&&|\b(?:true|false)\b|[('"!\s]/g,
index: 0,}
function append_throw(itemn2) {
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n2);
result.push(item);
},
_next(void }0);
});
let match = status.startTokenRe.exec(expression);
};
 
}
const skipSpace = () => {
function _createForOfIteratorHelper(r, e) {
while (/\s/.test(expression[status.index] || "")) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
status.index++;
if (!t) {
}
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
};
t && (r = t);
 
var n = 0, F = while function(match) {
};
const token = match[0];
return { s: F, n: function() {
 
return n >= r.length ? { done: true } : { done: false, value: r[n++] };
if (status.startTokenRe.lastIndex - token.length !== status.index) {
}, e: if (token === "function("r2) {
throw r2;
// 处理函数调用
}, f: F };
const parsed = this._handleFunctionCall(status);
if (!parsed) {
break;
}
} else {
break;
}
} else {
let parsed = false;
switch (token) {
case "(":
parsed = this._handleExpressionStatement(status);
break;
case "||":
case "&&":
parsed = this._handleLogicalOperator(status, token);
break;
case "!":
parsed = this._handleUnaryExpression(status, token);
break;
case "'":
case '"':
parsed = this._handleStringLiteral(status, token);
break;
case "true":
case "false":
parsed = this._handleBooleanLiteral(status, token);
break;
}
if (!parsed) {
break;
}
}
 
skipSpace();
status.startTokenRe.lastIndex = status.index;
match = status.startTokenRe.exec(expression);
}
 
if (status.index < expression.length - 1) {
throw new SyntaxError("Unexpected token.");
}
 
return result;
}
 
/**
* 处理函数调用
*
* @param {TokenizeStatus} status
* @return {boolean}
*/
_handleFunctionCall(status) {
const functionName = status.expression
.slice(status.index, status.startTokenRe.lastIndex - 1)
.trim();
 
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(functionName)) {
return false;
}
 
const argsStartIndex = status.startTokenRe.lastIndex - 1;
const endIndex = this._findNextBalanceItem(
status.expression,
"(",
")",
argsStartIndex
);
if (endIndex === -1) {
throw new SyntaxError("Unbalanced parentheses in function call");
}
 
const rawArgs = status.expression
.slice(argsStartIndex + 1, endIndex)
.trim();
const args = !rawArgs.length
? []
: this._balanceSplit(rawArgs, ",", "(", ")");
 
status.append({
type: "FunctionCall",
functionName,
args: args.map((arg) => this._tokenizeExpression(arg)),
});
status.index = endIndex + 1;
return true;
}
 
/**
* 处理逻辑运算符
*
* @param {TokenizeStatus} status
* @param {string} token
* @return {boolean}
*/
_handleLogicalOperator(status, token) {
status.append({
type: "LogicalExpression",
operator: token,
});
status.index = status.startTokenRe.lastIndex;
return true;
}
 
/**
* 处理一元表达式
*
* @param {TokenizeStatus} status
* @param {string} token
* @return {boolean}
*/
_handleUnaryExpression(status, token) {
const item = {
type: "UnaryExpression",
operator: token,
argument: undefined,
};
status.append(item);
const origAppend = status.append.__orig__ || status.append;
status.append = function (nextItem) {
if (nextItem.type === "LogicalExpression") {
throw new SyntaxError("Unexpected LogicalExpression");
}
item.argument = nextItem;
status.append = origAppend;
};
status.append.__orig__ = origAppend;
status.index = status.startTokenRe.lastIndex;
return true;
}
 
/**
* 处理布尔值字面量
*
* @param {TokenizeStatus} status
* @param {string} token
* @return {boolean}
*/
_handleBooleanLiteral(status, token) {
status.append({
type: "BooleanLiteral",
value: token === "true",
});
status.index = status.startTokenRe.lastIndex;
return true;
}
 
/**
* 处理表达式语句
*
* @param {TokenizeStatus} status
* @return {boolean}
*/
_handleExpressionStatement(status) {
const endIndex = this._findNextBalanceItem(
status.expression,
"(",
")",
status.index
);
if (endIndex === -1) {
throw new SyntaxError("Unbalanced parentheses in expression.");
}
status.append({
type: "ExpressionStatement",
expression: this._tokenizeExpression(
status.expression.slice(status.index + 1, endIndex)
),
});
status.index = endIndex + 1;
return true;
}
 
/**
* 处理字符串字面量
*
* @param {TokenizeStatus} status
* @param {string} delimiter
* @return {boolean}
*/
_handleStringLiteral(status, delimiter) {
const endIndex = this._findNextTokenWithoutEscape(
status.expression,
delimiter,
status.index + 1
);
if (endIndex === -1) {
throw new SyntaxError("Unterminated string literal.");
}
status.append({
type: "StringLiteral",
value: this._parseString(
status.expression.slice(status.index + 1, endIndex)
),
});
status.index = endIndex + 1;
return true;
}
 
/**
* 查找下一个平衡项
*
* @param {string} expression
* @param {string} startToken
* @param {string} endToken
* @param {number} currentIndex
* @return {number}
*/
_findNextBalanceItem(expression, startToken, endToken, currentIndex) {
let count = 1;
while (++currentIndex < expression.length) {
if (expression[currentIndex] === startToken) {
count++;
} else if (expression[currentIndex] === endToken) {
count--;
}
if (count === 0) {
return currentIndex;
}
}
return -1;
}
 
/**
* 分割平衡子表达式
*
* @param {string} expression
* @param {string} startToken
* @param {string} endToken
* @param {string} splitToken
* @return {string[]}
*/
_balanceSplit(expression, splitToken, startToken, endToken) {
const result = [];
let balance = 0;
let current = "";
for (const char of expression) {
if (char === startToken) {
balance++;
} else if (char === endToken) {
balance--;
}
if (char === splitToken && balance === 0) {
result.push(current.trim());
current = "";
} else {
current += char;
}
}
if (current) {
result.push(current.trim());
}
return result;
}
 
/**
* 查找未转义的标记
*
* @param {string} expression
* @param {string} token
* @param {number} currentIndex
* @return {number}
*/
_findNextTokenWithoutEscape(expression, token, currentIndex) {
while (currentIndex < expression.length) {
const foundIndex = expression.indexOf(token, currentIndex);
if (foundIndex === -1) {
return -1;
} else if (expression[foundIndex - 1] !== "\\") {
return foundIndex;
}
currentIndex = foundIndex + 1;
}
return -1;
}
 
/**
* 解析字符串并处理转义字符
*
* @param {string} input
* @return {string}
*/
_parseString(input) {
return input.replace(
/\\(n|t|r|b|f|x[0-9A-Fa-f]{2}|u\{[0-9A-Fa-f]+\}|u[0-9A-Fa-f]{4}|.)/g,
(_, esc) => {
switch (esc[0]) {
case "n":
return "\n";
case "t":
return "\t";
case "r":
return "\r";
case "b":
return "\b";
case "f":
return "\f";
case "x":
if (esc === "x") {
throw new SyntaxError("Invalid hexadecimal escape sequence.");
}
return String.fromCharCode(parseInt(esc.slice(1), 16));
case "u":
if (esc === "u") {
throw new SyntaxError("Invalid Unicode escape sequence.");
} else if (esc[1] === "{") {
const codePoint = Number.parseInt(esc.slice(2, -1), 16);
if (codePoint > 0x10ffff) {
throw new SyntaxError(
`Undefined Unicode code-point: \\${esc}.`
);
}
return String.fromCodePoint(codePoint);
}
return String.fromCharCode(Number.parseInt(esc.slice(1), 16));
default:
return esc;
}
}
);
}
 
/**
* @param {any[]} tokens
*/
_tokensToAst(tokens) {
if (!tokens.length) {
throw new TypeError("Token list is empty.");
}
// 先處理 && 再處理 ||
let logicalItemIndex = tokens.findIndex((t) => t.type === "LogicalExpression" && t.operator === '&&');
if (logicalItemIndex === -1) {
logicalItemIndex = tokens.findIndex((t) => t.type === "LogicalExpression" && t.operator === '||');
}
 
if (logicalItemIndex === -1) {
if (tokens.length === 1) {
return this._tokenToAst(tokens[0]);
}
throw new SyntaxError(`Unexpected ${tokens[1].type}.`);
} else if (logicalItemIndex === 0) {
throw new SyntaxError(`Unexpected LogicalExpression`);
} else {
const left = this._tokensToAst(tokens.slice(0, logicalItemIndex));
const right = this._tokensToAst(tokens.slice(logicalItemIndex + 1));
return {
type: "LogicalExpression",
operator: tokens[logicalItemIndex].operator,
left,
right,
};
}
}
 
/**
* @param {any} token
*/
_tokenToAst(token) {
if (!token) {
throw new TypeError('token is undefined or null.');
}
const result = Object.assign({}, token);
if (token.type === "UnaryExpression") {
if (!result.argument) {
throw new SyntaxError("Unexpected UnaryExpression.");
}
result.argument = this._tokenToAst(token.argument);
} else if (token.type === "FunctionCall") {
result.args = token.args.map((argument) =>
this._tokensToAst(argument)
);
} else if (token.type === "ExpressionStatement") {
result.expression = this._tokensToAst(token.expression);
}
return result;
}
 
/**
* @param {string} expression
*/
toAst(expression) {
const tokenizes = this._tokenizeExpression(expression);
return this._tokensToAst(tokenizes);
}
 
/**
* @param {string} functionName
* @param {any[]} args
*/
_executeFunction(functionName, args) {
if (!Object.prototype.hasOwnProperty.call(this.functions, functionName)) {
throw new Error(`Function ${functionName} is not allowed.`);
}
return this.functions[functionName](...args);
}
 
/**
* @param {any} ast
*/
evaluate(ast) {
switch (ast.type) {
case "ExpressionStatement":
return this.evaluate(ast.expression);
 
case "UnaryExpression":
if (ast.operator === "!") {
return !this.evaluate(ast.argument);
}
throw new Error(`Unknown UnaryExpression operator: ${ast.operator}`);
 
case "LogicalExpression":
if (ast.operator === "&&" || ast.operator === "||") {
const left = this.evaluate(ast.left);
if (ast.operator === "&&" && !left) {
return false;
} else if (ast.operator === "||" && left) {
return true;
}
return this.evaluate(ast.right);
}
throw new Error(`Unknown LogicalExpression operator: ${ast.operator}`);
 
case "FunctionCall":
const args = ast.args.map((arg) => this.evaluate(arg));
let returnValue = this._executeFunction(ast.functionName, args);
if (typeof returnValue === 'undefined' || returnValue === null) {
returnValue = false;
} else if (typeof returnValue !== 'string' && typeof returnValue !== 'boolean') {
console.warn(
'[AdvancedSiteNotices]: The return type %s of the function %s() is unsafe and has been forcibly converted to a string.',
typeof returnValue,
ast.functionName
);
returnValue = String(returnValue);
}
return returnValue;
 
case "StringLiteral":
case "BooleanLiteral":
return ast.value;
 
default:
throw new Error(`Unknown AST node type: ${ast.type}`);
}
}
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
 
}
const functions = {};
var o, a = true, u = false;
 
return { s: function() {
// 帶參數
ift = t.call(geor) {;
}, n: function() {
functions.in_country = (...counties) => counties.includes(geo.country);
var r2 = t.next();
functions.in_region = (...regions) => regions.includes(geo.region);
return a = r2.done, r2;
functions.in_city = (...cities) => cities.includes(geo.city);
}, e: } elsefunction(r2) {
u = true, o = r2;
// 无 geoIP 时,跳过地区筛选(或改为 return false 禁用)
}, f: function() {
functions.in_country = functions.in_region = functions.in_city = (...args) => args.length ? true : false;
try {
a || null == t.return || t.return();
} finally {
if (u) throw o;
}
} };
const configs = mw.config.get(["wgUserGroups", "wgUserLanguage"]);
}
functions.in_group = (...groups) => groups.some(group => configs.wgUserGroups.includes(group));
function _unsupportedIterableToArray(r, a) {
functions.in_group_every = (...groups) => groups.every(group => configs.wgUserGroups.includes(group));
if (r) {
functions.in_lang = (...useLangs) => useLangs.includes(configs.wgUserLanguage);
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;
// 錯誤示範:
}
// functions.is_anon = mw.user.isAnon; // 不安全,無法確定 mw.user.isAnon 是否有被修改過可以傳奇怪的值進去
}
// functions.is_anon = () => mw.user.isAnon(); // 不安全,返回值為 boolean 的,只要無法保證一定返回 boolean,就應該全部強制轉換成 boolean
function _arrayLikeToArray(r, a) {
functions.is_anon = () => !!mw.user.isAnon();
(null == a || a > r.length) && (a = r.length);
// 支持较旧的 MediaWiki 版本(通常是其他维基)
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
// mw.user.isTemp 和 mw.user.isNamed 在 MediaWiki 1.40 中添加
return n;
functions.is_temp = () => typeof mw.user.isTemp === "function" ? !!mw.user.isTemp() : false;
}
functions.is_named = () => typeof mw.user.isNamed === "function" ? !!mw.user.isNamed() : !mw.user.isAnon();
var __create = Object.create;
 
var __defProp = Object.defineProperty;
const parser = new CriteriaExecutor(functions);
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
 
var __getOwnPropNames2 = Object.getOwnPropertyNames;
const cache = new WeakMap();
var __getProtoOf = Object.getPrototypeOf;
function getCache($element, key) {
var __hasOwnProp = Object.prototype.hasOwnProperty;
const element = $element.get(0);
var __copyProps = (to, from, except, desc) => {
if (cache.has(element)) {
if (from && typeof from === "object" || typeof from === "function") {
return cache.get(element)[key];
var _iterator = _createForOfIteratorHelper(__getOwnPropNames2(from)), _step;
}
try {
for (_iterator.s(); !(_step = _iterator.n()).done; ) {
let key = _step.value;
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
function setCache($element, key, value) {
return to;
const element = $element.get(0);
};
if (cache.has(element)) {
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
cache.get(element)[key] = value;
// If the importer is in node compatibility mode or this is not an ESM
} else {
// file that has been converted to a CommonJS file using a Babel-
cache.set(element, {
// compatible transform (i.e. "__esModule" has not been set), then set
[key]: value,
// "default" to the CommonJS "module.exports" for node compatibility.
});
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
}
value: mod,
enumerable: true
}) : target,
mod
));
//! src/AdvancedSiteNotices/options.json
var ajaxPageTitle = "Template:AdvancedSiteNotices/ajax";
var mountPointSelector = "#siteNotice";
var storageKey = "ext.gadget.AdvancedSiteNotices_dismissASN";
var cacheKey = "ext.gadget.AdvancedSiteNotices_cache";
var version = "4.0";
//! src/AdvancedSiteNotices/AdvancedSiteNotices.ts
var import_ext_gadget7 = require("ext.gadget.Util");
//! src/AdvancedSiteNotices/modules/api.ts
var import_ext_gadget = require("ext.gadget.Util");
var api = (0, import_ext_gadget.initMwApi)("AdvancedSiteNotices/".concat(version));
//! src/AdvancedSiteNotices/modules/util/queryApi.ts
var {
wgUserLanguage
} = mw.config.get();
var parameters = {
action: "parse",
format: "json",
formatversion: "2",
prop: "text",
page: ajaxPageTitle,
uselang: wgUserLanguage,
variant: wgUserLanguage,
smaxage: 600,
maxage: 600
};
var queryApi = /* @__PURE__ */ (function() {
var _ref = _asyncToGenerator(function* () {
try {
let response;
if (mw.storage.getObject(cacheKey)) {
response = mw.storage.getObject(cacheKey);
} else {
response = yield api.get(parameters);
mw.storage.setObject(cacheKey, response, 60 * 10);
}
return response;
} catch (error) {
console.error("[AdvancedSiteNotices] Ajax error:", error);
return {};
}
});
 
return function matchCriteriaqueryApi2($noticeItem) {
return _ref.apply(this, arguments);
let cache = getCache($noticeItem, "asn-cache");
};
if (cache !== undefined) {
})();
return cache;
//! src/AdvancedSiteNotices/modules/loadRemoteNotices.tsx
}
var import_ext_gadget2 = __toESM(require("ext.gadget.JSX"), 1);
let criteria = $noticeItem.attr("data-asn-criteria");
var loadRemoteNotices = /* @__PURE__ */ (function() {
let result;
var _ref2 = _asyncToGenerator(function* () {
if (criteria !== undefined) {
const response = yield queryApi();
if (criteria === "") {
const responseParse = response["parse"];
result = true;
if (!(responseParse !== null && responseParse !== void 0 && responseParse.text)) {
} else {
tryreturn {};
criteria = decodeURIComponent(criteria.replace(/\+/g, "%20")).trim();
const ast = parser.toAst(criteria);
result = !!parser.evaluate(ast);
} catch (error) {
console.warn(
'[AdvancedSiteNotices]: Fail to parse or evaluate criteria "%s":',
criteria,
error
);
result = false;
}
}
} else {
const testList = [];
if ($noticeItem.hasClass("only_sysop")) {
testList.push(functions.in_group("sysop"));
}
if (
$noticeItem.hasClass("only_logged_in") ||
$noticeItem.hasClass("only_logged") /* 已弃用 */ ||
$noticeItem.hasClass("is_named")
) {
testList.push(functions.is_named());
}
if (
$noticeItem.hasClass("only_logged_out") ||
$noticeItem.hasClass("only_anon") /* 已弃用 */
) {
testList.push(!functions.is_named());
}
if ($noticeItem.hasClass("is_temp")) {
testList.push(functions.is_temp());
}
if ($noticeItem.hasClass("is_anon")) {
testList.push(functions.is_anon());
}
if ($noticeItem.hasClass("only_zh_cn")) {
testList.push(functions.in_lang("zh-cn"));
}
if ($noticeItem.hasClass("only_zh_hk")) {
testList.push(functions.in_lang("zh-hk"));
}
if ($noticeItem.hasClass("only_zh_sg")) {
testList.push(functions.in_lang("zh-sg"));
}
if ($noticeItem.hasClass("only_zh_tw")) {
testList.push(functions.in_lang("zh-tw"));
}
result = !testList.length || testList.every((v) => !!v);
}
 
setCache($noticeItem, "asn-cache", result);
return result;
}
const remoteNotice = (/* @__PURE__ */ import_ext_gadget2.default.createElement("div", {
 
innerHTML: responseParse.text
function getNoticeElement($noticeItem) {
})).querySelector("ul.sitents");
let $cache = getCache($noticeItem, "asn-element");
if ($cache !== undefinedremoteNotice) {
return $cache{};
}
 
$cache = $("<div>").append($noticeItem.contents().clone());
setCache($noticeItem, "asn-element", $cache);
return $cache;
}
const $remoteNotices = $(remoteNotice);
 
const $notices2 = $remoteNotices.find("li");
let isSetMinHeightCalled = false;
const remoteNoticesVersion = $remoteNotices.data("asn-version").toString();
 
/**return {
$notices: $notices2,
* 设置 ASN 的高度为所有条目的最大高度,以防止在切换时出现大量布局偏移。
version: remoteNoticesVersion
*/
};
function setMinHeight($noticeList) {
});
let minHeight = -1;
return function loadRemoteNotices2() {
$noticeList.each((_, nt) => {
return _ref2.apply(this, arguments);
let $nt = $(nt);
};
$asnBody.replaceWith($nt);
})();
minHeight = Math.max(minHeight, $nt.height());
//! src/AdvancedSiteNotices/modules/constant.ts
$nt.replaceWith($asnBody);
var CLASS_NAME = "gadget-advanced_site_notices";
});
var CLASS_NAME_DISMISS = "".concat(CLASS_NAME, "__dismiss");
 
var CLASS_NAME_NOTICE = "".concat(CLASS_NAME, "__notice");
$asnRoot.css("min-height", `${minHeight}px`);
var CLASS_NAME_NOTICE_CONTENT = "".concat(CLASS_NAME_NOTICE, "__content");
 
var CLASS_NAME_TITLE = "".concat(CLASS_NAME, "__title");
if (!isSetMinHeightCalled) {
//! src/AdvancedSiteNotices/modules/showNotice.tsx
isSetMinHeightCalled = true;
var import_ext_gadget5 = __toESM(require("ext.gadget.JSX"), 1);
window.addEventListener(
//! src/AdvancedSiteNotices/modules/util/generateArea.tsx
"resize",
var import_ext_gadget4 = __toESM(require("ext.gadget.JSX"), 1);
mw.util.debounce(() => setMinHeight($noticeList), 300)
//! src/AdvancedSiteNotices/modules/i18n.ts
);
var import_ext_gadget3 = require("ext.gadget.i18n");
}
var getI18nMessages = () => {
return {
Dismiss: (0, import_ext_gadget3.localize)({
en: "Turn off this notice",
ja: "ASNをオフにする",
"zh-hans": "关闭公告",
"zh-hant": "關閉公告"
}),
DismissNotice: (0, import_ext_gadget3.localize)({
en: "You have chosen to turn off Advanced Site Notices for the next 30 days. <br>If the site-wide announcement is not updated within the next 30 days, it will no longer be displayed; however, if the site-wide announcement is updated, it will be displayed again.",
ja: "今後30日間、ASNをオフにすることを選択しました。<br>サイト全体の通知が今後30日以内に更新されない場合、表示されなくなります。ただし、サイト全体の通知が更新される場合は、再び表示されます。",
"zh-hans": "您已选择在接下来30日内关闭“高级站点通告”。<br>若接下来30日内全站公告未有更新,则不再显示;但是,若全站公告内容更新,则将重新显示。",
"zh-hant": "您已選擇在接下來30日內關閉「高級站點通告」。<br>若接下來30日內全站公告未有更新,則不再顯示;但是,若全站公告內容更新,則將重新顯示。"
}),
Title: (0, import_ext_gadget3.localize)({
en: "Announcement",
ja: "通知",
zh: "公告"
})
};
};
var i18nMessages = getI18nMessages();
var getMessage = (key) => {
return i18nMessages[key] || key;
};
//! src/AdvancedSiteNotices/modules/util/generateArea.tsx
var generateArea = () => {
const area = /* @__PURE__ */ import_ext_gadget4.default.createElement("div", {
className: [CLASS_NAME, "noprint"]
}, /* @__PURE__ */ import_ext_gadget4.default.createElement("div", {
className: CLASS_NAME_TITLE
}, getMessage("Title")), /* @__PURE__ */ import_ext_gadget4.default.createElement("div", {
className: CLASS_NAME_NOTICE
}, /* @__PURE__ */ import_ext_gadget4.default.createElement("div", {
className: [CLASS_NAME_NOTICE_CONTENT, "center"]
})), /* @__PURE__ */ import_ext_gadget4.default.createElement("div", {
className: CLASS_NAME_DISMISS
}, /* @__PURE__ */ import_ext_gadget4.default.createElement("a", {
role: "button",
"aria-label": getMessage("Dismiss")
})));
return $(area);
};
//! src/AdvancedSiteNotices/modules/util/matchCriteria.ts
var {
wgUserGroups,
wgGlobalGroups,
wgUserLanguage: wgUserLanguage2
} = mw.config.get();
var in_group = (group) => {
return !!(wgUserGroups !== null && wgUserGroups !== void 0 && wgUserGroups.includes(group) || wgGlobalGroups !== null && wgGlobalGroups !== void 0 && wgGlobalGroups.includes(group));
};
var only_for = (userLanguage) => {
return userLanguage === wgUserLanguage2;
};
var matchCriteria = ($notice) => {
var _$notice$data;
const cache = $notice.data("asn-cache");
if (cache !== void 0) {
return cache;
}
const testCriteria = (criteria) => {
try {
return window.eval(criteria);
} catch {
return false;
}
};
 
let result = false;
function loadNotice($noticeList, pos) {
const criteriaData = ((_$notice$data = $notice.data("asn-criteria")) !== null && _$notice$data !== void 0 ? _$notice$data : "").trim();
const $noticeItem = $noticeList.eq(pos);
if (criteriaData) {
let nextPos = pos + 1;
try {
if (nextPos === $noticeList.length) {
result = testCriteria(decodeURIComponent(criteriaData.replace(/\+/g, "%20")));
nextPos = 0;
} catch }{
result = true;
 
const $noticeElement = getNoticeElement($noticeItem);
if ($asnBody.children().length) {
$asnBody.stop().fadeOut(() => {
$asnBody.empty().append($noticeElement);
// 动画 try/catch 以避免 TypeError: (Animation.tweeners[prop]||[]).concat is not a function 错误在生产环境中出现
try {
$asnBody.fadeIn();
} catch (_) { }
});
} else {
$asnBody.append($noticeElement).fadeIn();
}
 
if ($noticeList.length > 1) {
timeoutId = setTimeout(() => {
loadNotice($noticeList, nextPos);
}, customASNInterval * 1000);
}
}
} else if ($notice.attr("class")) {
 
let criteria;
function initialNotices($noticeList) {
if ($notice.hasClass("only_sysop")) {
if (!$asnRoot.length || !$noticeList.length || revisionId === cookieVal) {
criteria || (criteria = returnin_group("sysop"));
}
if ($notice.hasClass("only_logged")) {
 
criteria || (criteria = in_group("user"));
mw.cookie.set(COOKIE_NAME, null);
}
$asnRoot.appendTo($("#siteNotice"));
if ($notice.hasClass("only_anon")) {
setMinHeight($noticeList);
criteria || (criteria = !in_group("user"));
 
loadNotice($noticeList, Math.floor(Math.random() * $noticeList.length));
}
if ($notice.hasClass("only_zh_cn")) {
criteria || (criteria = only_for("zh-cn"));
}
if ($notice.hasClass("only_zh_sg")) {
criteria || (criteria = only_for("zh-sg"));
}
if ($notice.hasClass("only_zh_my")) {
criteria || (criteria = only_for("zh-my"));
}
if ($notice.hasClass("only_zh_hk")) {
criteria || (criteria = only_for("zh-hk"));
}
if ($notice.hasClass("only_zh_mo")) {
criteria || (criteria = only_for("zh-mo"));
}
if ($notice.hasClass("only_zh_tw")) {
criteria || (criteria = only_for("zh-tw"));
}
if (criteria === void 0) {
criteria = true;
}
result = criteria;
} else {
result = true;
}
$notice.data("asn-cache", result);
return result;
};
//! src/AdvancedSiteNotices/modules/showNotice.tsx
var import_ext_gadget6 = require("ext.gadget.Tippy");
var broadcastChannel = new BroadcastChannel(storageKey);
var currentVersion = "0";
var localVersion = mw.storage.get(storageKey);
var timer;
var $area = generateArea();
var $currentNotice = $area.find(".".concat(CLASS_NAME_NOTICE_CONTENT));
var $dismiss = $area.find(".".concat(CLASS_NAME_DISMISS)).find("a");
var closeNotices = () => {
broadcastChannel.postMessage("close");
broadcastChannel.close();
clearTimeout(timer);
$area.remove();
mw.storage.set(storageKey, currentVersion, 60 * 60 * 24 * 30);
};
broadcastChannel.addEventListener("message", closeNotices);
$dismiss.on("click", () => {
closeNotices();
void mw.notify($(/* @__PURE__ */ import_ext_gadget5.default.createElement("span", {
innerHTML: getMessage("DismissNotice")
})), {
tag: "AdvancedSiteNotices"
});
});
(0, import_ext_gadget6.tippy)($dismiss.get(0), {
arrow: true,
content: $dismiss.attr("aria-label"),
placement: "bottom"
});
var $notices;
var noticeStyles = [];
var showNotices = ($mountPoint, index, remoteNotices) => {
var _remoteNotices$versio;
currentVersion = (_remoteNotices$versio = remoteNotices === null || remoteNotices === void 0 ? void 0 : remoteNotices.version) !== null && _remoteNotices$versio !== void 0 ? _remoteNotices$versio : currentVersion;
if (currentVersion === localVersion) {
return;
}
if (remoteNotices !== null && remoteNotices !== void 0 && remoteNotices.$notices) {
({
$notices
} = remoteNotices);
}
const noticesLength = $notices.length;
const nextNoticeIndex = (index + 1) % noticesLength;
let $notice = $();
let i = 0;
while (i++ < noticesLength) {
$notice = $notices.eq(index);
if (!matchCriteria($notice)) {
showNotices($mountPoint, nextNoticeIndex);
return;
}
index = index++ % noticesLength;
}
if (typeof $notice.data("asn-html") === "string") {
$notice.data("asn-html-raw", decodeURIComponent($notice.data("asn-html").replace(/\+/g, "%20")));
$notice.data("asn-html", null);
}
if (typeof $notice.data("asn-style") === "string") {
$notice.data("asn-style-id", noticeStyles.length);
const style = mw.loader.addStyleTag(decodeURIComponent($notice.data("asn-style").replace(/\+/g, "%20")));
style.disabled = true;
noticeStyles[noticeStyles.length] = style;
$notice.data("asn-style", null);
}
const noticeHtml = $notice.data("asn-html-raw") || $notice.html();
const noticeStyleId = $notice.data("asn-style-id");
const currentNoticeHtml = $currentNotice.html();
if (currentNoticeHtml && currentNoticeHtml !== noticeHtml) {
$currentNotice.stop().fadeOut(() => {
for (var _i = 0, _noticeStyles = noticeStyles; _i < _noticeStyles.length; _i++) {
const style = _noticeStyles[_i];
style.disabled = true;
}
const noticeStyle = noticeStyles[noticeStyleId];
if (noticeStyle) {
noticeStyle.disabled = false;
}
$currentNotice.html(noticeHtml);
try {
$currentNotice.fadeIn();
} catch {
}
});
} else if (!currentNoticeHtml) {
$mountPoint.append($area);
const noticeStyle = noticeStyles[noticeStyleId];
if (noticeStyle) {
noticeStyle.disabled = false;
}
$currentNotice.html(noticeHtml).fadeIn();
}
timer = setTimeout(() => {
showNotices($mountPoint, nextNoticeIndex);
}, 7 * 1e3);
};
//! src/AdvancedSiteNotices/AdvancedSiteNotices.ts
(function() {
var _advancedSiteNotices = _asyncToGenerator(function* () {
var _remoteNotices$$notic;
const $body = yield (0, import_ext_gadget7.getBody)();
const $mountPoint = $body.find(mountPointSelector);
if (!$mountPoint.length) {
return;
}
const remoteNotices = yield loadRemoteNotices();
if (!((_remoteNotices$$notic = remoteNotices.$notices) !== null && _remoteNotices$$notic !== void 0 && _remoteNotices$$notic.length)) {
return;
}
const randomIndex = Math.floor(Math.random() * remoteNotices.$notices.length);
showNotices($mountPoint, randomIndex, remoteNotices);
});
function advancedSiteNotices() {
return _advancedSiteNotices.apply(this, arguments);
}
return advancedSiteNotices;
})()();
 
})();
new mw.Api({
ajax: {
headers: {
"Api-User-Agent": "w:zh:MediaWiki:Gadget-AdvancedSiteNotices.js",
},
},
})
.parse(new mw.Title("Template:AdvancedSiteNotices/ajax"), {
variant: mw.config.get("wgUserVariant"),
maxage: 3600,
smaxage: 3600,
})
.then((html) => {
let $json = $("ul.sitents", $.parseHTML(html));
let $noticeList = $("li", $json).filter((_, li) => matchCriteria($(li)));
revisionId = $json.data("asn-version");
 
/* </nowiki> */
initialNotices($noticeList);
})
.catch((e) => {
console.error("[AdvancedSiteNotices]: error ", e);
});
});
// </nowiki>