Modified Javascripts

来自Tsetien’s Wiki
跳转到导航 跳转到搜索

As claimed in Scattered Javascripts, I don’t know JavaScript, and thus, all of the following scripts were modified by AI.

Github Sort Content

Originally written by Rob Garrison here, then modified by Pharaoh2k here, then modified by Gemini for further revisions as follows.

github-sort-content.user.js
// ==UserScript==
// @name         GitHub Sort Content
// @version      3.2.2
// @description  A userscript that makes some lists & markdown tables sortable
// @license      MIT
// @author       Rob Garrison (modified by Pharaoh2k, then fixed by Gemini)
// @namespace    https://github.com/Mottie
// @match        https://github.com/*
// @match        https://gist.github.com/*
// @run-at       document-idle
// @grant        GM.addStyle
// @grant        GM_addStyle
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?updated=20180103
// @require      https://cdnjs.cloudflare.com/ajax/libs/tinysort/3.2.5/tinysort.min.js
// @require      https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=1108163
// @icon         https://github.githubassets.com/pinned-octocat.svg
// @updateURL    https://raw.githubusercontent.com/Mottie/GitHub-userscripts/master/github-sort-content.user.js
// @downloadURL  https://raw.githubusercontent.com/Mottie/GitHub-userscripts/master/github-sort-content.user.js
// @supportURL   https://github.com/Mottie/GitHub-userscripts/issues
// ==/UserScript==

