您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A userscript that makes some lists & markdown tables sortable
当前为
// ==UserScript== // @name GitHub Sort Content // @version 1.1.3 // @description A userscript that makes some lists & markdown tables sortable // @license https://creativecommons.org/licenses/by-sa/4.0/ // @namespace https://github.com/Mottie // @include https://github.com/* // @grant GM_addStyle // @require https://cdnjs.cloudflare.com/ajax/libs/tinysort/2.3.6/tinysort.min.js // @run-at document-idle // @author Rob Garrison // ==/UserScript== /* global GM_addStyle, tinysort */ /* jshint unused:true, esnext:true */ (() => { "use strict"; /* example pages: tables - https://github.com/Mottie/GitHub-userscripts Contribute repos & Your Repos - https://github.com/ organization repos - https://github.com/jquery organization members - https://github.com/orgs/jquery/people pinned & no pinned repos - https://github.com/addyosmani repos - https://github.com/addyosmani?tab=repositories stars - https://github.com/stars watching - https://github.com/watching */ const sorts = ["asc", "desc"], icons = { white: { unsorted: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTE1IDhIMWw3LTh6bTAgMUgxbDcgN3oiIGZpbGw9IiNkZGQiIG9wYWNpdHk9Ii4yIi8+PC9zdmc+", asc: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTE1IDhIMWw3LTh6IiBmaWxsPSIjZGRkIi8+PHBhdGggZD0iTTE1IDlIMWw3IDd6IiBmaWxsPSIjZGRkIiBvcGFjaXR5PSIuMiIvPjwvc3ZnPg==", desc: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTE1IDhIMWw3LTh6IiBmaWxsPSIjZGRkIiBvcGFjaXR5PSIuMiIvPjxwYXRoIGQ9Ik0xNSA5SDFsNyA3eiIgZmlsbD0iI2RkZCIvPjwvc3ZnPg==" }, black: { unsorted: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTE1IDhIMWw3LTh6bTAgMUgxbDcgN3oiIGZpbGw9IiMyMjIiIG9wYWNpdHk9Ii4yIi8+PC9zdmc+", asc: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTE1IDhIMWw3LTh6IiBmaWxsPSIjMjIyIi8+PHBhdGggZD0iTTE1IDlIMWw3IDd6IiBmaWxsPSIjMjIyIiBvcGFjaXR5PSIuMiIvPjwvc3ZnPg==", desc: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTE1IDhIMWw3LTh6IiBmaWxsPSIjMjIyIiBvcGFjaXR5PSIuMiIvPjxwYXRoIGQ9Ik0xNSA5SDFsNyA3eiIgZmlsbD0iIzIyMiIvPjwvc3ZnPg==" } }, // toolbars - target for sort arrows regexBars = new RegExp( "\\b(" + [ "TableObject", // org repos "org-toolbar", // org people "sort-bar", // https://github.com/stars "tabnav-tabs", // https://github.com/:user/follower(s|ing) "Box-header|flex-auto", // watching "user-profile-nav" // user repos ].join("|") + ")\\b" ); function initSortTable(el) { removeSelection(); const dir = el.classList.contains(sorts[0]) ? sorts[1] : sorts[0], table = closest("table", el); tinysort($$("tbody tr", table), { order: dir, natural: true, selector: `td:nth-child(${el.cellIndex + 1})` }); $$("th", table).forEach(elm => { elm.classList.remove(...sorts); }); el.classList.add(dir); } function initSortUl(arrows, list, selector) { if (list && list.children) { removeSelection(); const dir = arrows.classList.contains(sorts[0]) ? sorts[1] : sorts[0], options = { order: dir, natural: true }; if (selector) { options.selector = selector; } // using children because the big repo contains UL > DIV tinysort(list.children, options); arrows.classList.remove(...sorts); arrows.classList.add(dir); } } function needDarkTheme() { let brightest = 0, // color will be "rgb(#, #, #)" or "rgba(#, #, #, #)" color = window.getComputedStyle(document.body).backgroundColor; const rgb = (color || "") .replace(/\s/g, "") .match(/^rgba?\((\d+),(\d+),(\d+)/i); if (rgb) { color = rgb.slice(1); // remove "rgb.." part from match color.forEach(c => { // http://stackoverflow.com/a/15794784/145346 brightest = Math.max(brightest, parseInt(c, 10)); }); // return true if we have a dark background return brightest < 128; } // fallback to bright background return false; } function $(str, el) { return (el || document).querySelector(str); } function $$(str, el) { return Array.from((el || document).querySelectorAll(str)); } function closest(selector, el) { while (el && el.nodeType === 1) { if (el.matches(selector)) { return el; } el = el.parentNode; } return null; } function removeSelection() { // remove text selection - http://stackoverflow.com/a/3171348/145346 const sel = window.getSelection ? window.getSelection() : document.selection; if (sel) { if (sel.removeAllRanges) { sel.removeAllRanges(); } else if (sel.empty) { sel.empty(); } } } function init() { const styles = needDarkTheme() ? icons.white : icons.black; GM_addStyle(` /* unsorted icon */ .markdown-body table thead th { cursor:pointer; padding-right:22px !important; background-image:url(${styles.unsorted}) !important; background-repeat:no-repeat !important; background-position:calc(100% - 5px) center !important; } div.js-pinned-repos-reorder-container > h3, div.filter-repos, .dashboard-sidebar .boxed-group > h3, .sort-bar, h2 + .tabnav > .tabnav-tabs, .org-toolbar, .org-profile .TableObject-item--primary, .subscriptions-content .Box-header, div.user-profile-nav.js-sticky { cursor:pointer; padding-right:10px; background-image:url(${styles.unsorted}) !important; background-repeat:no-repeat !important; background-position:calc(100% - 5px) center !important; } /* https://github.com/ -> your repositories */ .dashboard-sidebar .user-repos h3 { background-position: 175px 10px !important; } /* https://github.com/:user?tab=repositories */ div.user-profile-nav.js-sticky { background-position:calc(100% - 80px) 22px !important; } /* https://github.com/:organization repos & people */ .org-profile .TableObject-item--primary, .org-toolbar { background-position:calc(100% - 5px) 10px !important; } .TableObject-item--primary input { width: 97.5% !important; } /* https://github.com/stars */ .sort-bar { background-position:525px 10px !important; } /* https://github.com/watching */ .subscriptions-content .Box-header { background-position:160px 15px !important; } /* asc/dec icons */ table thead th.asc, div.boxed-group h3.asc, div.user-profile-nav.asc, div.js-repo-filter.asc, .org-toolbar.asc, .TableObject-item--primary.asc, .sort-bar.asc, h2 + .tabnav > .tabnav-tabs.asc, .subscriptions-content .Box-header.asc { background-image:url(${styles.asc}) !important; background-repeat:no-repeat !important; } table thead th.desc, div.boxed-group h3.desc, div.user-profile-nav.desc, div.js-repo-filter.desc, .org-toolbar.desc, .TableObject-item--primary.desc, .sort-bar.desc, h2 + .tabnav > .tabnav-tabs.desc, .subscriptions-content .Box-header.desc { background-image:url(${styles.desc}) !important; background-repeat:no-repeat !important; } /* remove sort arrows */ .popular-repos + div.boxed-group h3 { background-image:none !important; cursor:default; } /* move "Customize your pinned..." - https://github.com/:self */ .pinned-repos-setting-link { margin-right:14px; } `); document.body.addEventListener("click", event => { let el; const target = event.target, name = target.nodeName; if (target && target.nodeType === 1 && ( // nodes th|h3 & form for stars page name === "H3" || name === "TH" || name === "FORM" || // https://github.com/:organization filter bar // filter: .TableObject-item--primary, repo wrapper: .org-profile // https://github.com/stars (sort-bar) // https://github.com/:user/followers (tabnav-tabs) // https://github.com/:user/following (tabnav-tabs) // https://github.com/:user?tab=repositories (user-profile-nav) // https://github.com/:user?tab=stars (user-profile-nav) // https://github.com/:user?tab=followers (user-profile-nav) // https://github.com/:user?tab=followering (user-profile-nav) regexBars.test(target.className) )) { // don't sort tables not inside of markdown if (name === "TH" && closest(".markdown-body", target)) { return initSortTable(target); } // following el = $("ol.follow-list", closest(".container", target)); if (el) { return initSortUl(target, el, ".follow-list-name a"); } // organization people - https://github.com/orgs/:organization/people el = $("ul.member-listing-next", target.parentNode); if (el) { return initSortUl(target, el, ".member-info a"); } // stars - https://github.com/stars el = closest(".sort-bar", target); if (el && $(".repo-list", el.parentNode)) { return initSortUl(el, $(".repo-list", el.parentNode), "h3 a"); } // org repos - https://github.com/:organization el = closest(".org-profile", target); if (el && $(".repo-list", el)) { return initSortUl(target, $(".repo-list", el), "h3 a"); } // https://github.com/watching el = closest(".subscriptions-content", target); if (el && $(".repo-list", el)) { return initSortUl($(".Box-header", el), $(".repo-list", el), "li a"); } // mini-repo listings with & without filter - https://github.com/ // and pinned repo lists el = closest(".boxed-group", target); // prevent clicking on the H3 header of filtered repos if (el && name === "H3" && ( el.classList.contains("js-repo-filter") || el.classList.contains("js-pinned-repos-reorder-container") )) { return initSortUl(target, $(".mini-repo-list", el)); } // user sticky navigation if (target.classList.contains("user-profile-nav")) { el = $(".underline-nav-item.selected", target); if (el) { if (el.textContent.indexOf("Overview") > -1) { return initSortUl(target, $(".pinned-repos-list"), ".repo"); } else if (el.href.indexOf("tab=repo") > -1) { return initSortUl(target, $(".js-repo-list"), "h3 a"); } else if (el.href.indexOf("tab=stars") > -1) { return initSortUl(target, $(".js-repo-filter"), "h3 a"); } else if (el.href.indexOf("tab=follow") > -1) { return initSortUl(target, $(".js-repo-filter"), "a .f4"); } } } } }); } init(); })();