User:LBLaiSiNanHai/LetWiki-latest.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// 本工具将不在中文维基更新,因为我的中文维基账户被永久封禁。:(
// 当前版本为In Development版本,功能不完全,公开版更新频率:作者每写完并测试完一个功能更新一次
// 作者:LBLaiSiNanHai 开发:LBLaiSiNanHai 策划:LBLaiSiNanHai 版权持有人:LBLaiSiNanHai
// 当前版本许可证:All right reserved
// 预计正式发布后许可证:BSD 3 Clause (New or Revised BSD)
letwiki = {
localsettings: {
wgEnableAllFeatureForcely: false
},
preferences: {
features_enabled: ['rollback', 'rollbackTo', 'protectOrUnprotect', 'requestProtectOrUnprotect', 'csd', 'warn', 'reportAnm', 'reportVip', 'requestEdit', 'move', 'publishUserDraft', 'queryDelPage']
},
allReady: false,
codexLoaded: false,
oojsLoaded: false,
oojsuiLoaded: false,
ooWm: null,
mwApi: null,
editToken: "",
moveToken: "",
rollbackToken: "",
protectToken: "",
hooks: {
loaded: [],
ready: [],
preInitUI: [],
postInitUI: [],
preAct: [],
postAct: []
},
action: "view",
title: "",
username: "",
usergroups: [],
actorCfg: {}
};
String.prototype.toFirstCharUpperCase = function () {
return this.split('').map(function (char, idx) {return idx == 0 ? char.toUpperCase() : char}).join('');
}
lw = letwiki;
function wfHandleApiError(op, err) {
let pattern = "无法$op:未知错误 $err";
switch (err) {
case "http":
pattern = "无法$op:网络错误";
break;
case "badvalue":
case "missingparam":
case "mustpostparam":
pattern = "无法$op: 本工具调用的API已更新,可能您的工具太旧或工具尚未适配";
break;
case "permissiondenied":
case "protectedpage":
pattern = "无法$op: 没有足够的权限";
break;
case "abusefilter-warning":
pattern = "无法$op: 被过滤器警告,请重复操作以继续";
break;
case "abusefilter-disallowed":
pattern = "无法$op: 被过滤器阻止";
break;
default:
break;
}
OO.ui.alert(pattern.replace("$op", op).replace("$err", err));
}
function wfDoRollbackCurrRev() {
console.log("LetWiki 开始执行实际回退操作");
if (lw.actorCfg.rollback.useRealRollback) {
console.log("LetWiki 正使用真实回退API进行回退")
let who = lw.actorCfg.rollback.lastPageRevData.user;
let summary = $("#" + lw.actorCfg.rollback.currPopoverIdBase + "-summary").val();
console.log("LetWiki 已经准备好回退所需数据");
console.log("LetWiki 发送回退请求");
lw.mwApi.post({
action: "rollback",
token: lw.rollbackToken,
title: lw.title,
user: who,
summary: summary
}).done(function () {
console.log("LetWiki 成功回退了该页面的当前编辑");
OO.ui.alert("回退成功,建议刷新查看效果");
}).fail(function (result) {
console.log("LetWiki 回退该页面的当前编辑失败了");
wfHandleApiError("回退", result);
});
} else {
console.log("LetWiki 正使用编辑API进行伪回退");
let summary = $("#" + lw.actorCfg.rollback.currPopoverIdBase + "-summary").val();
console.log("LetWiki 正在获取上上一个修订版本的内容");
lw.mwApi.get({
action: "query",
prop: "revisions",
rvprop: "content",
rvlimit: 2,
rvdir: "older",
titles: lw.title
}).done(function (result) {
console.log("LetWiki 收到关于上上个修订版本查询请求的回复");
let rev = result.query.pages[Object.keys(result.query.pages)[0]].revisions[1];
let cont = rev['*'];
console.log("LetWiki 已经得到上上一个修订版本的内容");
console.log("LetWiki 现在开始覆盖页面,执行实际回退");
lw.mwApi.post({
action: "edit",
token: lw.editToken,
title: lw.title,
text: cont,
summary: summary
}).then(function () {
console.log("LetWiki 成功回退了该页面的当前编辑");
OO.ui.alert("回退成功,建议刷新查看效果");
}).fail(function (result) {
console.log("LetWiki 编辑该页面以回退时出错");
wfHandleApiError("回退", result);
});
}).fail(function (result) {
console.log("LetWiki 没能成功查询到上上个修订版本查询请求的内容");
wfHandleApiError("(回退依赖项)查询上上个修订版本的内容", result);
console.log("LetWiki 由于依赖不满足,回退终止");
});
}
}
function wfPageRollbackCaHandler(event) {
event.preventDefault();
console.log("LetWiki 正在构造和显示回退Popover");
lw.actorCfg.rollback.currPopoverIdBase = 'letwiki-rollback-popover-' + Math.floor(Math.random() * 0x6b43fecd2).toString(16);
$("#letwiki-ca-rollback").append(lw.actorCfg.rollback.constantsExported.ROLLBACK_POPOVER1_HTML.replaceAll("$idBase", lw.actorCfg.rollback.currPopoverIdBase));
let popoverCloseHandler = function (event) {
if ($("#" + lw.actorCfg.rollback.currPopoverIdBase).is($(event.target)) || $("#" + lw.actorCfg.rollback.currPopoverIdBase).has($(event.target)).length > 0) {
return;
}
console.log("LetWiki 回退Popover因外部点击而关闭");
$("#" + lw.actorCfg.rollback.currPopoverIdBase).remove();
$(document.body).off("click", popoverCloseHandler);
return;
}
setTimeout(function () {$(document.body).click(popoverCloseHandler)}, 15);
$("#" + lw.actorCfg.rollback.currPopoverIdBase + "-btn").click(function () {
console.log("LetWiki 回退操作已被确认,即将开始");
wfDoRollbackCurrRev();
console.log("LetWiki 关闭回退Popover因为回退结束");
$("#" + lw.actorCfg.rollback.currPopoverIdBase).remove();
$(document.body).off("click", popoverCloseHandler);
});
console.log("LetWiki 回退Popover骨架已搭建并显示");
console.log("LetWiki 开始获取当前修订版的基础信息以完善摘要");
lw.mwApi.get({
action: "query",
prop: "revisions",
rvprop: "user|comment|size",
rvlimit: 1,
rvdir: "older",
titles: lw.title
}).done(function (result) {
wfEnableCdxBtn($("#" + lw.actorCfg.rollback.currPopoverIdBase + "-btn"));
let rev = result.query.pages[Object.keys(result.query.pages)[0]].revisions[0];
lw.actorCfg.rollback.lastPageRevData = rev;
$("#" + lw.actorCfg.rollback.currPopoverIdBase + "-summary").attr("placeholder", "请输入回退摘要").val(`Rollback edit made by ${rev.user} (${rev.size} bytes, summary: ${rev.comment})`).removeAttr("disabled");
console.log("LetWiki 成功获取当前页面最近一次编辑的数据并填充回退摘要");
console.log("LetWiki 回退Popover现在所有可操作性已解锁");
}).fail(function (result) {
console.log("LetWiki 无法获取当前页面最近一次编辑的数据");
wfHandleApiError("查询修订版本数据", result);
wfEnableCdxBtn($("#" + lw.actorCfg.rollback.currPopoverIdBase + "-btn"));
$("#" + lw.actorCfg.rollback.currPopoverIdBase + "-summary").attr("placeholder", "请输入回退摘要").val(`回退编辑`).removeAttr("disabled");
console.log("LetWiki 回退Popover现在所有可操作性已解锁");
})
}
function wfInitRollbackUI() {
const ROLLBACK_POPOVER1_HTML = `
<div id="$idBase" class="cdx-popover">
<div class="cdx-popover__header">
<h4 class="cdx-popover__header__title">回退<sup class="cdx-info-chip cdx-info-chip--success">可用</sup></h4>
<hr/>
</div>
<div class="cdx-popover__body">
<div class="cdx-text-input">
<input type="text" disabled id="$idBase-summary" class="cdx-text-input__input" style="margin-bottom: 15px;" placeholder="正在查询..."></input>
</div>
<div id="$idBase-btn" class="cdx-button cdx-button--fake-button cdx-button--fake-button--disabled cdx-button--action-progressive cdx-button--weight-primary cdx-button--size-large">确认</div>
</div>
</div>
`
const PAGE_CA_HTML = `
<li id="letwiki-ca-rollback" class="mw-list-item">
<a href="javascript:0;">回退当前版本</a>
</li>
`;
console.log("LetWiki 回退功能演员UI开始初始化");
lw.actorCfg.rollback = {
useRealRollback: (function(){
console.log(lw.usergroups.includes("rollbacker") ? "LetWiki 检测到拥有回退员权限,将自动使用真正的回退API" : "LetWiki 检测到没有回退员权限,将使用普通编辑代替回退API");
return lw.usergroups.includes("rollbacker");
})(),
currPopoverIdBase: "",
lastPageRevData: {},
constantsExported: {
ROLLBACK_POPOVER1_HTML: ROLLBACK_POPOVER1_HTML
}
};
if (lw.action == "view") {
$("#p-views .vector-menu-content-list").append(PAGE_CA_HTML);
$("#letwiki-ca-rollback a").click(wfPageRollbackCaHandler);
console.log("LetWiki 已布置回退按钮并监听点击");
} else {
console.log("LetWiki 回退模块目前在这个动作没有用途");
}
console.log("LetWiki 回退功能演员UI成功初始化");
}
function wfDoRollbackToAction() {
let s = $("#" + lw.actorCfg.rollbackTo.currPopoverIdBase + "-summary").val();
console.log("LetWiki 已经暂存回退所需的基本信息");
console.log("LetWiki 开始提取目标修订版本的内容");
lw.mwApi.get({
action: "parse",
oldid: lw.actorCfg.rollbackTo.targetRevid,
prop: "wikitext"
}).done(function(result) {
console.log("LetWiki 成功提取到目标修订版本的内容");
console.log("LetWiki 正在覆盖页面当前内容以实际回退到目标修订版本");
lw.mwApi.post({
action: "edit",
token: lw.editToken,
title: lw.title,
text: result.parse.wikitext["*"],
summary: s
}).done(function () {
console.log("LetWiki 页面已经被编辑并回退到目标修订版本");
OO.ui.alert("回退成功,建议刷新查看效果");
}).fail(function (result) {
console.log("LetWiki 没能编辑该页面的内容以执行回退");
wfHandleApiError("回退", result);
});
}).fail(function (result) {
console.log("LetWiki 获取目标修订版本的内容失败");
wfHandleApiError("(回退依赖项)获取目标修订版本的内容", result);
console.log("LetWiki 由于没有目标内容,回退终止");
});
}
function wfRollbackToLinkClickHandler(event) {
console.log("LetWiki 回退到链接被点击,准备构造回退到确认Popover")
event.preventDefault();
let revE = $("[data-mw-revid]:has(.mw-history-histlinks [letwiki-rollbackto-link=\"" + $(this).attr("letwiki-rollbackto-link") + "\"])")
lw.actorCfg.rollbackTo.targetRevid = revE.attr("data-mw-revid");
console.log("LetWiki 已经获取并保存将被回退到的修订版本编号");
function wfRollbackToPopoverCloseHandler(event) {
if ($("#" + lw.actorCfg.rollbackTo.currPopoverIdBase).is($(event.target)) || $("#" + lw.actorCfg.rollbackTo.currPopoverIdBase).has($(event.target)).length > 0) {
return;
}
console.log("LetWiki 关闭回退到Popover因点击在外部");
$("#" + lw.actorCfg.rollbackTo.currPopoverIdBase).remove();
$(document.body).off("click", wfRollbackToPopoverCloseHandler);
}
lw.actorCfg.rollbackTo.currPopoverIdBase = "letwiki-rollbackto-popover-" + Math.floor(Math.random() * 0x6b43fecd2).toString(16)
let author = revE.find(".history-user bdi").text();
let size = revE.find(".history-size").attr("data-mw-bytes");
let summary = revE.find(".comment").text();
let s = `Rollback to edit made by ${author} (${size} bytes, summary: ${summary})`;
$(this).parent().append(lw.actorCfg.rollbackTo.constantsExported.ROLLBACKTO_POPOVER1_HTML.replaceAll("$idBase", lw.actorCfg.rollbackTo.currPopoverIdBase).replace("$v", s).replace("$author", author));
console.log("LetWiki 已填充默认摘要并展示回退到Popover");
setTimeout(function () {$(document.body).click(wfRollbackToPopoverCloseHandler);}, 15);
$("#" + lw.actorCfg.rollbackTo.currPopoverIdBase + "-btn").click(function () {
console.log("LetWiki 回退到操作被确认,现在终止处理Popover外部点击自动关闭");
$(document.body).off("click", wfRollbackToPopoverCloseHandler);
wfDoRollbackToAction();
console.log("LetWiki 关闭回退到Popover因回退到已经结束");
$("#" + lw.actorCfg.rollbackTo.currPopoverIdBase).remove();
});
console.log("LetWiki 已监听回退到Popover的各类操作,交互功能已全部可用");
}
function wfPutRollbackToLinkTo(_, e) {
e = $(e);
e.append(lw.actorCfg.rollbackTo.constantsExported.ROLLBACKTO_LINK_HTML.replace("$rand", Math.floor(Math.random() * 0x6b43fecd2).toString(16)));
let link = e.find('a[letwiki-rollbackto-link]');
link.click(wfRollbackToLinkClickHandler);
}
function wfInitRollbackToUI() {
const ROLLBACKTO_POPOVER1_HTML = `
<div id="$idBase" class="cdx-popover">
<div class="cdx-popover__header">
<h4 class="cdx-popover__header__title">回退到<bdi>$author</bdi>的修订版本<sup class="cdx-info-chip cdx-info-chip--success">可用</sup></h4>
<hr/>
</div>
<div class="cdx-popover__body">
<div class="cdx-text-input">
<input type="text" id="$idBase-summary" class="cdx-text-input__input" style="margin-bottom: 15px;" placeholder="回退摘要" value="$v"></input>
</div>
<div id="$idBase-btn" class="cdx-button cdx-button--fake-button cdx-button--fake-button--enabled cdx-button--action-progressive cdx-button--weight-primary cdx-button--size-large">确认</div>
</div>
</div>
`
const ROLLBACKTO_LINK_HTML = `
<span>
<a href="javascript:0;" letwiki-rollbackto-link="$rand">回退到此版本</a>
</span>
`
console.log("LetWiki 回退到功能演员UI开始初始化");
lw.actorCfg.rollbackTo = {
currPopoverIdBase: "",
targetRevid: 0,
constantsExported: {
ROLLBACKTO_POPOVER1_HTML: ROLLBACKTO_POPOVER1_HTML,
ROLLBACKTO_LINK_HTML: ROLLBACKTO_LINK_HTML
}
};
if (lw.action == "history") {
console.log("LetWiki 正给每个修订版本条目前插入回退到链接");
let revs = $("[data-mw-revid] .mw-history-histlinks");
revs.each(wfPutRollbackToLinkTo);
console.log("LetWiki 每个修订版本都被成功插入回退到链接");
} else {
console.log("LetWiki 当前动作下回退到模块无需工作");
}
console.log("LetWiki 回退到功能演员UI已经初始化完毕");
}
function wfInitUI() {
console.log("LetWiki 开始初始化所有功能的UI")
wfExecHook('preInitUI');
lw.preferences.features_enabled.forEach(function (feature) {
let error = false;
let func = new Function(`wfInit${feature.toFirstCharUpperCase()}UI();`);
try {
func();
} catch (e) {
error = true;
console.log(`LetWiki 功能 ${feature} 演员的UI未能初始化成功: ${e.message}`);
}
if (!error) {
console.log(`LetWiki 功能 ${feature} 演员的UI初始化成功`);
}
});
console.log("LetWiki UI现在已经完全可用")
wfExecHook('postInitUI');
}
function wfExecHook(p) {
lw.hooks[p].forEach(function (hook) {hook.call(lw)});
console.log(`LetWiki '${p}' 钩子执行好了`);
}
function wfEnableCdxBtn(btn) {
btn.removeClass("cdx-button--fake-button--disabled").addClass("cdx-button--fake-button--enabled");
}
function wfDisableCdxBtn(btn) {
btn.addClass("cdx-button--fake-button--disabled").removeClass("cdx-button--fake-button--enabled");
}
function wfReadyCallback() {
console.log("LetWiki 主程序已加载");
wfExecHook('loaded');
mw.loader.load("https://unpkg.com/@wikimedia/codex@2.3.3/dist/codex.style.css", "text/css");
lw.codexLoaded = true;
if (mw.loader.getState('oojs') == 'ready') {
lw.oojsLoaded = true;
if (mw.loader.getState('oojs-ui') == 'ready') {
lw.oojsuiLoaded = true;
}
}
console.log("LetWiki 已经加载并准备好所有需要的静态资源");
lw.mwApi = new mw.Api();
console.log("LetWiki API包装器现在可用");
lw.mwApi._post = lw.mwApi.post;
lw.mwApi.post = function (data) {
if (data.summary) {
data.summary = data.summary + " (via [[mw:User:LBLaiSiNanHai/LetWiki-latest.js|LetWiki]])";
}
return lw.mwApi._post(data);
}
console.log("LetWiki 已经覆盖本地API包装器的部分函数以确保编辑摘要包含小工具名称");
let api = lw.mwApi;
api.getEditToken().then(function (token) {lw.editToken = token;});
api.getToken('move').then(function (token) {lw.moveToken = token;});
api.getToken('rollback').then(function (token) {lw.rollbackToken = token;});
api.getToken('protect').then(function (token) {lw.protectToken = token;});
console.log("LetWiki 成功获取并保存所有令牌");
lw.action = mw.config.get("wgAction");
lw.title = mw.config.get("wgRelevantPageName");
console.log("LetWiki 已经获取当前页面的信息");
lw.username = mw.config.get("wgUserName");
lw.usergroups = mw.config.get("wgUserGroups");
console.log("LetWiki 已经获取用户的信息");
console.log("LetWiki 核心准备好了");
lw.allReady = true;
wfExecHook('ready');
wfInitUI();
}
mw.loader.enqueue(['mediawiki.base', 'mediawiki.page.ready'], wfReadyCallback);