IgnoreSomeCompanies

根据需要添加关键字,然后可以把页面上相对应公司的招聘条目给忽略

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         IgnoreSomeCompanies
// @namespace    https://github.com/hfc1994
// @version      1.1.1
// @description  根据需要添加关键字,然后可以把页面上相对应公司的招聘条目给忽略
// @author       枯木
// @license      GPL
// @icon         https://avatars2.githubusercontent.com/u/32028349?s=40&v=4
// @match        https://search.51job.com/list/*
// @match        https://sou.zhaopin.com/*
// @grant        none
// ==/UserScript==

/**
 * 根据添加的指定关键字,忽略求职网站上指定公司的招聘条目
 * 如果发现bug,非常欢迎向我提出来https://github.com/hfc1994/IgnoreSomeCompanies
 */

let companies = []
let website = ''

// 初始化,用来读取localStorage
// 存储格式key:companies,value:['','']
function init() {
    judgeWebsite()
    appendGlobalStyle()
    appendFloatDiv()
    try {
        companies = JSON.parse(window.localStorage.getItem('companies'))
        if (companies === null || companies === undefined || companies.length === 0) {
            companies = []
            console.warn('页面暂无需要过滤的数据')
            return
        } else {
            for (let i=0; i<companies.length; i++) {
                document.getElementById('ISC_content').appendChild(buildContentChildNode(companies[i], i))
            }
            doIgnore()
        }
    } catch(err) {
        console.error(err)
    }
}

function judgeWebsite() {
    let href = window.location.href
    if (href.indexOf('sou.zhaopin.com') !== -1) {
        website = 'zlzp'
        addMutationObserver()
    } else {
        website = '51job'
    }
    console.log(website)
}

function addMutationObserver() {
    // 因为zlzp使用的都是ajax加载的数据,所以只能通过监视DOM变动
    let observer = new MutationObserver(() => {
        // console.log('DOM changed')
        doIgnore()
    })

    let number = setInterval(() => {
        let target = document.getElementById('listContent')
        if (null !== target) {
            doIgnore() // DOM布局第一次形成,先过滤一遍
            observer.observe(target, {'childList': true})
            clearInterval(number)
            // console.log('observer设置完毕,定时任务结束')
        } else {
            // console.log('dom还没有初始化完成,500毫秒后重试')
        }
    }, 500)
}

function doIgnore() {
    let compDivs = getDivListToIgnore()
    for (let i=0; i<compDivs.length; i++) {
        let item = compDivs[i]
        if (alreadyBeIgnored(item)) {
            continue
        }
        let cName = getRealCompanyName(item)
        if (isIgnoreCompany(cName)) {
            // console.log('匹配到:' + cName)
            addIgnoreClassTag(item)
            appendNewChildNode(item, cName)
        }
    }
}

function getDivListToIgnore() {
    if (website === '51job') {
        return document.querySelectorAll('.dw_table .el')
    } else {
        return document.querySelectorAll('.contentpile__content__wrapper .clearfix')
    }
}

function getRealCompanyName(node) {
    if (website === '51job') {
        return node.getElementsByClassName('t2')[0].textContent.trim()
    } else {
        return node.getElementsByClassName('company_title')[0].textContent.trim()
    }
}

// 添加一些全局样式
function appendGlobalStyle() {
    // 需要被忽略的节点
    buildStyle('.ISC_ignoreNode{height:30px !important;background-color:#dbecfe !important;}')
    // 需要被忽略的子节点
    buildStyle('.ISC_ignoreChildNode{display:none !important;}')
    // toolbox节点里面的
    if (website === '51job') {
        // 新添加的节点
        buildStyle('.ISC_appendNode{font-size: 10px;text-align: center;margin-top: -5px;color: #bababa;}')

        buildStyle('#ISC_info {position: fixed;bottom: 126px;margin-left: 1042px;text-align: center;padding-top: 5px;height: 48px;width: 48px;}')
        buildStyle('#ISC_input {bottom: 182px;height: 30px;}')
        buildStyle('#ISC_content {bottom: 215px;min-height: 150px;}')
        buildStyle('#ISC_content,#ISC_input {position: fixed;margin-left: 890px;box-shadow: 1px 1px 3px 0px #a3a3a3;width: 200px;opacity: 0.75;z-index: 10;}')
    } else {
        // 新添加的节点
        buildStyle('.ISC_appendNode{font-size: 10px;text-align: center;padding-top: 5px;color: #bababa;}')

        buildStyle('#ISC_info {position: fixed;bottom: 22px;margin-left: 800px;text-align: center;padding-top: 5px;height: 48px;width: 48px;}')
        buildStyle('#ISC_input {bottom: 73px;height: 30px;}')
        buildStyle('#ISC_content {bottom: 106px;min-height: 150px;}')
        buildStyle('#ISC_content,#ISC_input {position: fixed;margin-left: 800px;box-shadow: 1px 1px 3px 0px #a3a3a3;width: 200px;opacity: 0.75;z-index: 10;}')

        // 额外调整UI的
        buildStyle('#filterInput {line-height: initial;background: #fff;width: 155px;height: 21px;border: 1px solid #aaa;}')
        buildStyle('#filterButton {border: 1px solid #aaa;background-color: #eee;width: 31px;height: 22px;font-size: 14px;margin-bottom: 6px;}')
    }
    
    buildStyle('#ISC_info:hover {border-radius: 10px;box-shadow: 2px 2px 5px 0px #a3a3a3;}')
    buildStyle('#ISC_info:active {transform: scale(0.8);-webkit-transform: scale(0.8);-moz-transform: scale(0.8);-ms-transform: scale(0.8);}')
    buildStyle('#ISC_content,#ISC_input,#ISC_info,.ISC_keyword {background-color: #ecf5ff;border: 1px solid #409eff;color: #409eff;}')
    buildStyle('.ISC_keyword {margin: 5px;padding: 1px 2px;display: inline-block;color: #000;cursor: pointer;box-shadow: 2px 2px 4px 0px #a3a3a3;}')
    buildStyle('.ISC_keyword:hover {transform: scale(1.1);-webkit-transform: scale(1.1);-moz-transform: scale(1.1);-ms-transform: scale(1.1);}')
    buildStyle('#ISC_info,.ISC_keyword {transition: all 0.3s;-webkit-transition: all 0.3s;-moz-transition: all 0.3s;-ms-transition: all 0.3s;}')

    buildStyle('#filterInput, #filterButton {margin: 3px 2px;}')
    buildStyle('#ISC_node_copy {opacity: 0.4;}')
}

