- 欢迎来到偶像大师中文维基,本站仍在筹备阶段,如有兴趣参与建设可加群申请账号:542540342
MediaWiki:Gadget-EditDraft.js
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
/* eslint-disable no-magic-numbers */
/* global mw */
/* jshint ignore:start */
// <pre>
"use strict";
try {
const statesMap = {
0: "尚未发出请求",
1: "已发出请求但未收到数据",
2: "已收到 header",
3: "接收数据中",
4: "数据接收完成",
};
(async () => {
const userId = mw.config.get("wgUserId");
if (typeof userId !== "number" || !/^\d+$/.test("" + userId) || userId <= 0) {
return;
}
if (!["edit", "submit"].includes(mw.config.get("wgAction"))) {
return;
}
let style;
try {
style = await $.ajax({
url: `${mw.config.get("wgServer")}${mw.config.get("wgScriptPath")}/MediaWiki:Gadget-EditDraft.css?action=raw&ctype=text/css`,
type: "GET",
cache: true,
});
} catch (e) {
throw new Error(`无法加载 CSS:\n 加载进度:${statesMap[e.readyState]}\n 服务器返回代码:${e.status}${e.statusText === "error" ? "" : `(${e.statusText})`}`);
}
class DraftStorage {
constructor(userId) {
const legalKeys = ["timerInterval", "drafts"];
this.userId = userId;
let data;
try {
data = JSON.parse(localStorage.getItem("AnnTools-QuickSaveDraft"));
} catch (_) {
console.debug(_);
}
let setBackFlag = false;
if (!$.isPlainObject(data)) {
data = {};
setBackFlag = true;
}
if (!data[userId]) {
data[userId] = {};
setBackFlag = true;
}
Object.keys(data).forEach((uId) => {
const uData = data[uId];
if (typeof uData.timerInterval !== "number" || !/^\d+$/.test("" + uData.timerInterval) || uData.timerInterval <= 0) {
uData.timerInterval = 3;
setBackFlag = true;
}
if (!$.isPlainObject(uData.drafts)) {
uData.drafts = {};
setBackFlag = true;
}
Object.keys(uData.drafts).forEach((pagename) => {
if (!$.isPlainObject(uData.drafts[pagename])) {
delete uData.drafts[pagename];
setBackFlag = true;
return;
}
Object.keys(uData.drafts[pagename]).forEach((section) => {
if (!$.isPlainObject(uData.drafts[pagename][section])
|| typeof uData.drafts[pagename][section].timestamp !== "number" || !/^\d+$/.test("" + uData.drafts[pagename][section].timestamp) || uData.drafts[pagename][section].timestamp <= 0
|| typeof uData.drafts[pagename][section].draft !== "string") {
delete uData.drafts[pagename][section];
setBackFlag = true;
return;
}
});
});
Object.keys(uData).forEach((key) => {
if (!legalKeys.includes(key)) {
delete uData[key];
setBackFlag = true;
}
});
});
this.data = data;
if (setBackFlag) {
this.setData();
}
}
setData() {
localStorage.setItem("AnnTools-QuickSaveDraft", JSON.stringify(this.data));
}
getTimerInterval() {
return this.data[this.userId].timerInterval;
}
setTimerInterval(interval) {
if (this.data[this.userId].timerInterval !== interval) {
this.data[this.userId].timerInterval = interval;
this.setData();
}
}
getDraft(pagename, section) {
return $.isPlainObject(this.data[this.userId].drafts[pagename]) && $.isPlainObject(this.data[this.userId].drafts[pagename][section]) ? this.data[this.userId].drafts[pagename][section].draft : null;
}
setDraft(pagename, section, text) {
if (!$.isPlainObject(this.data[this.userId].drafts[pagename])) {
this.data[this.userId].drafts[pagename] = {};
}
if (!$.isPlainObject(this.data[this.userId].drafts[pagename][section])) {
this.data[this.userId].drafts[pagename][section] = {};
}
this.data[this.userId].drafts[pagename][section].timestamp = new Date().getTime();
this.data[this.userId].drafts[pagename][section].draft = text;
this.setData();
}
getTimestamp(pagename, section) {
return $.isPlainObject(this.data[this.userId].drafts[pagename]) && $.isPlainObject(this.data[this.userId].drafts[pagename][section]) ? this.data[this.userId].drafts[pagename][section].timestamp : null;
}
}
class IntervalRegistry {
constructor() {
this.intervalRegistry = {};
const date = new Date();
const now = date.getTime();
date.setMilliseconds(0);
date.setSeconds(date.getSeconds() + 1);
setTimeout(() => {
this.runInterval();
setInterval(() => {
this.runInterval();
}, 1000);
}, date.getTime() - now);
}
register(denominator, ...callbacks) {
const key = denominator + "";
const index = +(Math.random() + "").replace(/^.*?(\d+)$/, "$1");
if (!this.intervalRegistry[key]) {
this.intervalRegistry[key] = [];
}
const callback1 = callbacks[0];
let callback;
if (Array.isArray(callback1)) {
callback = callback1;
}
else {
callback = callbacks;
}
callback.forEach((cb) => {
this.intervalRegistry[key].push({ func: cb, index });
});
return index;
}
unregister(denominator, index) {
let result = false;
if (!index) {
const idx = denominator;
Object.keys(this.intervalRegistry).forEach((key) => {
if (this.deleteFunction(this.intervalRegistry[key], idx)) {
result = true;
}
});
}
else if (this.deleteFunction(this.intervalRegistry[denominator], index)) {
result = true;
}
return result;
}
deleteFunction(registry, index) {
for (const reg of registry) {
if (reg.index === index || reg.func === index) {
registry.splice(registry.indexOf(reg), 1);
return true;
}
}
return false;
}
runInterval() {
const now = Math.round(Date.now() / 1000);
Object.keys(this.intervalRegistry).forEach((key) => {
if (now % +key === 0) {
this.intervalRegistry[key].forEach((reg) => {
reg.func();
});
}
});
}
}
jQuery.fn.extend({
disable() {
return this.each((_, ele) => {
if (!$(ele).is("input,button")) { return; }
if ($(ele).parent().hasClass("oo-ui-widget-enabled")) { $(ele).parent().toggleClass("oo-ui-widget-enabled oo-ui-widget-disabled"); }
ele.disabled = true;
});
},
enable() {
return this.each((_, ele) => {
if (!$(ele).is("input,button")) { return; }
if ($(ele).parent().hasClass("oo-ui-widget-disabled")) { $(ele).parent().toggleClass("oo-ui-widget-enabled oo-ui-widget-disabled"); }
ele.disabled = false;
});
},
});
const draftStorage = new DraftStorage(userId);
const pagename = mw.config.get("wgPageName");
const section = $('[name="wpSection"]').val() || "(-1)全文";
const textarea = $("#wpTextbox1");
const buttonArea = $("<div/>", {
css: {
"margin-top": ".5em",
},
}).appendTo("#editform .editButtons");
const saveButton = inputConstruct({
"class": "QuickSaveDraftSaveButton",
val: "立即保存草稿",
attr: {
type: "button",
},
});
const recoverButton = inputConstruct({
"class": "QuickSaveDraftRecoverButton",
val: "暂无草稿",
attr: {
type: "button",
},
});
const rollbackButton = inputConstruct({
"class": "QuickSaveDraftRollbackButton",
val: "回退还原",
attr: {
type: "button",
},
});
const timerInput = inputConstruct({
"class": "QuickSaveDraftTimerInput",
val: draftStorage.getTimerInterval(), //默认值
maxlength: 2,
});
const timerSave = $("<span/>", {
id: "QuickSaveDraftTimerSave",
});
const lastRun = $("<div/>", {
"class": "QuickSaveDraftLastRunDiv",
text: "上次草稿保存于",
}).append($("<span/>", {
"class": "QuickSaveDraftLastRun",
})).append($("<span/>", {
"class": "QuickSaveDraftSame",
text: ",草稿内容与当前编辑内容一致",
}));
const pasueButton = inputConstruct({
"class": "QuickSaveDraftPauseButton",
val: "点击暂停自动保存",
attr: {
type: "button",
},
});
function inputConstruct(opt) {
const r = $("<span/>");
const input = $("<input/>", opt);
if (opt.attr && opt.attr.type === "button") {
r.addClass("oo-ui-widget oo-ui-widget-enabled oo-ui-inputWidget oo-ui-buttonElement oo-ui-buttonElement-framed oo-ui-labelElement oo-ui-buttonInputWidget");
input.addClass("oo-ui-inputWidget-input oo-ui-buttonElement-button");
} else {
r.addClass("oo-ui-widget oo-ui-widget-enabled oo-ui-inputWidget oo-ui-textInputWidget oo-ui-textInputWidget-type-text QuickSaveDraftTimer");
input.addClass("oo-ui-inputWidget-input");
}
r.append(input);
["on", "val", "disable", "enable"].forEach((key) => {
r[key] = input[key].bind(input);
});
return r;
}
function complement(_n, l) {
const n = _n + "";
if (n.length >= l) {
return n;
}
const b = '<span style="speak:none;visibility:hidden;color:transparent;">';
let c = "";
while (l > (n + c).length) {
c += "0";
}
return `${b + c}</span>${n}`;
}
function check() {
if (draftStorage.getDraft(pagename, section) === undefined) {
return;
}
const draft = draftStorage.getDraft(pagename, section);
if (draft === null) //检测是否同一章节
{
return recoverButton.disable().val("暂无草稿");
}
if (draft !== textarea.val()) {
//检测草稿是否一致
recoverButton.enable().val("立即还原草稿");
lastRun.find(".QuickSaveDraftSame").fadeOut();
} else {
recoverButton.disable().val("草稿内容一致");
lastRun.find(".QuickSaveDraftSame").fadeIn();
}
}
function save() {
const date = new Date(),
value = textarea.val();
draftStorage.setDraft(pagename, section, value);
check();
lastRun.fadeIn().find(".QuickSaveDraftLastRun").html(`今日${complement(date.getHours(), 2)}时${complement(date.getMinutes(), 2)}分,草稿长度为 ${draftStorage.getDraft(pagename, section).length || "-1(暂无)"} 字符`);
}
let originText = null;
let pause = false;
let pastTime = 0;
let timerSaveCode;
recoverButton.disable();
rollbackButton.disable();
buttonArea.append(saveButton).append(recoverButton).append(rollbackButton).append("每隔").append(timerInput).append("分钟保存一次").append(timerSave).append(pasueButton).append(lastRun);
const timestamp = draftStorage.getTimestamp(pagename, section);
const date = new Date(timestamp);
if (timestamp) {
lastRun.fadeIn().find(".QuickSaveDraftLastRun").html(`${date.getDate() === new Date().getDate() ? "今" : complement(date.getDate(), 2)}日${complement(date.getHours(), 2)}时${complement(date.getMinutes(), 2)}分,草稿长度为 ${draftStorage.getDraft(pagename, section).length || "-1(暂无)"} 字符`);
}
textarea.on("input change", function () {
check();
});
timerInput.on("input", () => {
let flag = false;
const input = timerInput.val();
if (/^\d+$/.test(input) && +input > 0) {
flag = true;
draftStorage.setTimerInterval(+input);
}
const result = flag ? ",保存成功!" : ",保存失败";
timerSave.text(result);
timerSave.removeClass("disapper");
if (timerSaveCode) {
window.clearTimeout(timerSaveCode);
}
timerSaveCode = window.setTimeout(() => {
timerSave.addClass("disapper");
}, 3000);
});
rollbackButton.on("click", () => {
if (rollbackButton.is(":disabled") || originText === null) {
return;
}
textarea.val(originText);
originText = null;
rollbackButton.disable();
check();
return false;
});
recoverButton.on("click", () => {
if (recoverButton.is(":disabled")) {
return;
}
const draft = draftStorage.getDraft(pagename, section);
if (draft === null) {
return;
}
originText = textarea.val();
textarea.val(draft);
rollbackButton.enable();
check();
return false;
});
saveButton.on("click", () => {
if (saveButton.is(":disabled")) {
return;
}
save(false);
return false;
});
pasueButton.on("click", () => {
if (pause) {
pasueButton.val("点击暂停自动保存");
pause = false;
} else {
pasueButton.val("点击继续自动保存");
pause = true;
}
});
$("<style/>", {
text: style,
}).appendTo(document.head);
const intervalRegistry = new IntervalRegistry();
intervalRegistry.register(60, () => {
if (pause) {
return;
}
const interval = draftStorage.getTimerInterval();
if (pastTime >= interval) {
save();
pastTime = 0;
} else {
pastTime++;
}
});
})();
} catch (e) {
$("#editButtons").append(`<p>草稿工具 3.0-alpha 出现问题:[${e.name}]${e.message}`);
}
// </pre>