-
-
Save autoxbc/6d80da78a9e976f91e22554b464305f8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name V2EX with Filter | |
// @author autoxbc | |
// @version 1.0 | |
// @match *://*.v2ex.com/* | |
// @grant GM_addStyle | |
// ==/UserScript== | |
'use strict'; | |
( () => { | |
const buttons = document.querySelector('.topic_buttons'); | |
if(!buttons){ | |
return; | |
} | |
const style = ` | |
.ago + .small.fade { | |
color:#ED090D !important; | |
} | |
`; | |
GM_addStyle(style); | |
// 删除多余空格 | |
[...buttons.childNodes].forEach( e => { | |
if( e.nodeType === 3 ){ | |
e.nodeValue = e.nodeValue.trim(); | |
} | |
} ); | |
// 添加 优评排序 & 内容过滤框 | |
const [ , good , filter , input ] = [ | |
,'<a>优评</a>' | |
,'<a>过滤</a>' | |
,'<input type="text" hidden="hidden" />' | |
].map( e => html2node(e) ); | |
[ good , filter ].forEach( e => { | |
e.href = '#;'; | |
e.className = 'tb'; | |
} ); | |
const cells = document.querySelectorAll('.box > .cell[id^="r_"]'); | |
const box = cells[0].parentNode ; | |
const info = box.querySelector('.cell:not([id])'); | |
good.reset = () => [ ...cells , box , info , good ].forEach( e => e.removeAttribute('style') ); | |
good.onclick = () => { | |
filter.reset(); | |
if( box.hasAttribute('style') ) | |
{ | |
good.reset(); | |
} else { | |
const maxOrder = [...cells].reduce( (pre,cell) => { | |
const order = [ ...cell.querySelectorAll('span.fade') ] | |
.reduce( (pre,cur) => { | |
const order = /\d+/.exec(cur.textContent); | |
return Math.max( pre , order ); | |
},0); | |
cell.style = order ? `order:${ order };` : 'display:none;'; | |
return Math.max( pre , order ); | |
},0); | |
box.style = ` | |
display:flex; | |
flex-direction:column-reverse; | |
`; | |
info.style = `order:${ maxOrder+1 };`; | |
good.style = 'font-weight:700;'; | |
} | |
return false ; | |
}; | |
filter.title = ` | |
普通字符串:abc | |
正则字面量:/abc/i | |
排除符号:@@abc , @@/abc/i | |
注意:每次过滤在上一次结果上叠加 | |
如想进行全新过滤,双击输入框重置 | |
`.replace( /\t/g ,'').trim(); | |
filter.reset = () => { | |
input.setAttribute('hidden','hidden'); | |
input.ondblclick(); | |
}; | |
filter.onclick = () => { | |
good.reset(); | |
if( input.hasAttribute('hidden') ) | |
{ | |
input.removeAttribute('hidden'); | |
input.focus(); | |
} else { | |
filter.reset(); | |
} | |
return false ; | |
}; | |
input.ondblclick = () => { | |
input.value = ''; | |
input.onchange(); | |
}; | |
input.onchange = () => { | |
const { value } = input ; | |
if( value === '' ) | |
{ | |
nodeFilter(); | |
return; | |
} | |
const cvtRegExp = str => { | |
if( /^\/(.+)\/(\w*)$/.test(str) ) | |
{ | |
const { $1 , $2 } = RegExp ; | |
return new RegExp( $1 , $2 ); | |
} else { | |
return str ; | |
} | |
}; | |
if( /^@@/.test(value) ){ | |
nodeFilter( cvtRegExp( value.substr(2) ) , true ); | |
} else { | |
nodeFilter( cvtRegExp(value) ); | |
} | |
}; | |
buttons.append( good , filter , input ); | |
} )(); | |
function html2node(str) | |
{ | |
const div = document.createElement('div'); | |
div.innerHTML = str.trim(); | |
if( isSame( 1 , div.childNodes.length , div.children.length ) ){ | |
return div.childNodes[0]; | |
} else { | |
return div ; | |
} | |
} | |
function isSame(...args) | |
{ | |
const callee = isSame ; | |
const { length } = args ; | |
if( length === 0 ){ | |
return true; | |
} | |
if( length === 1 ){ | |
const ele = args[0]; | |
if( Array.isArray(ele) ){ | |
return callee(...ele); | |
} else { | |
return true ; | |
} | |
} | |
if( length > 1 ){ | |
return new Set(args).size === 1 ; | |
} | |
} | |
function nodeFilter(...args) | |
{ | |
const callee = nodeFilter ; | |
callee.last = callee.last || new Set(); | |
const { last } = callee ; | |
if( args.length === 0 ) | |
{ | |
last.forEach( e => e.hidden = false ); | |
last.clear(); | |
return; | |
} | |
let [ findReg , reverse = false , nodeSelector , fineSelector ] = args ; | |
// 附带规则,用于增强指定网站的过滤能力 | |
[ | |
[ 'v2ex.com' , '.box > .cell[id^="r_"]' ] , | |
].some( ([ host , _nodeSelector , _fineSelector ]) => { | |
if( !nodeSelector && location.href.includes(host) ) | |
{ | |
nodeSelector = _nodeSelector ; | |
fineSelector = _fineSelector ; | |
return true ; | |
} | |
} ); | |
[ ...document.querySelectorAll(nodeSelector) ].forEach( e => { | |
const target = e.querySelector(fineSelector) || e ; | |
if( contains( target.textContent , findReg ) !== reverse ){ | |
return; | |
} | |
e.hidden = true; | |
last.add(e); | |
} ); | |
} | |
function contains( str , arg ){ | |
if( isString(arg) ) | |
return str.includes(arg); | |
if( isRegExp(arg) ) | |
return arg.test(str); | |
return false ; | |
} | |
function isRegExp(reg) | |
{ | |
return Object.prototype.toString.call(reg) === '[object RegExp]'; | |
} | |
function isString(str) | |
{ | |
return !!str && typeof str === 'string' && str.constructor === String ; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment