User:Royal Sailor/JS/HKCATool.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/**
* 修改自:https://zh.wikipedia.org/wiki/User:SuperGrey/gadgets/ACGATool/main.js
* 原作者:https://zh.wikipedia.org/wiki/User:SuperGrey
* 原著作权标识:https://opensource.org/licenses/MIT MIT
*/
(function () {
const HKCATool = {
/**
* 維基香港內容獎提名規則。
* @returns {object} 包含規則組的對象。
*/
NominationRules: function () {
return [
{
group: HKCATool.convByVar({
hant: '(1) 內容擴充',
hans: '(1) 内容扩充',
}),
rules: [
{
rule: '1a',
desc: HKCATool.convByVar({
hant: '3000+',
hans: '3000+',
}),
score: 1,
},
{
rule: '1b',
desc: HKCATool.convByVar({
hant: '4750+',
hans: '4750+',
}),
score: 2,
},
{
rule: '1c',
desc: HKCATool.convByVar({
hant: '6500+',
hans: '6500+',
}),
score: 3,
},
{
rule: '1d',
desc: HKCATool.convByVar({
hant: '8250+',
hans: '8250+',
}),
score: 4,
},
{
rule: '1e',
desc: HKCATool.convByVar({
hant: '1萬+',
hans: '1万+',
}),
score: 5,
},
],
},
{
group: HKCATool.convByVar({
hant: '(2) 額外加分',
hans: '(2) 额外加分',
}),
rules: [
{
rule: '2-itn',
desc: HKCATool.convByVar({
hant: '新聞動態',
hans: '新闻动态',
}),
score: 1,
},
{
rule: '2-dyk',
desc: HKCATool.convByVar({
hant: 'DYK',
hans: 'DYK',
}),
score: 1,
},
{
rule: '2-ga',
desc: HKCATool.convByVar({
hant: '優良',
hans: '优良',
}),
score: 5,
},
{
rule: '2-fa',
desc: HKCATool.convByVar({
hant: '典特',
hans: '典特',
}),
score: 10,
},
],
},
];
},
/**
* 提名規則別名。
* @returns {object} 包含別名的對象。
*/
NominationRuleAliases: function () {
return {
'2a': '2-itn',
'2b': '2-dyk',
'2c': '2-ga',
'ga': '2-ga',
'2d': '2-fa',
'fa': '2-fa',
'fl': '2-fa',
};
},
/**
* 提名規則集合。
* @returns {object} 包含規則名稱和規則對象的對象。
*/
NominationRuleSet: function () {
let ruleNames = [];
let ruleDict = {};
for (let ruleGroup of HKCATool.NominationRules()) {
if (ruleGroup.rules) {
for (let ruleSet of ruleGroup.rules) {
ruleNames.push(ruleSet.rule);
ruleDict[ruleSet.rule] = ruleSet;
}
} else if (ruleGroup.tabs) {
for (let tab of ruleGroup.tabs) {
for (let ruleSet of tab.rules) {
ruleNames.push(ruleSet.rule);
ruleDict[ruleSet.rule] = ruleSet;
}
}
}
}
return {
ruleNames: ruleNames,
ruleDict: ruleDict,
};
},
/**
* 獲取排序後的規則狀態。
* @param ruleNames 即 NominationRuleSet().ruleNames。
* @param ruleStatus 規則狀態對象。
* @returns {Array} 包含排序後的規則狀態對象的數組。
*/
getOrderedRuleStatus: function (ruleNames, ruleStatus) {
return ruleNames.filter(rule => ruleStatus.hasOwnProperty(rule)).map(rule => ({rule, ...ruleStatus[rule]}));
},
/**
* 獲取完整的wikitext。
* @param {string} pageName 頁面名稱,默認為「Wikipedia:香港維基人佈告板/維基香港內容獎/登記處」。
* @returns {Promise<string>} 包含完整wikitext的Promise。
*/
getFullText: async function (pageName) {
let response = await HKCATool.api.get({
action: 'query',
titles: pageName || 'Wikipedia:香港維基人佈告板/維基香港內容獎/登記處',
prop: 'revisions',
rvslots: '*',
rvprop: 'content',
indexpageids: 1,
});
return response.query.pages[response.query.pageids[0]].revisions[0].slots.main['*'];
},
/**
* Trims a token’s text and adjusts its absolute boundaries (skipping leading/trailing whitespace).
* @param {object} token An object with properties { text, start, end }.
* @returns {object} An object with properties { text, start, end } after trimming.
*/
trimToken: function (token) {
const leadingMatch = token.text.match(/^\s*/);
const trailingMatch = token.text.match(/\s*$/);
const leading = leadingMatch ? leadingMatch[0].length : 0;
const trailing = trailingMatch ? trailingMatch[0].length : 0;
return {
text: token.text.trim(),
start: token.start + leading,
end: token.end - trailing,
};
},
/**
* Splits the inner content of a template into tokens by detecting top-level "\n|" delimiters.
* It scans the inner text (tracking nested braces) and splits only when it sees a newline followed by "|".
* @param {string} innerContent The content between the outer "{{" and "}}".
* @param {number} offset The absolute start position of innerContent in the wikitext.
* @returns {Array} An array of tokens; each token is an object { text, start, end }.
*/
splitParameters: function (innerContent, offset) {
let tokens = [];
let lastIndex = 0;
let braceCount = 0;
let i = 0;
while (i < innerContent.length) {
if (innerContent.substr(i, 2) === '{{') {
braceCount++;
i += 2;
continue;
}
if (innerContent.substr(i, 2) === '}}') {
braceCount = Math.max(braceCount - 1, 0);
i += 2;
continue;
}
// At top level, if we see a newline followed by a pipe, split here.
if (braceCount === 0 && innerContent[i] === '\n' && innerContent[i + 1] === '|') {
tokens.push({
text: innerContent.slice(lastIndex, i),
start: offset + lastIndex,
end: offset + i,
});
i += 2; // skip the "\n|"
lastIndex = i;
continue;
}
i++;
}
tokens.push({
text: innerContent.slice(lastIndex),
start: offset + lastIndex,
end: offset + innerContent.length,
});
return tokens;
},
/**
* Finds the matching closing braces "}}" for a template that starts at the given index.
* @param {string} text The full wikitext.
* @param {number} start The starting index where "{{" is found.
* @returns {object} An object { endIndex } where endIndex is the index immediately after the closing "}}".
*/
findTemplateEnd: function (text, start) {
let braceCount = 0;
let i = start;
while (i < text.length) {
if (text.substr(i, 2) === '{{') {
braceCount++;
i += 2;
continue;
}
if (text.substr(i, 2) === '}}') {
braceCount--;
i += 2;
if (braceCount === 0) break;
continue;
}
i++;
}
return {endIndex: i};
},
/**
* Parses a template starting at the given index in the wikitext.
* For simpler {{HKCA Apply}} templates, parameters are parsed as key=value pairs. The keys are expected to have a trailing number (e.g. 條目名稱1, 用戶名稱1, etc.); entries are grouped by that number.
* @param {string} text The full wikitext.
* @param {number} start The starting index of the template (expects "{{").
* @returns {object} An object { template, endIndex }.
*/
parseTemplate: function (text, start) {
const templateStart = start;
const {endIndex: templateEnd} = HKCATool.findTemplateEnd(text, start);
// Extract inner content (between outer "{{" and "}}").
const innerStart = start + 2;
const innerEnd = templateEnd - 2;
const innerContent = text.slice(innerStart, innerEnd);
// Split the inner content into tokens using the top-level "\n|" delimiter.
const tokens = HKCATool.splitParameters(innerContent, innerStart);
// The first token is the template name.
let nameToken = HKCATool.trimToken(tokens[0]);
let templateObj = {
name: nameToken.text,
nameLocation: {
start: nameToken.start,
end: nameToken.end,
},
params: {},
location: {
start: templateStart,
end: templateEnd,
},
};
if (templateObj.name.startsWith("HKCA Apply")) {
// For HKCA Apply, process tokens as key=value pairs.
// Group parameters by their trailing number.
let kvGroups = {};
for (let j = 1; j < tokens.length; j++) {
let token = tokens[j];
let tokenTrim = HKCATool.trimToken(token);
if (tokenTrim.text === "") continue;
const eqIndex = tokenTrim.text.indexOf('=');
if (eqIndex === -1) continue;
let rawKey = tokenTrim.text.substring(0, eqIndex);
let rawValue = tokenTrim.text.substring(eqIndex + 1);
let keyText = rawKey.trim();
let valueText = rawValue.trim();
let keyLeading = rawKey.match(/^\s*/)[0].length;
let keyLocation = {
start: tokenTrim.start + keyLeading,
end: tokenTrim.start + keyLeading + keyText.length,
};
let valueLeading = rawValue.match(/^\s*/)[0].length;
let valueLocation = {
start: tokenTrim.start + eqIndex + 1 + valueLeading,
end: tokenTrim.end,
};
// Expect keys in the form: prefix + number, e.g. "條目名稱1", "用戶名稱1", etc.
let m = keyText.match(/^(.+?)(\d+)$/);
if (m) {
let prefix = m[1].trim(); // e.g. "條目名稱"
let num = parseInt(m[2], 10);
if (!kvGroups[num]) kvGroups[num] = {};
kvGroups[num][prefix] = {
value: valueText,
keyLocation: keyLocation,
valueLocation: valueLocation,
fullLocation: {
start: token.start,
end: token.end,
},
};
} else {
// If the key doesn't match the expected pattern, store it under group "0".
if (!kvGroups["0"]) kvGroups["0"] = {};
kvGroups["0"][keyText] = {
value: valueText,
keyLocation: keyLocation,
valueLocation: valueLocation,
fullLocation: {
start: token.start,
end: token.end,
},
};
}
}
let entries = [];
let groupNums = Object.keys(kvGroups).filter(k => k !== "0").map(Number).sort((a, b) => a - b);
for (let num of groupNums) {
let group = kvGroups[num];
let allTokens = Object.values(group);
let startPos = Math.min(...allTokens.map(t => t.fullLocation.start));
let endPos = Math.max(...allTokens.map(t => t.fullLocation.end));
group.fullLocation = {
start: startPos,
end: endPos,
};
entries.push(group);
}
templateObj.entries = entries;
}
return {
template: templateObj,
endIndex: templateEnd,
};
},
/**
* Returns an array of date sections from the full wikitext.
* Each section is determined by h3 headings of the form "=== date ===".
* @param {string} text The full wikitext.
* @returns {Array} Array of sections: { date, start, end }.
*/
getDateSections: function (text) {
const regex = /^===\s*(.+?)\s*===/gm;
let sections = [];
let matches = [];
let match;
while ((match = regex.exec(text)) !== null) {
matches.push({
date: match[1].trim(),
start: match.index,
end: regex.lastIndex,
});
}
for (let i = 0; i < matches.length; i++) {
const sectionStart = matches[i].start;
const sectionDate = matches[i].date;
const sectionEnd = (i < matches.length - 1) ? matches[i + 1].start : text.length;
sections.push({
date: sectionDate,
start: sectionStart,
end: sectionEnd,
});
}
return sections;
},
/**
* In a given date section (from h3 heading to before the next h3), collects all entries.
* Each entry is an entry from {{HKCA Apply}}.
* @param {string} text The full wikitext.
* @param {object} section A section object { date, start, end }.
* @returns {Array} Array of entry objects: { template, start, end, type }.
*/
collectEntriesInSection: function (text, section) {
let entries = [];
const sectionText = text.slice(section.start, section.end);
// Regex: match {{HKCA Apply
const regex = /{{(?:HKCA Apply)/g;
let match;
while ((match = regex.exec(sectionText)) !== null) {
let absolutePos = section.start + match.index;
let {
template,
endIndex,
} = HKCATool.parseTemplate(text, absolutePos);
if (template.name.startsWith("HKCA Apply")) {
// For HKCA Apply, add each grouped entry.
if (template.entries) {
for (let entry of template.entries) {
entries.push({
template: entry, // entry holds the grouped key-value parameters
start: entry.fullLocation.start,
end: entry.fullLocation.end,
type: 'hkca1',
});
}
}
}
// Advance regex.lastIndex to avoid reparsing inside this template.
regex.lastIndex = endIndex - section.start;
}
// Sort entries in order of appearance.
entries.sort((a, b) => a.start - b.start);
return entries;
},
/**
* Queries the full wikitext for an entry given a specific date (from the h3 heading)
* and an entry index (1-based, counting all entries in order).
* Returns the entry object including its location.
* @param {string} text The full wikitext.
* @param {string} date The date string (e.g. "2月3日").
* @param {number} index The 1-based index of the entry under that date.
* @returns {object|null} The entry object { template, start, end, type } or null if not found.
*/
queryEntry: function (text, date, index) {
const sections = HKCATool.getDateSections(text);
const targetSection = sections.find(sec => sec.date === date);
if (!targetSection) return null;
const entries = HKCATool.collectEntriesInSection(text, targetSection);
if (index < 1 || index > entries.length) return null;
return entries[index - 1]; // 1-based index
},
/**
* Given an entry (from queryEntry) and a set of changes (mapping parameter key to new value),
* updates only those parameter values in the original wikitext by using the precise location data.
* This function does not replace the entire entry substring—only the changed parameter values.
*
* For main or extra entries, changes should be provided as an object where keys are parameter names
* (e.g. "條目名稱") and values are the new text.
*
* For HKCA Apply entries, use keys like "條目名稱", "用戶名稱", "提名理由", "核對用", etc.
*
* @param {string} original The full original wikitext.
* @param {object} entry The entry object (from queryEntry).
* @param {object} changes An object mapping parameter keys to new values.
* @returns {string} The updated wikitext.
*/
updateEntryParameters: function (original, entry, changes) {
let mods = [];
if (entry.type === 'main' || entry.type === 'extra') {
let params = entry.template.params;
for (let key in changes) {
if (params[key] && params[key].valueLocation) {
mods.push({
start: params[key].valueLocation.start,
end: params[key].valueLocation.end,
replacement: changes[key],
});
}
}
} else if (entry.type === 'hkca1') {
// For HKCA Apply grouped entry, keys are like "條目名稱1", "用戶名稱1", etc.
for (let key in changes) {
if (entry.template[key]) {
let token = entry.template[key];
// Use token.valueLocation for precise updating.
mods.push({
start: token.valueLocation.start,
end: token.valueLocation.end,
replacement: changes[key],
});
}
}
}
// Apply modifications in descending order of start position.
mods.sort((a, b) => b.start - a.start);
let updated = original;
for (let mod of mods) {
updated = updated.slice(0, mod.start) + mod.replacement + updated.slice(mod.end);
}
return updated;
},
/**
* Removes comments from the given text.
* @param text {string} The text to remove comments from.
* @returns {string} The text without comments.
*/
removeComments: function (text) {
text = text.replace(/<!--.*?-->/gs, '');
return text.trim();
},
/**
* 根據用戶的提名理由,解析出規則狀態。
* @param reason {string} 用戶的提名理由。
* @returns {object} 規則狀態。
*/
parseUserReason: function (reason) {
reason = HKCATool.removeComments(reason);
let ruleStatus = {};
if (reason.startsWith('{{HKCA Apply/request|ver=2|')) {
reason = reason.slice('{{HKCA Apply/request|ver=2|'.length, -2);
}
let reasonList = reason.split(/\s+/);
let ruleSet = HKCATool.NominationRuleSet();
let ruleNames = ruleSet.ruleNames;
let ruleAliases = HKCATool.NominationRuleAliases();
for (let rule of reasonList) {
if (rule.endsWith('?')) {
// 最後一個字符是?,可直接去掉?
rule = rule.slice(0, -1);
}
// 名稱和分數的自定義
let ruleNameMod = '',
ruleScoreMod = '';
while (rule.endsWith(')') || rule.endsWith(']')) {
if (rule.endsWith(')')) {
let lastLeftParen = rule.lastIndexOf('(');
if (lastLeftParen === -1) break;
ruleNameMod = rule.slice(lastLeftParen + 1, -1);
rule = rule.slice(0, lastLeftParen);
}
if (rule.endsWith(']')) {
let lastLeftBracket = rule.lastIndexOf('[');
if (lastLeftBracket === -1) break;
ruleScoreMod = rule.slice(lastLeftBracket + 1, -1);
rule = rule.slice(0, lastLeftBracket);
}
}
if (rule === '') continue;
if (ruleAliases[rule]) { // 是否是別名
rule = ruleAliases[rule];
}
if (ruleNames.includes(rule)) { // 是否在提名規則中
ruleStatus[rule] = {selected: true};
if (ruleNameMod !== '') {
ruleStatus[rule].desc = ruleNameMod;
}
if (ruleScoreMod !== '') {
ruleStatus[rule].score = parseFloat(ruleScoreMod);
if (isNaN(ruleStatus[rule].score)) {
console.log('[HKCATool] 分數不是數字', ruleScoreMod); // 分數不是數字,報錯
return null;
}
}
} else {
console.log('[HKCATool] 不在提名規則中', rule); // 不在提名規則中,報錯
return null;
}
}
return ruleStatus;
},
/**
* 將queried(查詢結果)轉換為nomData(提名數據)。
* @param queried {object} 查詢結果。
* @returns {object} 提名數據。
*/
queried2NomData: function (queried) {
let nomData = {};
if (queried.type === 'main' || queried.type === 'extra') {
let params = queried.template.params;
nomData.pageName = params['條目名稱'].value;
nomData.awarder = params['用戶名稱'].value;
let reasonWikitext = params['提名理由'].value;
nomData.ruleStatus = HKCATool.parseUserReason(reasonWikitext);
if (nomData.ruleStatus == null) {
return null;
}
return nomData;
} else if (queried.type === 'hkca1') {
let params = queried.template;
nomData.pageName = HKCATool.removeComments(params['條目名稱'].value);
nomData.awarder = HKCATool.removeComments(params['用戶名稱'].value);
let reasonWikitext = params['提名理由'].value;
nomData.ruleStatus = HKCATool.parseUserReason(reasonWikitext);
if (nomData.ruleStatus == null) {
return null;
}
return nomData;
} else {
return null;
}
},
/**
* 點擊編輯按鈕時的事件處理。
* @param date 日期(章節標題)
* @param index 該章節下第X個提名
*/
editNomination: function (date, index) {
HKCATool.getFullText().then(function (fulltext) {
HKCATool.queried = HKCATool.queryEntry(fulltext, date, index);
let nomData = HKCATool.queried2NomData(HKCATool.queried);
if (nomData == null) {
mw.notify(HKCATool.convByVar({
hant: '小工具無法讀取該提名,請手動編輯。',
hans: '小工具无法读取该提名,请手动编辑。',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
} else {
HKCATool.showEditNominationDialog(nomData);
}
});
},
/**
* 點擊核對按鈕時的事件處理。
* @param date 日期(章節標題)
* @param index 該章節下第X個提名
* @param multiCheckStatus 多選核對狀態字串
* @return {Promise} 返回一個Promise,當核對完成時解析。
*/
checkNomination: async function (date, index, multiCheckStatus) {
const fulltext = await HKCATool.getFullText();
HKCATool.queried = HKCATool.queryEntry(fulltext, date, index);
const nomData = HKCATool.queried2NomData(HKCATool.queried);
if (nomData == null) {
mw.notify(HKCATool.convByVar({
hant: '小工具無法讀取該提名,請手動編輯。',
hans: '小工具无法读取该提名,请手动编辑。',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return;
}
await HKCATool.showCheckNominationDialog(nomData, multiCheckStatus);
},
/**
* 批量核對提名的事件處理。
* 遍歷所有帶有 multi-nomCheck 類別的元素,為每個元素添加一個多選核對的複選框和按鈕。
* 當按下「開始大量核對」按鈕時,會遍歷所有選中的複選框,並對每個選中的提名進行核對。
* 如果沒有選中任何複選框,則顯示警告通知。
* 當核對完成後,如果有任何提名被修改,則刷新頁面。
*/
multiCheckNomination: function () {
$('.multi-nomCheck').each(function () {
let $this = $(this);
let checkbox = $('<input type="checkbox" class="multi-nomCheck-checkbox">');
checkbox.data('date', $this.data('date'));
checkbox.data('index', $this.data('index'));
checkbox.on('change', function () {
if ($(this).is(':checked')) {
// Change the background color of ancestor <td> to light green.
$this.closest('td').css('background-color', '#d4edda');
} else {
// Reset the background color of ancestor <td> to default.
$this.closest('td').css('background-color', '');
}
});
let startCheckingButton = $('<a>').text(HKCATool.convByVar({
hant: '開始批次核對',
hans: '开始批量核对',
})).addClass('multi-nomCheck-startBtn').attr('href', '#');
startCheckingButton.on('click', async function (e) {
e.preventDefault();
const $checkboxes = $('.multi-nomCheck-checkbox:checked');
if (!$checkboxes.length) {
mw.notify(HKCATool.convByVar({
hant: '請至少選擇一個提名進行核對。',
hans: '请至少选择一个提名进行核对。',
}), {
type: 'warning',
title: HKCATool.convByVar({
hant: '提示',
hans: '提示',
}),
});
return;
}
HKCATool.multiNomCheckOngoing = true;
HKCATool.multiNomCheckChanged = false;
for (let i = 0; i < $checkboxes.length; i++) {
const $checkbox = $($checkboxes[i]);
const date = $checkbox.data('date');
const index = $checkbox.data('index');
const status = `${i + 1}/${$checkboxes.length}`;
await HKCATool.checkNomination(date, index, status);
}
HKCATool.multiNomCheckOngoing = false;
if (HKCATool.multiNomCheckChanged) {
HKCATool.refreshPage();
}
});
$this.empty(); // 清空之前的內容
$this.append(checkbox);
$this.append(' ');
$this.append(startCheckingButton);
});
},
/**
* 點擊登記新提名按鈕時的事件處理。
*/
newNomination: function () {
HKCATool.showNewNominationDialog();
},
/**
* 點擊歸檔按鈕時的事件處理。
*/
archiveChapter: function (date) {
OO.ui.confirm(HKCATool.convByVar({
hant: '確定要歸檔「',
hans: '确定要归档「',
}) + date + HKCATool.convByVar({
hant: '」章節嗎?',
hans: '」章节吗?',
})).done(function (confirmed) {
if (confirmed) {
HKCATool.getFullText().then(function (fulltext) {
let sections = HKCATool.getDateSections(fulltext);
let targetSection = sections.find(sec => sec.date === date);
if (!targetSection) {
mw.notify(HKCATool.convByVar({
hant: '小工具無法讀取該章節,請手動歸檔。',
hans: '小工具无法读取该章节,请手动归档。',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return;
}
let sectionText = fulltext.slice(targetSection.start, targetSection.end);
let fulltextWithoutSection = fulltext.slice(0, targetSection.start) + fulltext.slice(targetSection.end);
// 找到包含年份的UTC字串,例如 2025年2月13日 (四) 20:58 (UTC)
let utcRegex = /提名人:.+?(\d{4})年(\d{1,2})月(\d{1,2})日 \((.*?)\) (\d{1,2}:\d{2}) \(UTC\)/;
let utcMatch = sectionText.match(utcRegex);
if (!utcMatch) {
mw.notify(HKCATool.convByVar({
hant: '小工具無法讀取該章節的UTC時間,請手動歸檔。',
hans: '小工具无法读取该章节的UTC时间,请手动归档。',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return;
}
// 獲得 X年Y月
let yearMonth = utcMatch[1] + '年' + utcMatch[2] + '月';
let archiveTarget = 'Wikipedia:香港維基人佈告板/維基香港內容獎/存檔/' + yearMonth;
mw.notify(HKCATool.convByVar({
hant: '小工具正在歸檔中,請耐心等待。',
hans: '小工具正在归档中,请耐心等待。',
}), {
type: 'info',
title: HKCATool.convByVar({
hant: '提示',
hans: '提示',
}),
autoHide: false,
});
// 先檢查新的存檔頁面是否存在
HKCATool.api.get({
action: 'query',
titles: archiveTarget,
prop: 'revisions',
rvslots: '*',
rvprop: 'content',
indexpageids: 1,
}).done(function (data) {
if (data.query.pageids[0] && (data.query.pages[data.query.pageids[0]].missing !== undefined || data.query.pages[data.query.pageids[0]].revisions[0].slots.main['*'].trim() === '')) {
// 新的存檔頁面不存在或者是空的
// 將存檔頁頭加入 sectionText
sectionText = '{{Talk archive|Wikipedia:香港維基人佈告板/維基香港內容獎/登記處}}\n\n' + sectionText;
} else {
// 直接歸檔,補充空行
sectionText = '\n\n' + sectionText;
}
HKCATool.api.postWithToken('csrf', {
action: 'edit',
title: archiveTarget,
appendtext: sectionText,
summary: '[[User:Royal Sailor/JS/HKCATool.js|' + HKCATool.convByVar({
hant: '歸檔',
hans: '归档',
}) + ']]「' + date + '」' + HKCATool.convByVar({
hant: '章節',
hans: '章节',
}),
}).done(function () {
HKCATool.api.postWithToken('csrf', {
action: 'edit',
title: 'Wikipedia:香港維基人佈告板/維基香港內容獎/登記處',
text: fulltextWithoutSection,
summary: '[[User:Royal Sailor/JS/HKCATool.js|' + HKCATool.convByVar({
hant: '歸檔',
hans: '归档',
}) + ']]「' + date + '」' + HKCATool.convByVar({
hant: '章節至',
hans: '章节至',
}) + '「[[' + archiveTarget + ']]」',
}).done(function () {
mw.notify(HKCATool.convByVar({
hant: '小工具已歸檔',
hans: '小工具已归档',
}) + '「' + date + '」' + HKCATool.convBysVar({
hant: '章節至',
hans: '章节至',
}) + '「[[' + archiveTarget + ']]」', {
type: 'success',
title: HKCATool.convByVar({
hant: '成功',
hans: '成功',
}),
});
HKCATool.refreshPage(); // 刷新頁面
}).fail(function (error) {
console.log(error);
mw.notify(HKCATool.convByVar({
hant: '小工具無法歸檔,請手動歸檔。',
hans: '小工具无法归档,请手动归档。',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
});
}).fail(function (error) {
console.log(error);
mw.notify(HKCATool.convByVar({
hant: '小工具無法歸檔,請手動歸檔。',
hans: '小工具无法归档,请手动归档。',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
});
});
});
}
});
},
/**
* 在頁面上添加編輯按鈕。
*/
addEditButtonsToPage: function () {
// 找到<span role"button">登記新提名</span>
let newNominationButton = $('span[role="button"]').filter(function () {
return $(this).text() === '登記新提名' || $(this).text() === '登记新提名';
});
if (newNominationButton.length > 0) {
// 修改原本按鈕的文本為「手動登記新提名」
newNominationButton.text(HKCATool.convByVar({
hant: '手動登記新提名',
hans: '手动登记新提名',
}));
newNominationButton.removeClass('mw-ui-progressive');
// 父節點的父節點是<span>,在後面加入編輯按鈕
let newNominationButtonParent = newNominationButton.parent().parent();
let editUIButton = $('<span>').addClass('mw-ui-button').addClass('mw-ui-progressive').attr('role', 'button').text(HKCATool.convByVar({
hant: '登記新提名',
hans: '登记新提名',
}));
let editButton = $('<a>').attr('href', 'javascript:void(0)').append(editUIButton).click(HKCATool.newNomination);
newNominationButtonParent.append(' ').append(editButton);
}
// 識別所有h3
$('div.mw-heading3').each(function () {
let h3div = $(this);
let h3 = h3div.find('h3').first();
let date = h3.text().trim();
let index = 0;
// 為h3div底下的span.mw-editsection添加歸檔按鈕
let editsection = h3div.find('span.mw-editsection').first();
let editsectionA = editsection.find('a').first();
$('<a>').attr('href', 'javascript:void(0)').click(function () {
HKCATool.archiveChapter(date);
}).append(HKCATool.convByVar({
hant: '歸檔',
hans: '归档',
})).insertAfter(editsectionA);
$('<span> | </span>').insertAfter(editsectionA);
h3div.nextUntil('div.mw-heading3', 'table.acgnom-table').each(function () {
let table = $(this);
let rows = table.find('tr').slice(1); // 去掉表頭
let title = "";
rows.each(function () {
let row = $(this);
let th = row.find('th');
if (th.length !== 0) {
// 提名行
let nomEntry = th.first();
let nomEntryA = nomEntry.find('a');
if (nomEntryA.length !== 0) {
title = nomEntry.find('a').first().attr('title');
} else {
title = nomEntry.text().trim();
}
++index;
// 加入編輯按鈕
let editIcon = $('<img>').attr('src', 'https://upload.wikimedia.org/wikipedia/commons/8/8a/OOjs_UI_icon_edit-ltr-progressive.svg').css({'width': '12px'});
const currentIndex = index;
let editButton = $('<a>').attr('href', 'javascript:void(0)').append(editIcon).click(function () {
HKCATool.editNomination(date, currentIndex);
});
nomEntry.append(' ').append(editButton);
} else {
// 核對行
let td = row.find('td').first();
let mwNoTalk = td.find('.mw-notalk').first();
const currentIndex = index;
// 單項核對
let checkIcon = $('<img>').attr('src', 'https://upload.wikimedia.org/wikipedia/commons/3/30/OOjs_UI_icon_highlight-progressive.svg').css({
'width': '12px',
'vertical-align': 'sub',
});
let checkButton = $('<a>').css({
'display': 'inline-block',
'margin-left': '5px',
'font-size': '.857em',
'font-weight': 'bold',
}).append(checkIcon).append(' ').append(HKCATool.convByVar({
hant: '核對',
hans: '核对',
})).attr('href', 'javascript:void(0)').click(function () {
HKCATool.checkNomination(date, currentIndex);
});
mwNoTalk.append(checkButton);
// 多選核對
let multiCheckDiv = $('<div>')
.addClass('multi-nomCheck')
.attr('data-date', date)
.attr('data-index', currentIndex)
.css({
'display': 'inline-block',
'margin-left': '5px',
'font-size': '.857em',
});
let multiCheckButton = $('<a>').attr('href', 'javascript:void(0)').text(HKCATool.convByVar({
hant: '多選',
hans: '多选',
})).click(function () {
HKCATool.multiCheckNomination();
});
multiCheckDiv.append(multiCheckButton);
mwNoTalk.append(multiCheckDiv);
}
});
});
});
},
/**
* 動態寬度文本輸入框。
* @param config
* @constructor
*/
DynamicWidthTextInputWidget: function (config) {
HKCATool.DynamicWidthTextInputWidget.parent.call(this, config);
this.$measure = $('<span>').css({
position: 'absolute',
visibility: 'hidden',
whiteSpace: 'pre',
fontSize: '14px',
fontFamily: 'sans-serif',
}).appendTo(document.body); // Create a hidden element for measuring text width.
this.$input.on('input', this.adjustWidth.bind(this)); // Bind the adjustWidth function to the 'input' event.
},
/**
* 初始化動態寬度文本輸入框。在腳本啟動時執行一次。
*/
initDynamicWidthTextInputWidget: function () {
OO.inheritClass(HKCATool.DynamicWidthTextInputWidget, OO.ui.TextInputWidget);
mw.util.addCSS('.DynamicWidthTextInputWidget { display: inline-block; vertical-align: baseline; width: auto; margin: 0; } .DynamicWidthTextInputWidget input { height: 20px !important; border: none !important; border-bottom: 2px solid #ccc !important; padding: 0 !important; text-align: center; } .DynamicWidthTextInputWidget input:focus { outline: none !important; box-shadow: none !important; border-bottom: 2px solid #36c !important; } .DynamicWidthTextInputWidget input:disabled { background-color: transparent !important; color: #101418 !important; -webkit-text-fill-color: #101418 !important; text-shadow: none !important; border-bottom: 2px solid #fff !important; }');
HKCATool.DynamicWidthTextInputWidget.prototype.adjustWidth = function () {
let text = this.getValue() || ''; // Get the current value; use placeholder if empty.
this.$measure.text(text); // Update the measurement element.
let newWidth = this.$measure.width() + 5; // Add a bit of padding.
this.$input.css('width', newWidth + 'px'); // Apply the new width to the input element.
};
},
/**
* 規則選框,附帶規則名和分數輸入框。
* @param config
* @constructor
*/
RuleCheckboxInputWidget: function (config) {
HKCATool.RuleCheckboxInputWidget.parent.call(this, config);
this.ruleset = config.ruleset;
this.nomidx = config.nomidx;
this.check = config.check || false;
if (!HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule]) {
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule] = {
selected: this.isSelected(),
desc: this.ruleset.desc,
ogDesc: this.ruleset.desc,
score: this.ruleset.score,
maxScore: this.ruleset.score,
};
} else {
this.setSelected(HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].selected);
if (!HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].desc) {
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].desc = this.ruleset.desc;
}
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].ogDesc = this.ruleset.desc;
if (!HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].score) {
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].score = this.ruleset.score;
}
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].maxScore = this.ruleset.score;
}
this.ruleInputWidget = new HKCATool.DynamicWidthTextInputWidget({
value: HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].desc,
disabled: this.check ? false : (!this.isSelected()),
});
this.ruleInputWidget.$element.addClass('DynamicWidthTextInputWidget');
this.ruleInputWidget.$element.css({'margin-left': '5px'});
this.ruleInputWidget.adjustWidth();
this.leftBracketLabelWidget = new OO.ui.LabelWidget({label: '('});
this.leftBracketLabelWidget.$element.css({
'vertical-align': 'baseline',
'border-bottom': '2px solid #fff',
});
this.scoreInputWidget = new HKCATool.DynamicWidthTextInputWidget({
value: HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].score,
disabled: this.check ? false : (!this.isSelected()),
});
this.scoreInputWidget.$element.addClass('DynamicWidthTextInputWidget');
this.scoreInputWidget.adjustWidth();
this.rightBracketLabelWidget = new OO.ui.LabelWidget({label: '分)'});
this.rightBracketLabelWidget.$element.css({
'vertical-align': 'baseline',
'border-bottom': '2px solid #fff',
'margin-right': '10px',
});
this.$element.append(this.ruleInputWidget.$element);
this.$element.append(this.leftBracketLabelWidget.$element);
this.$element.append(this.scoreInputWidget.$element);
this.$element.append(this.rightBracketLabelWidget.$element);
this.on('change', this.handleCheckboxChange.bind(this));
this.ruleInputWidget.on('change', this.handleRuleInputChange.bind(this));
this.scoreInputWidget.on('change', this.handleScoreInputChange.bind(this));
},
/**
* 初始化規則選框。在腳本啟動時執行一次。
*/
initRuleCheckboxInputWidget: function () {
OO.inheritClass(HKCATool.RuleCheckboxInputWidget, OO.ui.CheckboxInputWidget);
HKCATool.RuleCheckboxInputWidget.prototype.handleCheckboxChange = function (isChecked) {
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].selected = isChecked;
let disableCheck = this.check ? false : (!isChecked);
this.ruleInputWidget.setDisabled(disableCheck);
this.scoreInputWidget.setDisabled(disableCheck);
if (disableCheck) {
// 取消選取時,重設規則名和分數
this.ruleInputWidget.setValue(this.ruleset.desc);
this.ruleInputWidget.adjustWidth();
this.scoreInputWidget.setValue(this.ruleset.score);
this.scoreInputWidget.adjustWidth();
}
};
HKCATool.RuleCheckboxInputWidget.prototype.handleRuleInputChange = function (newValue) {
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].desc = newValue;
};
HKCATool.RuleCheckboxInputWidget.prototype.handleScoreInputChange = function (newValue) {
HKCATool.nominations[this.nomidx].ruleStatus[this.ruleset.rule].score = parseFloat(newValue);
};
},
/**
* 生成提名表單。
* @param {object} nomData 提名資料(非必須)。無資料時為新提名。
* @returns {OO.ui.FieldsetLayout} 提名表單。
*/
generateNominationFieldset: function (nomData) {
let awarder,
pageName,
ruleStatus;
if (nomData) {
awarder = nomData.awarder;
pageName = nomData.pageName;
ruleStatus = nomData.ruleStatus;
} else {
awarder = mw.config.get('wgUserName');
pageName = '';
ruleStatus = {};
}
const currentNomidx = HKCATool.nominations.length;
HKCATool.nominations.push({
awarder: awarder,
pageName: pageName,
ruleStatus: ruleStatus,
});
// 得分者
let userNameInput = new OO.ui.TextInputWidget({value: HKCATool.nominations[currentNomidx].awarder});
userNameInput.on('change', function (newValue) {
HKCATool.nominations[currentNomidx].awarder = newValue;
});
let userNameField = new OO.ui.FieldLayout(userNameInput, {
label: HKCATool.convByVar({
hant: '得分者',
hans: '得分者',
}),
align: 'left',
});
// 條目名稱
let pageNameInput = new OO.ui.TextInputWidget({value: HKCATool.nominations[currentNomidx].pageName});
pageNameInput.on('change', function (newValue) {
HKCATool.nominations[currentNomidx].pageName = newValue;
});
let pageNameField = new OO.ui.FieldLayout(pageNameInput, {
label: HKCATool.convByVar({
hant: '得分條目',
hans: '得分条目',
}),
align: 'left',
});
// 提名理由
let reasonFieldsetLayout = new OO.ui.FieldsetLayout();
reasonFieldsetLayout.$element.css({'padding-top': '15px'}); // 讓理由區域與上方的輸入框有點距離
let NominationRules = HKCATool.NominationRules();
for (let i = 0; i < NominationRules.length; i++) {
let ruleGroup = NominationRules[i];
let ruleGroupFieldset = new OO.ui.FieldsetLayout({
label: ruleGroup.group,
align: 'top',
help: ruleGroup.explanation,
helpInline: true,
});
if (ruleGroup.rules) {
let ruleItems = [];
for (let j = 0; j < ruleGroup.rules.length; j++) {
let rule = ruleGroup.rules[j];
let ruleCheckbox = new HKCATool.RuleCheckboxInputWidget({
value: rule.rule,
ruleset: rule,
nomidx: currentNomidx,
});
ruleItems.push(ruleCheckbox);
}
let horizontalLayout = new OO.ui.HorizontalLayout({items: ruleItems});
ruleGroupFieldset.addItems(horizontalLayout);
} else {
// 處理 (5) 條目評審
for (let j = 0; j < ruleGroup.tabs.length; j++) {
let tab = ruleGroup.tabs[j];
let tabFieldset = new OO.ui.FieldsetLayout({label: tab.tab});
tabFieldset.$element.find('legend > span').css({'font-size': '1.05em'});
let ruleItems = [];
for (let k = 0; k < tab.rules.length; k++) {
let rule = tab.rules[k];
let ruleCheckbox = new HKCATool.RuleCheckboxInputWidget({
value: rule.rule,
ruleset: rule,
nomidx: currentNomidx,
});
ruleItems.push(ruleCheckbox);
}
let horizontalLayout = new OO.ui.HorizontalLayout({items: ruleItems});
tabFieldset.addItems(horizontalLayout);
ruleGroupFieldset.addItems([tabFieldset]);
}
}
reasonFieldsetLayout.addItems([ruleGroupFieldset]);
}
let nominationFieldset = new OO.ui.FieldsetLayout({
items: [
userNameField,
pageNameField,
reasonFieldsetLayout,
],
});
nominationFieldset.$element.css({'margin-top': 0});
if (!nomData) {
let hr = $('<hr>').css({
'margin-top': '15px',
'margin-bottom': '15px',
}); // 頂部的 <hr>
nominationFieldset.$element.prepend(hr);
}
return nominationFieldset;
},
/**
* 獲取XTools頁面資訊。無法獲取時按下不表,返回空字串。
* @param pageName
* @returns {Promise<string>} XTools頁面資訊。
*/
getXToolsInfo: async function (pageName) {
try {
return await $.get('https://xtools.wmcloud.org/api/page/pageinfo/' + mw.config.get('wgServerName') + '/' + pageName.replace(/["?%&+\\]/g, escape) + '?format=html&uselang=' + mw.config.get('wgUserLanguage'));
} catch (error) {
console.error('Error fetching XTools data:', error);
return '';
}
},
/**
* 生成提名檢查單。
* @param nomData 提名資料。
* @returns {OO.ui.FieldsetLayout} 提名檢查單。
*/
generateChecklistFieldset: async function (nomData) {
let awarder = nomData.awarder;
let pageName = nomData.pageName;
let ruleStatus = nomData.ruleStatus;
HKCATool.nominations.push({
awarder: awarder,
pageName: pageName,
ruleStatus: ruleStatus,
invalid: false,
message: '',
});
// 得分者
let userNameLinkLabelWidget = new OO.ui.LabelWidget({label: $('<a>').attr('href', mw.util.getUrl('User:' + awarder)).text(awarder)});
let userTalkLinkLabelWidget = new OO.ui.LabelWidget({
label: $('<a>').attr('href', mw.util.getUrl('User talk:' + awarder)).text(HKCATool.convByVar({
hant: '討論',
hans: '讨论',
})),
});
let userContribsLinkLabelWidget = new OO.ui.LabelWidget({
label: $('<a>').attr('href', mw.util.getUrl('Special:用户贡献/' + awarder)).text(HKCATool.convByVar({
hant: '貢獻',
hans: '贡献',
})),
});
let userNameHorizontalLayout = new OO.ui.HorizontalLayout({
items: [
userNameLinkLabelWidget,
new OO.ui.LabelWidget({label: '('}),
userTalkLinkLabelWidget,
new OO.ui.LabelWidget({label: '·'}),
userContribsLinkLabelWidget,
new OO.ui.LabelWidget({label: ')'}),
],
});
userNameHorizontalLayout.$element.css({
'gap': '4px',
'width': '80%',
'flex-shrink': '0',
'flex-wrap': 'wrap',
});
let userNameLabelWidget = new OO.ui.LabelWidget({
label: HKCATool.convByVar({
hant: '得分者',
hans: '得分者',
}),
});
userNameLabelWidget.$element.css({
'flex-grow': 1,
'align-self': 'stretch',
});
let userNameField = new OO.ui.HorizontalLayout({
items: [
userNameLabelWidget,
userNameHorizontalLayout,
],
});
// 條目名稱
let pageNameHorizontalLayout,
pageNameLabelWidget;
if (pageName === '他薦' || pageName === '他荐') {
pageNameLabelWidget = new OO.ui.LabelWidget({
label: HKCATool.convByVar({
hant: '他薦',
hans: '他荐',
}),
});
pageNameHorizontalLayout = new OO.ui.HorizontalLayout({items: [pageNameLabelWidget]});
} else {
pageNameLabelWidget = new OO.ui.LabelWidget({label: $('<a>').attr('href', mw.util.getUrl(pageName)).text(pageName)});
let pageTalkLabelWidget = new OO.ui.LabelWidget({
label: $('<a>').attr('href', mw.util.getUrl('Talk:' + pageName)).text(HKCATool.convByVar({
hant: '討論',
hans: '讨论',
})),
});
let pageHistoryLabelWidget = new OO.ui.LabelWidget({
label: $('<a>').attr('href', mw.util.getUrl(pageName, {action: 'history'})).text(HKCATool.convByVar({
hant: '歷史',
hans: '历史',
})),
});
let pagesLinkedToPageLabelWidget = new OO.ui.LabelWidget({
label: $('<a>').attr('href', mw.util.getUrl('Special:链入页面/' + pageName)).text(HKCATool.convByVar({
hant: '連入',
hans: '链入',
})),
});
// 更多頁面資訊 from XTools
let xtoolsData = await HKCATool.getXToolsInfo(pageName);
let xtoolsPageInfoLabelWidget = new OO.ui.LabelWidget({label: $('<div>').html(xtoolsData)});
xtoolsPageInfoLabelWidget.$element.css({'font-size': '0.9em'});
pageNameHorizontalLayout = new OO.ui.HorizontalLayout({
items: [
pageNameLabelWidget,
new OO.ui.LabelWidget({label: '('}),
pageTalkLabelWidget,
new OO.ui.LabelWidget({label: '·'}),
pageHistoryLabelWidget,
new OO.ui.LabelWidget({label: '·'}),
pagesLinkedToPageLabelWidget,
new OO.ui.LabelWidget({label: ')'}),
xtoolsPageInfoLabelWidget,
],
});
}
pageNameHorizontalLayout.$element.css({
'gap': '4px',
'width': '80%',
'flex-shrink': '0',
'flex-wrap': 'wrap',
});
let pageLabelLabelWidget = new OO.ui.LabelWidget({
label: HKCATool.convByVar({
hant: '得分條目',
hans: '得分条目',
}),
});
pageLabelLabelWidget.$element.css({
'flex-grow': 1,
'align-self': 'stretch',
});
let pageNameField = new OO.ui.HorizontalLayout({
items: [
pageLabelLabelWidget,
pageNameHorizontalLayout,
],
});
pageNameField.$element.css({'margin-top': '15px'});
// 提名無效
let invalidToggleSwitchWidget = new OO.ui.ToggleSwitchWidget({value: false});
invalidToggleSwitchWidget.on('change', function (isChecked) {
HKCATool.nominations[0].invalid = isChecked;
});
let invalidField = new OO.ui.FieldLayout(invalidToggleSwitchWidget, {
label: HKCATool.convByVar({
hant: '提名無效',
hans: '提名无效',
}),
align: 'left',
});
invalidField.$element.css({'margin-top': '15px'});
invalidField.$element.addClass('checklist-field');
// 提名理由
let reasonField = new OO.ui.HorizontalLayout();
reasonField.$element.css({'margin-top': '15px'});
let reasonLabelWidget = new OO.ui.LabelWidget({
label: HKCATool.convByVar({
hant: '提名理由',
hans: '提名理由',
}),
});
reasonLabelWidget.$element.css({
'flex-grow': 1,
'align-self': 'stretch',
});
let ruleItems = [];
let {
ruleNames,
ruleDict,
} = HKCATool.NominationRuleSet();
let orderedRuleStatus = HKCATool.getOrderedRuleStatus(ruleNames, ruleStatus);
for (const ruleItem of orderedRuleStatus) {
let ruleSet = ruleDict[ruleItem.rule];
let ruleCheckbox = new HKCATool.RuleCheckboxInputWidget({
value: ruleItem.rule,
ruleset: ruleSet,
nomidx: 0,
check: true,
});
ruleItems.push(ruleCheckbox);
}
let horizontalLayout = new OO.ui.HorizontalLayout({items: ruleItems});
horizontalLayout.$element.css({
'width': '80%',
'flex-shrink': '0',
'flex-wrap': 'wrap',
});
reasonField.addItems([
reasonLabelWidget,
horizontalLayout,
]);
// 附加說明
let messageInput = new OO.ui.MultilineTextInputWidget({
autosize: true,
rows: 1,
});
messageInput.on('change', function (newValue) {
HKCATool.nominations[0].message = newValue;
});
messageInput.on('resize', function () {
try {
HKCATool.checkNominationDialog.updateSize();
} catch (error) {
console.error('[HKCATool] Error updating dialog size:', error);
}
});
let messageField = new OO.ui.FieldLayout(messageInput, {
label: HKCATool.convByVar({
hant: '附加說明',
hans: '附加说明',
}),
align: 'left',
help: HKCATool.convByVar({
hant: '可不填;無須簽名',
hans: '可不填;无须签名',
}),
helpInline: true,
});
messageField.$element.css({'margin-top': '15px'});
messageField.$element.addClass('checklist-field');
let nominationFieldset = new OO.ui.FieldsetLayout({
items: [
userNameField,
pageNameField,
invalidField,
reasonField,
messageField,
],
});
nominationFieldset.$element.css({'margin-top': 0});
return nominationFieldset;
},
/**
* 生成提名理由。
* @param ruleStatus
* @param check
* @returns {{reasonText: string, unselectedReasonText: string}|string|null}
*/
generateReason: function (ruleStatus, check) {
// 拼湊提名理由
let reasonText = '',
unselectedReasonText = '';
let reasonScore = 0;
let {ruleNames} = HKCATool.NominationRuleSet();
let orderedRuleStatus = HKCATool.getOrderedRuleStatus(ruleNames, ruleStatus);
for (const ruleItem of orderedRuleStatus) {
if (check ? true : ruleItem.selected) {
if (isNaN(ruleItem.score) || ruleItem.score < 0) {
mw.notify(HKCATool.convByVar({
hant: '規則',
hans: '规则',
}) + '「' + ruleItem.rule + '」' + HKCATool.convByVar({
hant: '的分數不合法,請檢查!',
hans: '的分数不合法,请检查!',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return null;
}
// if (ruleItem.score > ruleItem.maxScore) {
// mw.notify(
// HKCATool.convByVar({ hant: '規則', hans: '规则' }) + '「' + ruleItem.rule + '」' + HKCATool.convByVar({ hant: '的分數超過最大值', hans: '的分数超过最大值' }) + '「' + ruleItem.maxScore + '」' + HKCATool.convByVar({ hant: ',請檢查!', hans: ',请检查!' }),
// { type: 'error', title: HKCATool.convByVar({ hant: '錯誤', hans: '错误' }) }
// );
// return null;
// }
if (ruleItem.selected) {
reasonText += ' ' + ruleItem.rule;
if (ruleItem.desc !== ruleItem.ogDesc) reasonText += '(' + ruleItem.desc + ')';
if (ruleItem.score !== ruleItem.maxScore) reasonText += '[' + ruleItem.score + ']';
reasonScore += ruleItem.score;
} else if (check) {
unselectedReasonText += ' ' + ruleItem.rule;
if (ruleItem.desc !== ruleItem.ogDesc) unselectedReasonText += '(' + ruleItem.desc + ')';
if (ruleItem.score !== ruleItem.maxScore) unselectedReasonText += '[' + ruleItem.score + ']';
}
}
}
reasonText = reasonText.trim();
unselectedReasonText = unselectedReasonText.trim();
if (check) {
return {
reasonText: reasonText,
unselectedReasonText: unselectedReasonText,
reasonScore: reasonScore,
};
}
return reasonText;
},
/**
* 保存新提名。
* @returns {Promise<boolean>} 是否成功提交。
*/
saveNewNomination: async function () {
let proposedWikitext = '{{HKCA Apply';
for (let i = 0; i < HKCATool.nominations.length; i++) {
let nomination = HKCATool.nominations[i];
if (nomination.awarder === '' || nomination.pageName === '') {
mw.notify(HKCATool.convByVar({
hant: '得分者或得分條目未填寫,請檢查!',
hans: '得分者或得分条目未填写,请检查!',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
let reasonText = HKCATool.generateReason(nomination.ruleStatus);
if (reasonText == null) {
return true;
}
if (reasonText === '') {
mw.notify(HKCATool.convByVar({
hant: '未選擇任何評審規則,請檢查!',
hans: '未选择任何评审规则,请检查!',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
proposedWikitext += '\n|條目名稱' + (i + 1) + ' = ' + nomination.pageName.trim();
proposedWikitext += '\n|用戶名稱' + (i + 1) + ' = ' + nomination.awarder.trim();
proposedWikitext += '\n|提名理由' + (i + 1) + ' = {{HKCA Apply/request|ver=2|' + reasonText + '}}';
proposedWikitext += '\n|核對用' + (i + 1) + ' = {{HKCA Apply/check|ver=2|}}';
}
const signature = '~' + '~' + '~' + '~';
proposedWikitext += "\n}}\n'''提名人:'''" + signature;
// 附加說明
let message = HKCATool.newNominationDialog.messageInput.getValue().trim();
if (message !== '') {
proposedWikitext += "\n: {{說明}}:" + message + '--' + signature;
}
// 是否已有今日的date
let today = new Date();
let todayDate = (today.getMonth() + 1) + '月' + today.getDate() + '日';
let fulltext = await HKCATool.getFullText();
if (!fulltext.includes('=== ' + todayDate + ' ===')) {
// 沒有今日的date,先新增一個
proposedWikitext = '=== ' + todayDate + ' ===\n' + proposedWikitext;
}
// 提交
let response = await HKCATool.api.postWithToken('csrf', {
action: 'edit',
title: 'Wikipedia:香港維基人佈告板/維基香港內容獎/登記處',
appendtext: '\n' + proposedWikitext,
summary: '[[User:Royal Sailor/JS/HKCATool.js|新提名]]',
});
if (response.edit.result === 'Success') {
mw.notify(HKCATool.convByVar({
hant: '新提名已成功提交!',
hans: '新提名已成功提交!',
}), {
title: HKCATool.convByVar({
hant: '成功',
hans: '成功',
}),
autoHide: true,
});
HKCATool.refreshPage();
return false;
} else {
mw.notify(HKCATool.convByVar({
hant: '新提名提交失敗:',
hans: '新提名提交失败:',
}) + response.edit.result, {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
},
/**
* 保存修改提名。
* @returns {Promise<boolean>} 是否成功提交。
*/
saveModifiedNomination: async function () {
let nomination = HKCATool.nominations[0];
if (nomination.awarder === '' || nomination.pageName === '') {
mw.notify(HKCATool.convByVar({
hant: '得分者或得分條目未填寫,請檢查!',
hans: '得分者或得分条目未填写,请检查!',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
let reasonText = HKCATool.generateReason(nomination.ruleStatus);
if (reasonText == null) {
return true;
}
if (reasonText === '') {
mw.notify(HKCATool.convByVar({
hant: '未選擇任何評審規則,請檢查!',
hans: '未选择任何评审规则,请检查!',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
let fulltext = await HKCATool.getFullText(),
updatedText;
if (HKCATool.queried.type === 'main' || HKCATool.queried.type === 'extra') {
let changes = {
'條目名稱': nomination.pageName,
'用戶名稱': nomination.awarder,
'提名理由': '{{HKCA Apply/request|ver=2|' + reasonText + '}}',
};
updatedText = HKCATool.updateEntryParameters(fulltext, HKCATool.queried, changes);
} else if (HKCATool.queried.type === 'hkca1') {
let changes = {
'條目名稱': nomination.pageName,
'用戶名稱': nomination.awarder,
'提名理由': '{{HKCA Apply/request|ver=2|' + reasonText + '}}',
};
updatedText = HKCATool.updateEntryParameters(fulltext, HKCATool.queried, changes);
}
if (updatedText === fulltext) {
mw.notify(HKCATool.convByVar({
hant: '提名並未改動!',
hans: '提名并未改动!',
}), {
type: 'warn',
title: HKCATool.convByVar({
hant: '提示',
hans: '提示',
}),
});
return true;
}
let response = await HKCATool.api.postWithToken('csrf', {
action: 'edit',
title: 'Wikipedia:香港維基人佈告板/維基香港內容獎/登記處',
text: updatedText,
summary: '[[User:Royal Sailor/JS/HKCATool.js|編輯提名]]',
});
if (response.edit.result === 'Success') {
mw.notify(HKCATool.convByVar({
hant: '提名已成功修改!',
hans: '提名已成功修改!',
}), {
title: HKCATool.convByVar({
hant: '成功',
hans: '成功',
}),
autoHide: true,
});
HKCATool.refreshPage();
return false;
} else {
mw.notify(HKCATool.convByVar({
hant: '提名修改失敗:',
hans: '提名修改失败:',
}) + response.edit.result, {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
},
/**
* 保存核分。
* @returns {Promise<boolean>} 是否成功提交。
*/
saveNominationCheck: async function () {
let nomination = HKCATool.nominations[0];
let checkText = '{{HKCA Apply/check|ver=2|';
let reasonScore = 0;
// 是否選擇「提名無效」
if (nomination.invalid) {
checkText += '0';
} else {
let reasonObject = HKCATool.generateReason(nomination.ruleStatus, true);
if (reasonObject == null) {
return true;
}
let reasonText = reasonObject.reasonText;
let unselectedReasonText = reasonObject.unselectedReasonText;
reasonScore = reasonObject.reasonScore;
checkText += reasonText;
if (unselectedReasonText !== '') {
checkText += '|no=' + unselectedReasonText;
}
}
checkText += '}}' + nomination.message;
let signature = '~' + '~' + '~' + '~';
checkText += '--' + signature;
let fulltext = await HKCATool.getFullText(),
updatedText;
if (HKCATool.queried.type === 'main' || HKCATool.queried.type === 'extra') {
let changes = {'核對用': checkText};
updatedText = HKCATool.updateEntryParameters(fulltext, HKCATool.queried, changes);
} else if (HKCATool.queried.type === 'hkca1') {
let changes = {'核對用': checkText};
updatedText = HKCATool.updateEntryParameters(fulltext, HKCATool.queried, changes);
}
if (updatedText === fulltext) {
mw.notify(HKCATool.convByVar({
hant: '核分並未改動!',
hans: '核分并未改动!',
}), {
type: 'warn',
title: HKCATool.convByVar({
hant: '提示',
hans: '提示',
}),
});
return true;
}
let response = await HKCATool.api.postWithToken('csrf', {
action: 'edit',
title: 'Wikipedia:香港維基人佈告板/維基香港內容獎/登記處',
text: updatedText,
summary: '[[User:Royal Sailor/JS/HKCATool.js|核對分數]]',
});
if (response.edit.result === 'Success') {
mw.notify(HKCATool.convByVar({
hant: '核分已成功提交!',
hans: '核分已成功提交!',
}), {
title: HKCATool.convByVar({
hant: '成功',
hans: '成功',
}),
autoHide: false,
});
if (reasonScore > 0) {
await HKCATool.editHKCAScoreList(nomination.awarder, reasonScore);
}
if (!HKCATool.multiNomCheckOngoing) {
HKCATool.refreshPage();
}
HKCATool.multiNomCheckChanged = true;
return false;
} else {
mw.notify(HKCATool.convByVar({
hant: '核分提交失敗:',
hans: '核分提交失败:',
}) + response.edit.result, {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true;
}
},
/**
* 編輯 Module:HKCA/list。
* @param {string} awarder 得分者。
* @param {number} score 得分。
* @return {Promise<boolean>} 是否成功提交。
*/
editHKCAScoreList: async function (awarder, score) {
let scorelistText = await HKCATool.getFullText('Module:HKCA/list');
let scorelistLines = scorelistText.trim().split('\n').slice(1, -1); // 去掉 'return {' 和 '}' 行
let scorelist = {};
for (let line of scorelistLines) {
let match = line.match(/^\s*\[?(?:'([^']+)'|"([^"]+)")\]?\s*=\s*([+-]?[\d.]+)\s*,?\s*$/);
if (match) {
let name = match[1] || match[2]; // 使用第一個捕獲組或第二個捕獲組
scorelist[name] = parseFloat(match[3]);
}
}
let originalScore = scorelist[awarder] || 0; // 獲取原始分數
scorelist[awarder] = originalScore + score; // 更新分數
let editSummary = awarder + ' ' + originalScore + '+' + score + '=' + scorelist[awarder];
let sortedNames = Object.keys(scorelist).sort((a, b) => {
// 按照名稱排序,忽略大小寫
return a.toLowerCase().localeCompare(b.toLowerCase(), "en");
});
let newScorelistText = 'return {\n';
for (let name of sortedNames) {
let nameQuoted = name.includes('"') ? "'" + name + "'" : '"' + name + '"'; // 確保名稱被正確引用
newScorelistText += ' [' + nameQuoted + '] = ' + scorelist[name].toString() + ',\n';
}
newScorelistText += '}';
// 提交修改
let response = await HKCATool.api.postWithToken('csrf', {
action: 'edit',
title: 'Module:HKCA/list',
text: newScorelistText,
summary: editSummary + '([[User:Royal Sailor/JS/HKCATool.js|核對分數]])',
});
if (response.edit.result === 'Success') {
mw.notify(HKCATool.convByVar({
hant: 'Module:HKCA/list 已成功更新!',
hans: 'Module:HKCA/list 已成功更新!',
}), {
title: HKCATool.convByVar({
hant: '成功',
hans: '成功',
}),
autoHide: true,
});
return false; // 成功提交
} else {
mw.notify(HKCATool.convByVar({
hant: 'Module:HKCA/list 更新失敗:',
hans: 'Module:HKCA/list 更新失败:',
}) + response.edit.result, {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return true; // 提交失敗
}
},
/**
* 刷新頁面。
*/
refreshPage: function () {
// 2秒後刷新頁面
setTimeout(function () {
location.reload();
}, 2000);
},
/**
* 新提名對話框。
* @param config
* @constructor
*/
NewNominationDialog: function (config) {
HKCATool.NewNominationDialog.super.call(this, config);
},
/**
* 初始化新提名對話框。在腳本啟動時執行一次。
*/
initNewNominationDialog: function () {
OO.inheritClass(HKCATool.NewNominationDialog, OO.ui.ProcessDialog);
HKCATool.NewNominationDialog.static.name = 'NewNominationDialog';
HKCATool.NewNominationDialog.static.title = HKCATool.convByVar({
hant: '新提名(維基香港內容獎小工具)',
hans: '新提名(维基香港内容奖小工具)',
});
HKCATool.NewNominationDialog.static.actions = [
{
action: 'save',
label: HKCATool.convByVar({
hant: '儲存',
hans: '储存',
}),
flags: [
'primary',
'progressive',
],
},
{
action: 'cancel',
label: HKCATool.convByVar({
hant: '取消',
hans: '取消',
}),
flags: 'safe',
},
{
action: 'add',
label: HKCATool.convByVar({
hant: '額外提名 + 1',
hans: '额外提名 + 1',
}),
},
{
action: 'minus',
label: HKCATool.convByVar({
hant: '額外提名 − 1',
hans: '额外提名 − 1',
}),
},
];
HKCATool.NewNominationDialog.prototype.initialize = function () {
HKCATool.NewNominationDialog.super.prototype.initialize.call(this);
this.panel = new OO.ui.PanelLayout({
padded: true,
expanded: false,
});
this.content = new OO.ui.FieldsetLayout();
// 附加說明
this.messageInput = new OO.ui.MultilineTextInputWidget({
autosize: true,
rows: 1,
});
this.messageInput.connect(this, {resize: 'onMessageInputResize'});
this.messageInputField = new OO.ui.FieldLayout(this.messageInput, {
label: HKCATool.convByVar({
hant: '附加說明',
hans: '附加说明',
}),
align: 'top',
help: HKCATool.convByVar({
hant: '可不填;無須簽名',
hans: '可不填;无须签名',
}),
helpInline: true,
});
this.messageInputFieldSet = new OO.ui.FieldsetLayout({items: [this.messageInputField]});
this.content.addItems([
this.messageInputFieldSet,
HKCATool.generateNominationFieldset(),
]);
this.panel.$element.append(this.content.$element);
this.$body.append(this.panel.$element);
};
HKCATool.NewNominationDialog.prototype.onMessageInputResize = function () {
this.updateSize();
};
HKCATool.NewNominationDialog.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight(true);
};
HKCATool.NewNominationDialog.prototype.getActionProcess = function (action) {
if (action === 'save') {
return new OO.ui.Process(async function () {
let response = await HKCATool.saveNewNomination();
if (!response) {
this.close();
}
}, this);
} else if (action === 'add') {
return new OO.ui.Process(function () {
// 新增一個提名
let newFieldset = HKCATool.generateNominationFieldset();
this.content.addItems([newFieldset]);
this.updateSize();
}, this);
} else if (action === 'minus') {
return new OO.ui.Process(function () {
if (this.content.items.length <= 2) {
mw.notify(HKCATool.convByVar({
hant: '至少需要一個提名!',
hans: '至少需要一个提名!',
}), {
type: 'error',
title: HKCATool.convByVar({
hant: '錯誤',
hans: '错误',
}),
});
return;
}
// 移除最後一個提名
this.content.removeItems([this.content.items[this.content.items.length - 1]]);
HKCATool.nominations.pop();
this.updateSize();
}, this);
} else if (action === 'cancel') {
return new OO.ui.Process(function () {
this.close();
}, this);
}
return HKCATool.NewNominationDialog.super.prototype.getActionProcess.call(this, action);
};
HKCATool.NewNominationDialog.prototype.getTearnDownProcess = function (data) {
return HKCATool.NewNominationDialog.super.prototype.getTearnDownProcess.call(this, data);
};
},
/**
* 顯示新提名對話框。
*/
showNewNominationDialog: function () {
// 清空原有的items
HKCATool.nominations.length = 0;
HKCATool.newNominationDialog = new HKCATool.NewNominationDialog({
size: 'large',
padded: true,
scrollable: true,
});
HKCATool.windowManager.addWindows([HKCATool.newNominationDialog]);
HKCATool.windowManager.openWindow(HKCATool.newNominationDialog);
},
/**
* 編輯提名對話框。
* @param config
* @constructor
*/
EditNominationDialog: function (config) {
HKCATool.EditNominationDialog.super.call(this, config);
},
/**
* 初始化編輯提名對話框。在腳本啟動時執行一次。
*/
initEditNominationDialog: function () {
OO.inheritClass(HKCATool.EditNominationDialog, OO.ui.ProcessDialog);
HKCATool.EditNominationDialog.static.name = 'EditNominationDialog';
HKCATool.EditNominationDialog.static.title = HKCATool.convByVar({
hant: '編輯提名(維基香港內容獎小工具)',
hans: '编辑提名(维基香港内容奖小工具)',
});
HKCATool.EditNominationDialog.static.actions = [
{
action: 'save',
label: HKCATool.convByVar({
hant: '儲存',
hans: '储存',
}),
flags: [
'primary',
'progressive',
],
},
{
action: 'cancel',
label: HKCATool.convByVar({
hant: '取消',
hans: '取消',
}),
flags: 'safe',
},
];
HKCATool.EditNominationDialog.prototype.initialize = function () {
HKCATool.EditNominationDialog.super.prototype.initialize.call(this);
this.panel = new OO.ui.PanelLayout({
padded: true,
expanded: false,
});
this.panel.$element.append(HKCATool.editNominationDialogContent.$element);
this.$body.append(this.panel.$element);
};
HKCATool.EditNominationDialog.prototype.onMessageInputResize = function () {
this.updateSize();
};
HKCATool.EditNominationDialog.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight(true);
};
HKCATool.EditNominationDialog.prototype.getActionProcess = function (action) {
if (action === 'save') {
return new OO.ui.Process(async function () {
let response = await HKCATool.saveModifiedNomination();
if (!response) {
this.close();
}
}, this);
} else if (action === 'cancel') {
return new OO.ui.Process(function () {
this.close();
}, this);
}
return HKCATool.EditNominationDialog.super.prototype.getActionProcess.call(this, action);
};
HKCATool.EditNominationDialog.prototype.getTearnDownProcess = function (data) {
return HKCATool.EditNominationDialog.super.prototype.getTearnDownProcess.call(this, data);
};
},
/**
* 顯示編輯提名對話框。
* @param nomData 提名資料。
*/
showEditNominationDialog: function (nomData) {
// 清空原有的items
HKCATool.editNominationDialogContent.clearItems();
HKCATool.nominations.length = 0;
HKCATool.editNominationDialog = new HKCATool.EditNominationDialog({
size: 'large',
padded: true,
scrollable: true,
});
// 加入新的items
HKCATool.editNominationDialogContent.addItems([HKCATool.generateNominationFieldset(nomData)]);
HKCATool.windowManager.addWindows([HKCATool.editNominationDialog]);
HKCATool.windowManager.openWindow(HKCATool.editNominationDialog);
},
/**
* 核分提名對話框。
* @param config
* @constructor
*/
CheckNominationDialog: function (config) {
HKCATool.CheckNominationDialog.super.call(this, config);
},
/**
* 初始化核分提名對話框。在腳本啟動時執行一次。
*/
initCheckNominationDialog: function () {
OO.inheritClass(HKCATool.CheckNominationDialog, OO.ui.ProcessDialog);
HKCATool.CheckNominationDialog.static.name = 'CheckNominationDialog';
HKCATool.CheckNominationDialog.static.title = HKCATool.convByVar({
hant: '核對分數(維基香港內容獎小工具)',
hans: '核对分数(维基香港内容奖小工具)',
});
HKCATool.CheckNominationDialog.static.actions = [
{
action: 'save',
label: HKCATool.convByVar({
hant: '儲存',
hans: '储存',
}),
flags: [
'primary',
'progressive',
],
},
{
action: 'cancel',
label: HKCATool.convByVar({
hant: '取消',
hans: '取消',
}),
flags: 'safe',
},
];
HKCATool.CheckNominationDialog.prototype.initialize = function () {
HKCATool.CheckNominationDialog.super.prototype.initialize.call(this);
this._header = this.$body.find('.oo-ui-processDialog-title');
this.panel = new OO.ui.PanelLayout({
padded: true,
expanded: false,
});
this.panel.$element.append(HKCATool.checkNominationDialogContent.$element);
this.$body.append(this.panel.$element);
};
HKCATool.CheckNominationDialog.prototype.getSetupProcess = function (data) {
return HKCATool.CheckNominationDialog.super.prototype.getSetupProcess.call(this, data)
.next(function () {
if (data.title) {
this._header.innerText = data.title;
}
}, this);
};
HKCATool.CheckNominationDialog.prototype.onMessageInputResize = function () {
this.updateSize();
};
HKCATool.CheckNominationDialog.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight(true);
};
HKCATool.CheckNominationDialog.prototype.getActionProcess = function (action) {
if (action === 'save') {
return new OO.ui.Process(async function () {
let response = await HKCATool.saveNominationCheck();
if (!response) {
this.close();
}
}, this);
} else if (action === 'cancel') {
return new OO.ui.Process(function () {
this.close();
}, this);
}
return HKCATool.CheckNominationDialog.super.prototype.getActionProcess.call(this, action);
};
HKCATool.CheckNominationDialog.prototype.getTearnDownProcess = function (data) {
return HKCATool.CheckNominationDialog.super.prototype.getTearnDownProcess.call(this, data);
};
mw.util.addCSS('.checklist-field .oo-ui-fieldLayout-field { width: 80% !important; }');
},
/**
* 顯示核分提名對話框。
* @param nomData 提名資料。
* @param multiCheckStatus 多選核對狀態字串。
*/
showCheckNominationDialog: async function (nomData, multiCheckStatus) {
// 清空原有的items
HKCATool.checkNominationDialogContent.clearItems();
HKCATool.nominations.length = 0;
HKCATool.checkNominationDialog = new HKCATool.CheckNominationDialog({
size: 'large',
padded: true,
scrollable: true,
});
// 加入新的items
const field = await HKCATool.generateChecklistFieldset(nomData);
HKCATool.checkNominationDialogContent.addItems([field]);
HKCATool.windowManager.addWindows([HKCATool.checkNominationDialog]);
const instance = HKCATool.windowManager.openWindow(HKCATool.checkNominationDialog, multiCheckStatus ? {
title: HKCATool.convByVar({
hant: '核對分數,' + multiCheckStatus + '(維基香港內容獎小工具)',
hans: '核对分数,' + multiCheckStatus + '(维基香港内容奖小工具)',
}),
} : undefined);
await instance.closed;
},
/**
* 腳本入口。
*/
init: function () {
HKCATool.pageName = mw.config.get('wgPageName');
if (HKCATool.pageName !== 'Wikipedia:香港維基人佈告板/維基香港內容獎' && HKCATool.pageName !== 'Wikipedia:香港維基人佈告板/維基香港內容獎/登記處') return; // 非目標頁面,不執行
mw.loader.using('ext.gadget.HanAssist').then((require) => {
const {convByVar} = require('ext.gadget.HanAssist');
HKCATool.convByVar = convByVar;
// Initialize OOUI custom widgets
HKCATool.initDynamicWidthTextInputWidget();
HKCATool.initRuleCheckboxInputWidget();
// Initialize dialogs
HKCATool.initNewNominationDialog();
HKCATool.initEditNominationDialog();
HKCATool.initCheckNominationDialog();
// Append the window manager element to the body
HKCATool.windowManager = new OO.ui.WindowManager();
$(document.body).append(HKCATool.windowManager.$element);
// 添加提名按鈕
HKCATool.addEditButtonsToPage();
});
},
api: new mw.Api({userAgent: 'HKCATool/1.1.0'}), // MediaWiki API實例
pageName: '', // JS運行的當前頁面
windowManager: null, // Window manager for OOUI dialogs
newNominationDialog: null, // 新提名dialog
editNominationDialog: null, // 修改提名dialog
editNominationDialogContent: new OO.ui.FieldsetLayout(), // 修改提名dialog的內容池
checkNominationDialog: null, // 檢查提名dialog
checkNominationDialogContent: new OO.ui.FieldsetLayout(), // 檢查提名dialog的內容池
queried: null, // 查詢到的提名
nominations: [], // 提名
convByVar: null, // 簡繁轉換
multiNomCheckOngoing: false, // 多選核對進度狀態
multiNomCheckChanged: false, // 多選核對是否有變更
};
$(HKCATool.init);
})();