// 根据给定内容构造样式
function buildStyle(content) {
    let newStyle = document.createElement('style')
    newStyle.type = 'text/css'
    newStyle.innerHTML = content
    document.head.appendChild(newStyle)
}

// 是否是需要被忽略的
function isIgnoreCompany(cName) {
    for (let i = 0; i < companies.length; i++) {
        let ignoreName = companies[i]
        if (cName === ignoreName || cName.indexOf(ignoreName) !== -1) {
            return true
        }
    }
    return false
}

// 是否已经被过滤过了,true为已经被过滤了
function alreadyBeIgnored(node) {
    for (let i=0; i<node.classList.length; i++) {
        if ('ISC_ignoreNode' === node.classList[i]) {
            return true
        }
    }
    return false
}

// 处理需要被忽略的目标节点
function addIgnoreClassTag(node) {
    node.classList.add('ISC_ignoreNode')
    for (let j=0; j<node.children.length; j++) {
        node.children[j].classList.add('ISC_ignoreChildNode')
    }
}

// 被忽略的节点上增加一个div,用于显示忽略信息
function appendNewChildNode(node, name) {
    let div = document.createElement('div')
    div.classList.add('ISC_appendNode')
    div.innerText = '被忽略的公司 -> ' + name

    // 把被忽略的节点给恢复
    div.onclick = function (event) {
        event.target.parentNode.classList.remove('ISC_ignoreNode')
        let children = event.target.parentNode.children
        // HTMLCollection没有forEach
        // appendNode是append上去的,是在最后一个
        for (let i=0; i<children.length; i++) {
            if (children[i].classList.contains('ISC_ignoreChildNode')) {
                children[i].classList.remove('ISC_ignoreChildNode')
            } else if (children[i].classList.contains('ISC_appendNode')) {
                children[i].remove()
            }
        }
        document.getElementById('ISC_node_copy').remove()
    }
    
    div.onmouseenter = function (event) {
        let fNode = event.target.parentNode
        let fNodeCopy = fNode.cloneNode(true)
        fNodeCopy.classList.remove('ISC_ignoreNode')
        fNodeCopy.id = 'ISC_node_copy'
        fNodeCopy.getElementsByClassName('ISC_appendNode')[0].remove()
        for (let i=0; i<fNodeCopy.children.length; i++) {
            fNodeCopy.children[i].classList.remove('ISC_ignoreChildNode')
        }

        let nextNode = fNode.nextSibling
        if (nextNode === null) {
            fNode.parentNode.appendChild(fNodeCopy)
        } else {
            fNode.parentNode.insertBefore(fNodeCopy, nextNode)
        }
    }
    div.onmouseleave = function () {
        document.getElementById('ISC_node_copy').remove()
    }
    node.appendChild(div)
}