(() => {
	"use strict";
	const sorts = ["asc", "desc"];
	const icons = {
		unsorted: color => `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="${color}">
			<path d="M15 8H1l7-8zm0 1H1l7 7z" opacity=".2"/>
		</svg>`,
		ascending: color => `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="${color}">
			<path d="M15 8H1l7-8z"/>
			<path d="M15 9H1l7 7z" opacity=".2"/>
		</svg>`,
		descending: color => `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="${color}">
			<path d="M15 8H1l7-8z" opacity=".2"/>
			<path d="M15 9H1l7 7z"/>
		</svg>`
	};
	const sortables = {
		"repo-files": {
			check: el => el.tagName === "TH" && el.closest(".Box-sc-g0xbh4-0"),
			sort: el => initSortFiles(el),
			css: {
				unsorted: [
					".Box-sc-g0xbh4-0 th"
				],
				tweaks: [
					`body .Box-sc-g0xbh4-0 th {
						text-align: left;
						background-position: 3px center !important;
						cursor: pointer;
						padding-left: 22px !important;
					}`
				]
			}
		},
		"repo-overview": {
			check: el => el.tagName === "TH" && el.closest("table") && document.querySelector('.react-directory-row'),
			sort: el => initSortOverview(el),
			css: {
				unsorted: [
					"table th"
				],
				tweaks: [
					`body table th {
						text-align: left;
						background-position: 3px center !important;
						cursor: pointer;
						padding-left: 22px !important;
					}`
				]
			}
		}
	};
	function getIcon(type, color) {
		return "data:image/svg+xml;charset=UTF-8," +
			encodeURIComponent(icons[type](color));
	}
	function needDarkTheme() {
		let color = window.getComputedStyle(document.body).backgroundColor;
		const rgb = (color || "")
			.replace(/\s/g, "")
			.match(/^rgba?\((\d+),(\d+),(\d+)/i);
		if (rgb) {
			const colors = rgb.slice(1).map(Number);
			const brightest = Math.max(...colors);
			return brightest < 128;
		}
		return false;
	}
	function getDirection(el) {
		return (el.getAttribute("aria-sort") || "").includes(sorts[0])
			? sorts[1]
			: sorts[0];
	}
	function setDirection(els, currentElm, dir) {
		els.forEach(elm => {
			const cellDir = currentElm === elm ? `${dir}ending` : "none";
			elm.setAttribute("aria-sort", cellDir);
		});
	}
	function initSortFiles(el) {
		removeSelection();
		const dir = getDirection(el);
		const table = el.closest("table");
		let options = {
			order: dir,
			natural: true,
			selector: `td:nth-child(${el.cellIndex + 1})`
		};
		if (el.querySelector('[title="Last commit date"]')) {
			options = {
				order: dir,
				natural: true,
				selector: ".react-directory-commit-age relative-time, .react-directory-commit-age .ghst-time",
				attr: "datetime"
			};
		}
		else if (el.querySelector('[class*="text-bold"]')) {
			options.selector = ".react-directory-filename-cell a";
		}
		tinysort($$("tbody tr.react-directory-row", table), options);
		setDirection($$("th", table), el, dir);
	}
	function initSortOverview(el) {
		removeSelection();
		const dir = getDirection(el);
		const table = el.closest("table");
		const colIndex = el.cellIndex;
		let options = {
			order: dir,
			natural: true,
			selector: `td:nth-child(${colIndex + 1})`
		};
		if (el.textContent.includes("Last commit date")) {
			options = {
				order: dir,
				natural: true,
				selector: ".react-directory-commit-age relative-time, .react-directory-commit-age .ghst-time",
				attr: "datetime"
			};
		}
		else if (el.textContent.includes("Name")) {
			options.selector = ".react-directory-filename-cell a";
		}
		tinysort($$("tbody tr.react-directory-row", table), options);
		setDirection($$("th", table), el, dir);
	}
	function removeSelection() {
		const sel = window.getSelection ?
			window.getSelection() :
			document.selection;
		if (sel) {
			if (sel.removeAllRanges) {
				sel.removeAllRanges();
			} else if (sel.empty) {
				sel.empty();
			}
		}
	}
	function $(str, el) {
		return (el || document).querySelector(str);
	}
	function $$(str, el) {
		return [...(el || document).querySelectorAll(str)];
	}
	function init() {
		const color = needDarkTheme() ? "#ddd" : "#222";
		const allUnsorted = [...sortables["repo-files"].css.unsorted, ...sortables["repo-overview"].css.unsorted];
		const allTweaks = [...sortables["repo-files"].css.tweaks, ...sortables["repo-overview"].css.tweaks];
		GM.addStyle(`
			table thead th {
				min-width: 120px !important;
				padding: 8px !important;
			}
			table thead th .text-bold {
				display: inline !important;
				position: static !important;
				width: initial !important;
				height: initial !important;
				clip: initial !important;
				visibility: visible !important;
				font-size: 12px !important;
				line-height: 10px !important;
			}
			table thead th[colspan="2"] {
				min-width: 200px !important;
			}
			${allUnsorted.join(", ")} {
				cursor: pointer;
				padding-left: 22px !important;
				background-image: url(${getIcon("unsorted", color)}) !important;
				background-repeat: no-repeat !important;
				background-position: left center !important;
			}
			${allUnsorted.map(sel =>
				`${sel}[aria-sort="ascending"] {
					background-image: url(${getIcon("ascending", color)}) !important;
					background-repeat: no-repeat !important;
				}`
			).join("\n")}
			${allUnsorted.map(sel =>
				`${sel}[aria-sort="descending"] {
					background-image: url(${getIcon("descending", color)}) !important;
					background-repeat: no-repeat !important;
				}`
			).join("\n")}
			${allTweaks.join("\n")}`
		);
		document.body.addEventListener("click", event => {
			const target = event.target;
			if (target && target.nodeType === 1) {
				Object.keys(sortables).some(item => {
					const el = sortables[item].check(target, window.location);
					if (el) {
						sortables[item].sort(target);
						event.preventDefault();
						return true;
					}
					return false;
				});
			}
		});
	}
	init();
})();

Github Static Time

Originally written by Rob Garrison here, then modified by Gemini as follows to be compatible with Github Sort Content.

github-static-time.user.js
// ==UserScript==
// @name         GitHub Static Time
// @version      1.1.1
// @description  A userscript that replaces relative times with a static time formatted as you like it
// @license      MIT
// @author       Rob Garrison (modified by Gemini)
// @namespace    https://github.com/Mottie
// @match        https://github.com/*
// @run-at       document-idle
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment-with-locales.min.js
// @require      https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=1108163
// @require      https://greasyfork.org/scripts/398877-utils-js/code/utilsjs.js?version=1079637
// @require      https://raw.githubusercontent.com/bradwoo8621/moment-taiwan/master/target/moment-taiwan.js
// @icon         https://github.githubassets.com/pinned-octocat.svg
// @supportURL   https://github.com/Mottie/GitHub-userscripts/issues
// @downloadURL  https://update.greasyfork.org/scripts/29239/GitHub%20Static%20Time.user.js
// @updateURL    https://update.greasyfork.org/scripts/29239/GitHub%20Static%20Time.meta.js
// ==/UserScript==

(() => {
	"use strict";
	let busy = false;
	let timeFormat = GM_getValue("ghst-format", "LLL");
	let locale = GM_getValue("ghst-locale", "en");
	let useUTC = GM_getValue("ghst-utc", "false");
	const locales = [
		{ "abbr": "af", "name": "Afrikaans" },
		{ "abbr": "sq", "name": "Albanian" },
		{ "abbr": "ar", "name": "Arabic" },
		{ "abbr": "ar-dz", "name": "Arabic (Algeria)" },
		{ "abbr": "ar-kw", "name": "Arabic (Kuwait)" },
		{ "abbr": "ar-ly", "name": "Arabic (Libya)" },
		{ "abbr": "ar-ma", "name": "Arabic (Morocco)" },
		{ "abbr": "ar-sa", "name": "Arabic (Saudi Arabia)" },
		{ "abbr": "ar-tn", "name": "Arabic (Tunisia)" },
		{ "abbr": "hy-am", "name": "Armenian" },
		{ "abbr": "az", "name": "Azerbaijani" },
		{ "abbr": "bm", "name": "Bambara" },
		{ "abbr": "eu", "name": "Basque" },
		{ "abbr": "be", "name": "Belarusian" },
		{ "abbr": "bn", "name": "Bengali" },
		{ "abbr": "bn-bd", "name": "Bengali (Bangladesh)" },
		{ "abbr": "bs", "name": "Bosnian" },
		{ "abbr": "br", "name": "Breton" },
		{ "abbr": "bg", "name": "Bulgarian" },
		{ "abbr": "my", "name": "Burmese" },
		{ "abbr": "km", "name": "Cambodian" },
		{ "abbr": "ca", "name": "Catalan" },
		{ "abbr": "tzm", "name": "Central Atlas Tamazight" },
		{ "abbr": "tzm-latn", "name": "Central Atlas Tamazight Latin" },
		{ "abbr": "zh-cn", "name": "Chinese (China)" },
		{ "abbr": "zh-hk", "name": "Chinese (Hong Kong)" },
		{ "abbr": "zh-mo", "name": "Chinese (Macau)" },
		{ "abbr": "zh-tw", "name": "Chinese (Taiwan)" },
		{ "abbr": "cv", "name": "Chuvash" },
		{ "abbr": "hr", "name": "Croatian" },
		{ "abbr": "cs", "name": "Czech" },
		{ "abbr": "da", "name": "Danish" },
		{ "abbr": "nl", "name": "Dutch" },
		{ "abbr": "nl-be", "name": "Dutch (Belgium)" },
		{ "abbr": "en-au", "name": "English (Australia)" },
		{ "abbr": "en-ca", "name": "English (Canada)" },
		{ "abbr": "en-in", "name": "English (India)" },
		{ "abbr": "en-ie", "name": "English (Ireland)" },
		{ "abbr": "en-il", "name": "English (Israel)" },
		{ "abbr": "en-nz", "name": "English (New Zealand)" },
		{ "abbr": "en-sg", "name": "English (Singapore)" },
		{ "abbr": "en-gb", "name": "English (United Kingdom)" },
		{ "abbr": "en", "name": "English (United States)" },
		{ "abbr": "eo", "name": "Esperanto" },
		{ "abbr": "et", "name": "Estonian" },
		{ "abbr": "fo", "name": "Faroese" },
		{ "abbr": "fil", "name": "Filipino" },
		{ "abbr": "fi", "name": "Finnish" },
		{ "abbr": "fr", "name": "French" },
		{ "abbr": "fr-ca", "name": "French (Canada)" },
		{ "abbr": "fr-ch", "name": "French (Switzerland)" },
		{ "abbr": "fy", "name": "Frisian" },
		{ "abbr": "gl", "name": "Galician" },
		{ "abbr": "ka", "name": "Georgian" },
		{ "abbr": "de", "name": "German" },
		{ "abbr": "de-at", "name": "German (Austria)" },
		{ "abbr": "de-ch", "name": "German (Switzerland)" },
		{ "abbr": "el", "name": "Greek" },
		{ "abbr": "gu", "name": "Gujarati" },
		{ "abbr": "he", "name": "Hebrew" },
		{ "abbr": "hi", "name": "Hindi" },
		{ "abbr": "hu", "name": "Hungarian" },
		{ "abbr": "is", "name": "Icelandic" },
		{ "abbr": "id", "name": "Indonesian" },
		{ "abbr": "ga", "name": "Irish or Irish Gaelic" },
		{ "abbr": "it", "name": "Italian" },
		{ "abbr": "it-ch", "name": "Italian (Switzerland)" },
		{ "abbr": "ja", "name": "Japanese" },
		{ "abbr": "jv", "name": "Javanese" },
		{ "abbr": "kn", "name": "Kannada" },
		{ "abbr": "kk", "name": "Kazakh" },
		{ "abbr": "tlh", "name": "Klingon" },
		{ "abbr": "gom-deva", "name": "Konkani Devanagari script" },
		{ "abbr": "gom-latn", "name": "Konkani Latin script" },
		{ "abbr": "ko", "name": "Korean" },
		{ "abbr": "ku", "name": "Kurdish" },
		{ "abbr": "ky", "name": "Kyrgyz" },
		{ "abbr": "lo", "name": "Lao" },
		{ "abbr": "lv", "name": "Latvian" },
		{ "abbr": "lt", "name": "Lithuanian" },
		{ "abbr": "lb", "name": "Luxembourgish" },
		{ "abbr": "mk", "name": "Macedonian" },
		{ "abbr": "ms-my", "name": "Malay" },
		{ "abbr": "ms", "name": "Malay" },
		{ "abbr": "ml", "name": "Malayalam" },
		{ "abbr": "dv", "name": "Maldivian" },
		{ "abbr": "mt", "name": "Maltese (Malta)" },
		{ "abbr": "mi", "name": "Maori" },
		{ "abbr": "mr", "name": "Marathi" },
		{ "abbr": "mn", "name": "Mongolian" },
		{ "abbr": "me", "name": "Montenegrin" },
		{ "abbr": "ne", "name": "Nepalese" },
		{ "abbr": "se", "name": "Northern Sami" },
		{ "abbr": "nb", "name": "Norwegian Bokmål" },
		{ "abbr": "nn", "name": "Nynorsk" },
		{ "abbr": "oc-lnc", "name": "Occitan, lengadocian dialecte" },
		{ "abbr": "fa", "name": "Persian" },
		{ "abbr": "pl", "name": "Polish" },
		{ "abbr": "pt", "name": "Portuguese" },
		{ "abbr": "pt-br", "name": "Portuguese (Brazil)" },
		{ "abbr": "x-pseudo", "name": "Pseudo" },
		{ "abbr": "pa-in", "name": "Punjabi (India)" },
		{ "abbr": "ro", "name": "Romanian" },
		{ "abbr": "ru", "name": "Russian" },
		{ "abbr": "gd", "name": "Scottish Gaelic" },
		{ "abbr": "sr", "name": "Serbian" },
		{ "abbr": "sr-cyrl", "name": "Serbian Cyrillic" },
		{ "abbr": "sd", "name": "Sindhi" },
		{ "abbr": "si", "name": "Sinhalese" },
		{ "abbr": "sk", "name": "Slovak" },
		{ "abbr": "sl", "name": "Slovenian" },
		{ "abbr": "es", "name": "Spanish" },
		{ "abbr": "es-do", "name": "Spanish (Dominican Republic)" },
		{ "abbr": "es-mx", "name": "Spanish (Mexico)" },
		{ "abbr": "es-us", "name": "Spanish (United States)" },
		{ "abbr": "sw", "name": "Swahili" },
		{ "abbr": "sv", "name": "Swedish" },
		{ "abbr": "tl-ph", "name": "Tagalog (Philippines)" },
		{ "abbr": "tg", "name": "Tajik" },
		{ "abbr": "tzl", "name": "Talossan" },
		{ "abbr": "ta", "name": "Tamil" },
		{ "abbr": "te", "name": "Telugu" },
		{ "abbr": "tet", "name": "Tetun Dili (East Timor)" },
		{ "abbr": "th", "name": "Thai" },
		{ "abbr": "bo", "name": "Tibetan" },
		{ "abbr": "tr", "name": "Turkish" },
		{ "abbr": "tk", "name": "Turkmen" },
		{ "abbr": "uk", "name": "Ukrainian" },
		{ "abbr": "ur", "name": "Urdu" },
		{ "abbr": "ug-cn", "name": "Uyghur (China)" },
		{ "abbr": "uz", "name": "Uzbek" },
		{ "abbr": "uz-latn", "name": "Uzbek Latin" },
		{ "abbr": "vi", "name": "Vietnamese" },
		{ "abbr": "cy", "name": "Welsh" },
		{ "abbr": "yo", "name": "Yoruba Nigeria" },
		{ "abbr": "ss", "name": "siSwati" }
	];
	const block = document.createElement("span");
	block.className = "ghst-time time";
	function staticTime(tempFormat) {
		if (busy) {
			return;
		}
		busy = true;
		let selector = typeof tempFormat === "string"
			? ".ghst-time"
			: "relative-time, time-ago";
		if ($(selector)) {
			let indx = 0;
			const els = $$(selector);
			const len = els.length;
			const loop = () => {
				let el, time, node, formatted,
					max = 0;
				while (max < 20 && indx < len) {
					if (indx >= len) {
						return;
					}
					el = els[indx];
					time = moment(el.getAttribute("datetime") || "");
					if (el && time.isValid()) {
						if (useUTC === "true") {
							time = time.utc();
						}
						if (tempFormat) {
							formatted = time.format(tempFormat);
							el.textContent = formatted;
							el.title = formatted;
						} else {
							formatted = time.format(timeFormat);
							node = block.cloneNode(true);
							node.setAttribute("datetime", el.getAttribute("datetime"));
							node.textContent = formatted;
							node.title = formatted;
							if (el.parentElement) {
								el.parentElement.replaceChild(node, el);
							}
						}
						max++;
					}
					indx++;
				}
				if (indx < len) {
					requestAnimationFrame(loop);
				}
			};
			loop();
		}
		busy = false;
	}
	function addPanel() {
		const div = document.createElement("div");
		GM_addStyle(`
			#ghst-settings { opacity:0; visibility:hidden; }
			#ghst-settings.ghst-open { position:fixed; z-index:65535; top:0; bottom:0;
				left:0; right:0; opacity:1; visibility:visible;
				background:rgba(0, 0, 0, .5); }
			#ghst-settings-inner { position:fixed; left:50%; top:50%; width:25rem;
				transform:translate(-50%,-50%); box-shadow:0 .5rem 1rem #111;
				color:#c0c0c0 }
			#ghst-settings-inner .boxed-group-inner { height: 255px; }
			#ghst-footer { clear:both; border-top:1px solid rgba(68, 68, 68, .3);
				padding-top:5px; }
		`);
		div.id = "ghst-settings";
		let options = "";
		locales.forEach(loc => {
			let sel = loc.abbr === locale ? " selected" : "";
			options += `<option value="${loc.abbr}"${sel}>${loc.name}</option>`;
		});
		div.innerHTML = `
			<div id="ghst-settings-inner" class="boxed-group">
				<h3>GitHub Static Time Settings</h3>
				<div class="boxed-group-inner">
					<dl class="form-group flattened">
						<dt>
							<label for="ghst-locale">Select a locale</label>
						</dt>
						<dd>
							<select id="ghst-locale" class="form-select float-right" value="${locale}">
								${options}
							</select>
							<br>
						</dd>
					</dl>
					<dl class="form-group flattened">
						<dt>
							<label for="ghst-utc">Show UTC time (use "z" in format below)</label>
						</dt>
						<dd>
							<div class="form-checkbox">
								<input id="ghst-utc" type="checkbox" class="float-right">
							</div>
							<br>
						</dd>
					</dl>
					<dl class="form-group flattened">
						<dt>
							<label for="ghst-format">
								Set <a href="https://momentjs.com/docs/#/displaying/format/" target="_blank">
									MomentJS
								</a> format (e.g. "MMMM Do YYYY, h:mm A"):
							</label>
						</dt>
						<dd>
							<input id="ghst-format" type="text" class="form-control" value="${timeFormat}"/>
						</dd>
					</dl>
					<div id="ghst-footer">
						<button type="button" id="ghst-cancel" class="btn btn-sm float-right">Cancel</button>
						<button type="button" id="ghst-save" class="btn btn-sm float-right">Save</button>
					</div>
				</div>
			</div>`;
		$("body").appendChild(div);
		$("#ghst-utc").checked = useUTC === "true";
		on($("#ghst-settings"), "click", closePanel);
		on($("body"), "keyup", event => {
			if (
				event.key === "Escape" &&
				$("#ghst-settings").classList.contains("ghst-open")
			) {
				closePanel(event);
				return false;
			} else if (event.key === "Enter" && event.shiftKey) {
				closePanel();
				update("save");
			}
		});
		on($("#ghst-settings-inner"), "click", event => {
			event.stopPropagation();
		});
		on($("#ghst-save"), "click", () => {
			closePanel();
			update("save");
		});
		on($("#ghst-locale"), "change", update);
		on($("#ghst-utc"), "change", update);
		on($("#ghst-format"), "change", update);
		on($("#ghst-cancel"), "click", closePanel);
	}
	function closePanel(event) {
		$("#ghst-settings").classList.remove("ghst-open");
		if (event) {
			return update("revert");
		}
	}
	function update(mode) {
		if (mode === "revert") {
			$("#ghst-locale").value = locale;
			$("#ghst-format").value = timeFormat;
			$("#ghst-utc").checked = useUTC === "true";
		}
		let loc = $("#ghst-locale").value || "en";
		let time = $("#ghst-format").value || "LLL";
		let utc = $("#ghst-utc").checked ? "true" : "false";
		if (mode === "save") {
			timeFormat = time;
			locale = loc;
			useUTC = utc;
			GM_setValue("ghst-format", timeFormat);
			GM_setValue("ghst-locale", locale);
			GM_setValue("ghst-utc", useUTC);
		}
		moment.locale(loc);
		staticTime(time);
		return false;
	}
	function init() {
		addPanel();
		moment.locale(locale);
		staticTime();
	}
	GM_registerMenuCommand("Set GitHub static time format", () => {
		$("#ghst-settings").classList.add("ghst-open");
	});
	document.addEventListener("ghmo:container", () => {
		setTimeout(() => {
			staticTime();
		}, 100);
	});
	document.addEventListener("ghmo:preview", staticTime);
	init();
})();