您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Colorize bug list based on status
当前为
// ==UserScript== // @name crbug colorize // @description Colorize bug list based on status // @match https://bugs.chromium.org/* // @version 1.0.4 // @author wOxxOm // @namespace wOxxOm.scripts // @license MIT License // @run-at document-start // @grant none // ==/UserScript== const prefix = 'wOxxOm-' const sheet = new CSSStyleSheet(); sheet.replaceSync(` .${prefix}Starred { font-weight: bold } .${prefix}Archived { color: gray } .${prefix}Assigned { color: #3f71b1 } .${prefix}Available { color: #92479a } .${prefix}Duplicate, .${prefix}Invalid { opacity: 0.3 } .${prefix}ExternalDependency { color: #ababab } .${prefix}Fixed { color: #227700 } .${prefix}Started, .${prefix}FixPending { color: #06908b } .${prefix}Unconfirmed, .${prefix}New { color: black } .${prefix}Untriaged { color: #947911 } .${prefix}Verified, .${prefix}Accepted { color: #6a846f } .${prefix}WontFix { color: #d00 } tr[class*="${prefix}"] td[width="100%"] a { color: inherit; text-decoration: underline; } `); (async () => { const app = await added('mr-app'); const main = await added('main', app); while (true) await colorize(main); })(); async function colorize(main) { const page = await added('mr-list-page', main); const list = await shadowOf(await added('mr-issue-list', page)); list.adoptedStyleSheets = [...new Set([...list.adoptedStyleSheets, sheet])]; await added('td', list.host); const tbody = list.querySelector('tbody'); while (true) { for (const el of tbody.getElementsByTagName('td')) { const text = el.textContent.trim(); switch (text) { case '': continue; case 'Accepted': case 'Archived': case 'Assigned': case 'Available': case 'Duplicate': case 'ExternalDependency': case 'FixPending': case 'Fixed': case 'Invalid': case 'New': case 'Started': case 'Unconfirmed': case 'Untriaged': case 'Verified': case 'WontFix': setClass(el, text); continue; case '★': setClass(el, 'Starred'); continue; } if (el.align === 'right' && (text === '1' || text === '0')) { el.textContent = ''; } if (/% regression in|\b\d(\.\d)?%(-\d(\.\d)?%)? improvement in|test.*?is flaky|^(Android|Chrome)$/.test(text) && el.parentNode) { el.parentNode.remove(); } } const winner = await Promise.race([ removed(page), added('td', list.host, true), ]); if (!winner) return; } } function setClass(el, type) { const {className} = el.parentNode; const token = prefix + type; const allTokens = className .trim() .split(/\s+/) .filter(t => !t.startsWith(prefix) || t === token); const s = allTokens.join(' ') + (allTokens.includes(token) ? '' : ' ' + token); if (s !== className) el.parentNode.className = s; } async function added(tag, parent = document.documentElement, forceObserver) { const target = parent.shadowRoot || !parent.localName.includes('-') && parent || await shadowOf(parent); return !forceObserver && target.querySelector(tag) || new Promise(resolve => { const mo = new MutationObserver(mutations => { const el = forceObserver ? mutations.some(mutantAdded, {tag}) : target.querySelector(tag); if (el) { mo.disconnect(); resolve(el); } }); mo.observe(target, {childList: true, subtree: true}); }); } function removed(el) { const root = el.getRootNode(); return root.contains(el) && new Promise(resolve => { const mo = new MutationObserver(() => { if (!root.contains(el)) { mo.disconnect(); resolve(); } }); mo.observe(root, {childList: true, subtree: true}); }); } function shadowOf(el) { return el.shadowRoot || new Promise(resolve => { el.attachShadow = function (...args) { delete el.attachShadow; const root = el.attachShadow(...args); resolve(root); return root; }; }); } function mutantAdded({addedNodes, target}) { const {tag} = this; if (target.localName === tag) return true; for (const n of addedNodes) if (n.localName === tag || n.firstElementChild && n.getElementsByTagName(tag)[0]) return true; }