// 添加toolbox
function appendFloatDiv() {
    let toolbox = document.createElement('div')
    toolbox.id = 'ISC_toolbox'
    let content = document.createElement('div')
    content.id = 'ISC_content'
    content.style = 'display: none;'
    let input = document.createElement('div')
    input.id = 'ISC_input'
    input.style = 'display: none;'
    input.innerHTML = '<input id="filterInput" placeholder="关键字" type="text"/><button id="filterButton" type="button">添加</button>'
    let info = document.createElement('div')
    info.id = 'ISC_info'
    info.innerHTML = '<span>添加<br/>忽略</span>'
    info.onclick = function() {
        // 切换显示与否
        let visible = divVisibleSwitch()
        if (visible === 'block') {
            document.onwheel = function() {
                divVisibleSwitch()
                document.onwheel = undefined
            }
        } else {
            document.onwheel = undefined
        }
    }

    toolbox.appendChild(content)
    toolbox.appendChild(input)
    toolbox.appendChild(info)

    if (website === '51job') {
        document.getElementById('resultList').appendChild(toolbox)
    } else {
        document.getElementById('listItemPile').appendChild(toolbox)
    }

    document.getElementById('filterButton').onclick = function () {
        let keyword = document.getElementById('filterInput').value.trim()
        if (keyword.length === 0) {
            alert('不能使用空字符串')
            return
        }
        if (companies.length === 128) {
            alert('关键字限定数量为128,此刻关键字数量已达上限,可点击关键字进行删减')
            document.getElementById('filterInput').value = ''
            return
        }
        let status = addIntoCompanies(keyword)
        if (status !== -1) {
            let index = modifyLocalStorage()
            if (status !== 0) {
                // 等于0时已经在检测时替换掉了
                // 在content中显示该关键字
                document.getElementById('ISC_content').appendChild(buildContentChildNode(keyword, index))
            }
            doIgnore()
        } else {
            alert('关键字' + keyword + '已经存在,或者已经存在比它更详细的关键字了')
        }

        document.getElementById('filterInput').value = ''
    }

    // 敲击回车添加过滤
    document.getElementById('filterInput').onkeydown = function(e){
        if(e.keyCode === 13){
            document.getElementById('filterButton').click()
        }
    }
}

// 可见与不可见间转换
function divVisibleSwitch() {
    let obj1 = document.getElementById('ISC_input')
    let obj2 = document.getElementById('ISC_content')
    if (obj1.style.display === 'none') {
        obj1.style.display = 'block'
        obj2.style.display = 'block'
        return 'block'
    } else {
        obj1.style.display = 'none'
        obj2.style.display = 'none'
        return 'none'
    }
}

// 检查str是否已经在companies中存在,或者str是否包含或被包含于companies的某个值
// return 1 表示之前没有,现在已经添加进去了
// return 0 表示是一个更具体的值
// return -1 表示之前就有,或已有比其更具体值的存在
function addIntoCompanies(str) {
    if (companies === null) {
        companies = []
    }
    let len = companies.length
    for (let i=0; i<len; i++) {
        if (str === companies[i]) {
            return -1
        } else if (companies[i].indexOf(str) !== -1) {
            // str比companies[i]的值更具体,那么就需要用str替换对应的值
            companies[i] = str
            document.getElementById('ISC_keyword_' + i).textContent = str
            return 0
        } else if (str.indexOf(companies[i]) !== -1) {
            return -1
        }
    }

    companies.push(str)
    return 1
}

// 返回值作为新增节点的id
function modifyLocalStorage() {
    window.localStorage.setItem('companies', JSON.stringify(companies))
    return companies.length-1
}

// ISC_content区域里面的keyword节点
function buildContentChildNode(val, index) {
    let childNode = document.createElement('div')
    childNode.classList.add('ISC_keyword')
    let id = 'ISC_keyword_' + index
    childNode.id = id
    childNode.textContent = val
    childNode.onclick = function (event) {
        let tmpIndex = parseInt(event.target.id.split('_')[2])
        let tmpKeyword = event.target.innerText
        event.target.remove()
        companies.splice(tmpIndex, 1)
        modifyLocalStorage()
        correctNodeId(tmpIndex)
        removeIgnoredTag(tmpKeyword)
    }

    return childNode
}

// 点击删除一个节点后,后续节点的id就需要修正
// id值的最后一部分是代表这个关键字在companies中的序号
// index是刚被删除的节点的序号
function correctNodeId(index) {
    for (let i = index+1; i<=companies.length; i++) {
        let node = document.getElementById('ISC_keyword_' + i)
        if (null !== node) {
            node.id = 'ISC_keyword_' + (i - 1)
        }
    }
}

// 被移除的关键字对应的条目被恢复可见
function removeIgnoredTag(keyword) {
    let compDivs = getDivListToIgnore()
    for (let i=0; i<compDivs.length; i++) {
        let node = compDivs[i]
        if (alreadyBeIgnored(node)) {
            let cName = getRealCompanyName(node)
            if (cName.indexOf(keyword) !== -1) {
                node.classList.remove('ISC_ignoreNode')
                for (let j=0; j<node.children.length; j++) {
                    if (node.children[j].classList.contains('ISC_appendNode')) {
                        node.children[j].remove()
                    } else {
                        node.children[j].classList.remove('ISC_ignoreChildNode')
                    }
                }
            }
        }
    }
}

// 入口函数
init()