跳转到内容

User:What7what8/darkmodefixtool.js

维基百科,自由的百科全书

这是本页的一个历史版本,由What7what8留言 | 贡献2024年7月20日 (六) 20:16编辑。这可能和当前版本存在着巨大的差异。

注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
$(document).ready(function() {
	$.getJSON(mw.config.get("wgServer") + mw.config.get("wgScriptPath") + "/api.php?action=query&prop=revisions&format=json&titles=" + mw.config.get("wgPageName") + "&rvlimit=1&rvslots=*&rvprop=content|ids|timestamp&meta=tokens&type=csrf", function(data) {
		let token = data.query.tokens.csrftoken
		var js2 = data.query.pages[mw.config.get("wgArticleId")].revisions[0];
		let baserevid = js2.revid
		let basetimestamp = js2.timestamp
		var wikitext = js2.slots.main['*'];
		// REGEX
		var imgLink = /(?:File:|Image:)([\s\S]+?(?:\.png|\.jpg|\.svg|\.jpeg|\.gif|\.tiff|\.webp|\.xcf|\.pdf))/gim;
		var imgTemp = /([\s\S]+?(\.png|\.jpg|\.svg|\.jpeg|\.gif|\.tiff|\.webp|\.xcf|\.pdf))/gim;
		var linkAndTemp = /\[\[[\s\S]+?\]\]|{{[\s\S]+?}}/gim;
		function isRangeInRange(innerStart, innerEnd, outerStart, outerEnd) {
			return innerStart >= outerStart && innerEnd <= outerEnd;
		}
		function replaceBetween(input, replacement) {
			replacement = replacement.filter(function(currentValue, index, array){
				let [text, start, end] = currentValue;
				if (input.substring(start, end) === text) {
					return false
				}
				for (let i = 0; i < array.length; i++) {
					let [text1, start1, end1] = array[i];
					if (i !== index && isRangeInRange(start, end, start1, end1)) {
						return false
					}
				}
				return true
			})
			let res = [];
			let i = 0;
			for (let k = 0; k < replacement.length; k++) {
				let [text, start, end] = replacement[k];
				res.push(input.slice(i, start) + text);
				i = end;
			}
			res.push(input.slice(i));
			return res.join("")
		}
		function extractNestedStrings(inputStr, pattern = "[]", include = false) {
			//extract template or link from wikitext, example: 'abc[[a[[b]][[[aaa]]][abc]cde[[f[[g]]]]]]abc' -> ['b', '[aaa', 'g', 'f[[g]]', 'a[[b]][[[aaa]]][abc]cde[[f[[g]]]]']
			var openIndices = [];
			var openBracketCount = 0;
			var closeBracketCount = 0;
			var result = [];
			for (var i = 0; i < inputStr.length; i++) {
				var char = inputStr.charAt(i);
				if (char === pattern.charAt(0)) {
					openBracketCount++;
					if (openBracketCount === 2) {
						openBracketCount = 0;
						openIndices.push(include ? i - 1 : i + 1);
					}
				} else {
					openBracketCount = 0;
				}
				if (char === pattern.charAt(1)) {
					closeBracketCount++;
					if (closeBracketCount === 2) {
						closeBracketCount = 0;
						result.push(
							[inputStr.substring(openIndices[openIndices.length - 1], include ? i + 1 : i - 1),
							openIndices[openIndices.length - 1],
							include ? i + 1 : i - 1
							]
							);
						openIndices.pop();
					}
				} else {
					closeBracketCount = 0;
				}
			}
			return result;
		}

		function filterImage(mode) {
			var result = [];
			var pattern = (mode === 'temp') ? '{}' : '[]';
			var elist = extractNestedStrings(wikitext, pattern);
			for (var i = 0; i < elist.length; i++) {
				let [ele, start, end] = elist[i];
				let e = ele.replaceAll("{{skin-invert}}", "|class=skin-invert").replaceAll(linkAndTemp, "");
				var args = e.split("|");
				for (var j = 0; j < args.length; j++) {
					var arg = args[j];
					var r = (mode === 'temp') ? [...arg.split("=").at(-1).matchAll(imgTemp)] : [...arg.split("=").at(-1).matchAll(imgLink)];
					if (r.length !== 0 && !r[0][1].includes("://")) {
						let inverted = false
						if (mode === 'temp') {
							if (arg.includes("skin-invert") || (j + 1 !== args.length && /class\s*=.*skin-invert/.test(args[j + 1]))) {
								inverted = true
							}
						} else {
							if (e.includes('skin-invert')) {
								inverted = true
							}
						}
						var secondInvertWarn = 0;
						if (e.includes('skin-invert') && mode === 'temp') {
							secondInvertWarn = 1;
							if (!inverted) {
								secondInvertWarn = 2;
							}
						}
						let code = ele.replaceAll("\n", "</nowiki><br /><nowiki>").replaceAll(r[0][1], '</nowiki><span style="color: orange">' + r[0][1] + '</span><nowiki>').replaceAll("skin-invert", '</nowiki><span style="color: cyan">skin-invert</span><nowiki>')
						result.push({
							'target': r[0][1].replace("File:","").replace("Image:",""),
							'inverted': inverted,
							'warn': [mode === 'temp' ? e.includes("class") : false, secondInvertWarn],
							'code': (mode === 'temp') ? '{{' + code + '}}' : '[[' + code + ']]'
						});
					}
				}
			}
			return result;
		}

		function genOutput(mode) {
			let gen = ""
			let list = filterImage(mode)
			for (var i = 0; i < list.length; i++) {
				var e = list[i];
				var warn = '';
				if (e.warn[0] === true) {
					warn += '{{Ombox|type = notice|text = 留意反色有否干擾原來的class}}';
				}
				if (e.warn[1] === 1) {
					warn += '{{Ombox|type = notice|text = 留意有否二次反色}}';
				} else if (e.warn[1] === 2) {
					warn += '{{Ombox|type = content|text = 注意可能二次反色}}';
				}
				gen += '{{hr|5}}' + warn + '{{HideH|代碼:}}<nowiki>' + e.code + '</nowiki>{{HideF}} <div style="background-color: '+ (mode === 'temp' ? '#202122' : "#101418") +';"><div class="toolimg' + (e.inverted ? ' skin-invert' : '') + '" data-target="' + e.target + '" data-before-change-invert=' + e.inverted + ' data-mode=' + mode + '> [[File:' + e.target + '|250x250px]]</div></div>';
			}
			return gen
		}
		var output = genOutput("temp") + genOutput("link");
		var url = mw.config.get("wgServer") + mw.config.get("wgScriptPath")+'/api.php';
		var myobj = {
			"action": "parse",
			"format": "json",
			"formatversion": 2,
			"text": output,
			"pst": "true",
			"disableeditsection": "true",
			"disabletoc": "true",
			"uselang": mw.config.get("wgPageViewLanguage"),
			"useskin": "vector-2022",
			"contentmodel": "wikitext",
			"prop": "text"
		};
		$.ajax({
			url: url,
			type: 'POST',
			data: myobj,
			success: function(data) {
				$('body').append('<div id="toolimg-panel">' + data.parse.text + '</div>')
				$(".toolimg").each(function(index) {
					$(this).after('<input type="checkbox" id="toolimg-checkbox-' + index + '"/><label style="color: white;" for="toolimg-checkbox-' + index + '">反色</label><button type="button" id="toolimg-eyedropper-' + index + '">選擇背景顏色</button>')
					if ($(this).hasClass("skin-invert")) {
						$('#toolimg-checkbox-' + index)[0].checked = true;
					} else $('#toolimg-checkbox-' + index)[0].checked = false;
					let toolimg = $(this)
					$('#toolimg-checkbox-' + index).on('change', function() {
						if (this.checked) {
							if (!toolimg.hasClass("skin-invert")) toolimg.addClass("skin-invert")
						} else {
							if (toolimg.hasClass("skin-invert")) toolimg.removeClass("skin-invert")
						}
					});
					const eyeDropper = new EyeDropper()
					$('#toolimg-eyedropper-' + index).on('click', async function() {
						try {
						  const selectedColor = await eyeDropper.open();
						  toolimg.parent().attr("style", "background-color: " + selectedColor.sRGBHex + ";")
						} catch (err) {
						  console.log('eye dropper cancelled')
						}
					})
				})
				$("#toolimg-panel").dialog({
					autoOpen: false,
					height: 1080 * 0.5,
					buttons: {
						"提交": function() {
							let changelist = []
							$(".toolimg").each(function(index) {
								changelist.push([$(this).attr('data-target'), $(this).attr("data-mode"), $(this).hasClass("skin-invert"), $(this).attr('data-before-change-invert') === 'true' ? true : false]);
							})
							let newwikitext = wikitext
							let linklist = extractNestedStrings(wikitext, "[]", true)
							let templist = extractNestedStrings(wikitext, "{}", true)
							let lastReach = 0
							let replacementList = []
							for (let s = 0; s < templist.length; s++) {
								let [temp, start, end] = templist[s]
								let templistArg = temp.split("|")
								for (let i = 0; i < templistArg.length; i++) {
									for (let j = lastReach; j < changelist.length; j++) {
										let [target, mode, afterChangeInvert, beforeChangeInvert] = changelist[j]
										if (templistArg[i].includes(target) && mode === 'temp') {
											//change inverted to not invert
											if (afterChangeInvert === false && beforeChangeInvert === true) {
												if (templistArg[i].includes("{{skin-invert}}")) {
													templistArg[i] = templistArg[i].replace("{{skin-invert}}", "")
												} else if (i + 1 !== templistArg.length && /class\s*=.*skin-invert/.test(templistArg[i + 1])) {
													templistArg[i] = templistArg[i].replace("skin-invert", "")
												}
											//change not inverted to invert
											} else if (afterChangeInvert === true && beforeChangeInvert === false) {
												if (i + 1 !== templistArg.length && 
												/class\s*=.*/.test(templistArg[i + 1]) &&
												!(/class\s*=.*skin-invert/.test(templistArg[i + 1]))) {
													templistArg[i + 1] += " skin-invert"
												} else if (!templistArg[i].includes("{{skin-invert}}")) {
													templistArg[i] = templistArg[i].replace(target,target+"{{skin-invert}}")
												}
											}
											lastReach++
											continue
										}
									}
								}
								replacementList.push([templistArg.join('|'), start, end])
							}
							for (let i = 0; i < linklist.length; i++) {
									let [link, start, end] = linklist[i]
									for (let j = lastReach; j < changelist.length; j++) {
										let [target, mode, afterChangeInvert, beforeChangeInvert] = changelist[j]
										if (link.includes(target) && mode === 'link') {
											//change inverted to not invert
											if (afterChangeInvert === false && beforeChangeInvert === true) {
												if (link.includes("{{skin-invert-image}}")) {
													link = link.replace("{{skin-invert-image}}", "")
												} else if (/class\s*=.*skin-invert/.test(link)) {
													link = link.replace("skin-invert", "")
												}
											//change not inverted to invert
											} else if (afterChangeInvert === true && beforeChangeInvert === false) {
												if ( 
												/class\s*=.*/.test(link) &&
												!(/class\s*=.*skin-invert/.test(link))) {
													link = link.replace(/class\s*=(.*?)\|/,"class=$1 skin-invert-image|")
												} else if (!link.includes("{{skin-invert}}")) {
													link = link.replace(target,target+"{{skin-invert-image}}")
												}
											}
											lastReach++
											continue
										}
									}
									replacementList.push([link, start, end])
							}
							$(this).dialog("close");
							var editurl = mw.config.get("wgServer") + mw.config.get("wgScriptPath")+'/api.php';
							var editobj = {
								"action": "edit",
								"title": mw.config.get("wgPageName"),
								"format": "json",
								"formatversion": 2,
								"variant": "zh",
								"text": replaceBetween(newwikitext,replacementList),
								"summary": "dark mode fix",
								"token": token,
								"basetimestamp": basetimestamp,
								"baserevid": baserevid,
								"nocreate": true,
								"minor": true,
								"uselang": "zh",
								"useskin": "vector-2022"
							};
							$.ajax({
								url: editurl,
								type: 'POST',
								data: editobj,
								success: function(data) {
									location.reload();
									mw.notify("修改成功了!!!!!")
								}
							});
						}
					}
				})
			},
			error: function(error) {
				console.error(error);
			}
		});
	});
	$(document).ajaxStop(function() {
		if (!$("#darkmodefix").length) {
		mw.util.addPortlet('darkmodefix', 'Dark Mode Fix Tool', '#skin-client-prefs-skin-theme');
		const p = mw.util.addPortletLink('darkmodefix', "javascript:;", 'Skin-invert Image Tool')
		let open = false
		$(p).on("click", function() {
			if ($("#toolimg-panel").length) {
				if (!open) {
					$("#toolimg-panel").dialog("open");
					open = true
				} else {
					$("#toolimg-panel").dialog("close");
					open = false
				}
			}
		});
	}
	});
})