Jump to content

User:LBLaiSiNanHai/LetWiki-latest.js

From mediawiki.org

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);