NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name lihkg-of-trust // @version 0.0.3 // @description LIHKG of Trust. LIHKG User Reputation. // @license MIT // @author blah2017blah // @include http*://lihkg.com/* // @namespace https://github.com/blah2017blah/ // @homepageURL https://github.com/blah2017blah/lihkg-of-trust // @supportURL https://github.com/blah2017blah/lihkg-of-trust/issues // @grant none // ==/UserScript== (function() { 'use strict' /** * 格式: * const userIdMap = { * '用戶名1(不含emoji)': 11111, // 會員編號 11111 * . '用戶名1别名(不含emoji)': 11111, // 會員編號 11111 * * '用戶名2(不含emoji)': 22222, // 會員編號 22222 * } */ const userIdMap = { // '用戶名': 999999, } /** * 格式: * const userList = { * 11111: { // 會員編號 11111 * fiveCents: true, // 三毛/五毛 * troll: true, // 假膠 * }, * 22222: { // 會員編號 22222 * trusted: true, // 優質 * }, * } */ const userList = { // 999999: { // fiveCents: true, // troll: true, // trusted: true, // }, } const fiveCentsIcon = '<span class="ec ec-bug" />' const trollsIcon = '<span class="ec ec-clown-face"/>' const trustedIcon = '<span class="ec ec-reminder-ribbon"/>' const getElementByXpath = (path, contextNode = document) => document.evaluate(path, contextNode, null, XPathResult.ANY_TYPE, null) const initIcon = () => { const head = document.getElementsByTagName('head')[0] const link = document.createElement('link') link.rel = 'stylesheet' link.type = 'text/css' link.href = 'https://unpkg.com/emoji.css/dist/emoji.min.css' link.media = 'all' head.appendChild(link) } const attachObserver = (element, observeHandler) => { const config = { attributes: false, childList: true, subtree: false } const panelObserver = new MutationObserver(observeHandler) panelObserver.observe(element, config) } const attachIcon = (icon, element) => { element.innerHTML = `${element.innerHTML}${icon}` } const updatePanel = nameSpan => { const name = nameSpan.innerText.trim() const userId = userIdMap[name] if (!userId) { return } const user = userList[userId] if (user) { if (user.fiveCents) { attachIcon(fiveCentsIcon, nameSpan) } if (user.troll) { attachIcon(trollsIcon, nameSpan) } if (user.trusted) { attachIcon(trustedIcon, nameSpan) } } } const start = () => { const addIconsObserveHandler = getNameElements => mutationList => { mutationList.forEach(mutation => { if (mutation.type === 'childList' && mutation.addedNodes.length) { const nameElements = getNameElements(mutation.addedNodes[0]) nameElements.forEach(nameElement => updatePanel(nameElement)) } }) } const checkLeftPanelExist = setInterval(() => { if (getElementByXpath('//div[@id="leftPanel"]/div[2]').iterateNext()) { attachObserver( getElementByXpath('//div[@id="leftPanel"]/div[2]').iterateNext(), addIconsObserveHandler(addedNode => { const nameSpan = addedNode.querySelector('small > span:first-child') if (nameSpan) { return [nameSpan] } return [] }) ) clearInterval(checkLeftPanelExist) } }, 100) let checkRightPanelExist = 0 const checkRightPanel = () => { const resetRightPanelCheckObserveHandler = mutationList => { mutationList.forEach(mutation => { if (mutation.type === 'childList' && mutation.removedNodes.length && !checkRightPanelExist) { checkRightPanel() } }) } checkRightPanelExist = setInterval(() => { if (getElementByXpath('//div[@id="rightPanel"]/div[1]').iterateNext()) { attachObserver( getElementByXpath('//div[@id="rightPanel"]/div[1]').iterateNext(), addIconsObserveHandler(addedNode => addedNode.querySelectorAll('a[href^="/profile"]')) ) clearInterval(checkRightPanelExist) checkRightPanelExist = 0 attachObserver(getElementByXpath('//div[@id="rightPanel"]/parent::div').iterateNext(), resetRightPanelCheckObserveHandler) } }, 100) } checkRightPanel() } initIcon() start() })()