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()
})()