筛选ABDC

小工具

As of 2025-04-19. See the latest version.

// ==UserScript==
// @name         筛选ABDC
// @namespace    http://tampermonkey.net/
// @version      2025-04-19-001
// @description  小工具
// @author       周利斌
// @match        https://so1.imageoss.com/*
// @match        https://so3.cljtscd.com/scholar*
// @match        *://*/*
// @include        *webofscience*
// @include        *www-scopus-com*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=yitlink.com
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM.setValue
// @grant        GM.getValue
// @license MIT
// ==/UserScript==

(function () {
    "use strict";
    const btnStyle = "padding:5px;min-width: auto;"
    function appendTo(parentEle, tagName = "a", attrs = {}, functions = {}, id = "") {
        attrs = typeof attrs !== "string" ? attrs : { textContent: attrs };
        functions = typeof functions !== "function" ? functions : { click: functions };
        if (id && document.getElementById(id)) return document.getElementById(id)
        const ele = document.createElement(tagName);
        if (id) ele.id = id;
        for (const key in attrs) { ele[key] = attrs[key]; ele.setAttribute(key, attrs[key]); }
        for (const key in functions) ele.addEventListener(key, functions[key]);
        if (parentEle) parentEle.appendChild(ele);
        return ele;
    }
    function waitUtilAsync(callback, interval = 1000, timeout = 10000) {
        return new Promise((resolve, reject) => {
            const start = Date.now();
            const intervalId = setInterval(() => {
                const d = callback();
                if (d) {
                    clearInterval(intervalId);
                    resolve(d);
                } else if (Date.now() - start > timeout) {
                    clearInterval(intervalId);
                    resolve(false);
                }
            }, interval);
        });
    }
    function getRootDiv() {
        const existingDiv = document.getElementById('z_root_div');
        if (existingDiv) {
            return existingDiv;
        }

        const rootDiv = appendTo(document.body, "div", {
            id: "z_root_div",
            style: `
                    position: fixed;
                    z-index:999999;
                    background-color: lightblue;
                    cursor: move;
                    border: 2px solid purple;
                    border-left: 20px solid purple;
                `
        });

        // 使用 appendTo 设置左侧内边距颜色
        // appendTo(rootDiv, "div", {
        //     style: `
        //             position: absolute;
        //             left: 0;
        //             top: 0;
        //             bottom: 0;
        //             width: 20px;
        //             background-color: #660099;
        //         `
        // });

        // 恢复 rootDiv 的位置
        const savedLeft = GM_getValue('rootDivLeft', 0);
        const savedTop = GM_getValue('rootDivTop', 0);
        rootDiv.style.left = savedLeft + 'px';
        rootDiv.style.top = savedTop + 'px';

        let isDragging = false;
        let offsetX, offsetY;

        rootDiv.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - rootDiv.offsetLeft;
            offsetY = e.clientY - rootDiv.offsetTop;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                rootDiv.style.left = (e.clientX - offsetX) + 'px';
                rootDiv.style.top = (e.clientY - offsetY) + 'px';
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                // 保存 rootDiv 的位置
                GM_setValue('rootDivLeft', parseInt(rootDiv.style.left));
                GM_setValue('rootDivTop', parseInt(rootDiv.style.top));
            }
        });

        return rootDiv;
    }


    // Your code here...

    filterRank(".gs_r.gs_or.gs_scl")//scholar
    filterRank(".summary-record")//wos
    async function filterRank(selector = ".gs_r.gs_or.gs_scl") {
        if (!(await waitUtilAsync(() => document.querySelector(selector)))) { console.log("未找到", selector); return; }
        console.log("找到", selector);
        const lastClickBtn = GM_getValue("lastClickBtn")
        const btnClear = appendTo(getRootDiv(), "button", { textContent: "显示全部", style: btnStyle }, () => {
            lcb = undefined
            GM_setValue("lastClickBtn", "")
            for (const row of document.querySelectorAll(selector)) {
                const ck = row.querySelector("input[type=checkbox]")
                if (ck) {//wos
                    if (ck.checked) { ck.click() }
                    row.children[0].style.backgroundColor = "";
                }
                else {//scholar
                    row.style.maxHeight = "";
                    row.style.overflowY = ""
                    row.style.padding = ""
                }
                btnClear.textContent = "显示全部"
            }
        })
        createRankBtn("ABDC A*/A", ms => ms.some(m => m.includes("ABDC A")));
        createRankBtn("ABDC B", ms => ms.some(m => m.includes("ABDC B")));
        createRankBtn("SSCI IF>2", ms => ms.some(m => m.includes("SSCI")) && ms.some(m => m.startsWith("IF") && asIF(m) > 2));
        createRankBtn("IF>8", ms => ms.some(m => m.startsWith("IF") && asIF(m) > 8));
        createRankBtn("CiteScore>12", ms => ms.some(m => m.includes("CiteScore") && asIF(m) > 12));
        /**
         *
         * @param {string} content
         * @returns number
         */
        function asIF(content) {
            const IF = parseFloat(content.match(/([\d\.]+)$/g)?.[0]) || 0
            // console.log(content.match(/[\d\.]+/g), IF, content);
            return IF
        }
        /**
         *
         * @param {number} id
         * @param {string} btnTxt
         * @param {(rankInfos:string[])=>boolean} checkFunc
         */
        function createRankBtn(btnTxt = "", checkFunc = (a) => false) {
            const btn = appendTo(getRootDiv(), "button", { style: btnStyle, textContent: btnTxt }, () => {
                if (lcb != btn) {
                    lcb = btn
                    GM_setValue("lastClickBtn", btnTxt)
                }

                const qList = document.querySelectorAll(selector)
                let check = 0, checked = 0;
                for (const row of qList) {
                    const rks = [...row.querySelectorAll(".srankInfo")].map(a => a.textContent)
                    const ck = row.querySelector("input[type=checkbox]")
                    if (ck) {//wos
                        if (checkFunc(rks)) {
                            row.children[0].style.backgroundColor = getComputedStyle(row.querySelector(".srankInfo")).backgroundColor;
                            if (ck.checked) {
                                checked++;
                            } else {
                                ck.click();
                                check++;
                            }
                        }
                    }
                    else {//scholar
                        if (checkFunc(rks)) {
                            //  row.style.borderLeft= ""
                            //  row.style.backgroundClip= ""
                            //  row.style.backgroundOrigin= ""
                            //  row.style.backgroundImage= ""
                            row.style.borderLeft = ""
                            row.style.maxHeight = "";
                            row.style.overflowY = ""
                            row.style.padding = ""
                            check++
                        }
                        else {
                            //  row.style.borderLeft= "4px solid transparent"
                            //  row.style.backgroundClip= "padding-box, border-box"
                            //  row.style.backgroundOrigin= "padding-box, border-box"
                            //  row.style.backgroundImage= "linear-gradient(to bottom, #222, #222), linear-gradient(90deg, #8F41E9, #578AEF)"

                            row.style.borderLeft = "5px solid #300"
                            row.style.maxHeight = "1px"
                            row.style.overflowY = "hidden"
                            row.style.padding = "0px"
                        }
                    }
                }
                {//wos
                    const checkCount = document.querySelector("#snRecListTop .mat-checkbox")?.textContent || "";
                    const page = document.querySelector("#snNextPageTop")?.value || "";
                    const pageAll = document.querySelector("body > app-wos > main > div > div > div.holder > div > div > div.held > app-input-route > app-base-summary-component > div > div.results.ng-star-inserted > app-page-controls.app-page-controls.ng-star-inserted > div > form > div")?.textContent || "";
                    const rankLength = document.querySelectorAll(".srankdiv").length;
                    const birdLength = document.querySelectorAll(".gs_ri .scicrx-ico").length;

                    btnClear.textContent = `显示全部【${check}/${checked}/${qList.length}/${checkCount} / ${page} ${pageAll} ${rankLength} ${birdLength}】`;
                }
            });
            if (btnTxt == lastClickBtn)
                btn.click()
            return btn
        }
    }
    let lcb = undefined
    if (!window.rankInfoObserver) {
        window.rankInfoObserver =
            new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1 && node.classList.contains('srankdiv')) {
                            console.log(`.srankdiv 的数量: ${document.querySelectorAll('.srankdiv').length}`);
                            if (lcb) setTimeout(() => lcb.click(), 500)
                        }
                    });
                });
            });
        window.rankInfoObserver.observe(document.body, { childList: true, subtree: true });
    }
    //设置最小高度,让滚动条一直存在
    const gs_bdy = document.querySelector("#gs_bdy");
    if (gs_bdy) {
        gs_bdy.style.minHeight = "600px";
    }

    init();
})();