refactor tampermonkey script
This commit is contained in:
		
							
								
								
									
										203
									
								
								jetbra.js
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								jetbra.js
									
									
									
									
									
								
							@@ -3,7 +3,7 @@
 | 
			
		||||
// @namespace    https://github.com/novice88/jetbra
 | 
			
		||||
// @version      1.1
 | 
			
		||||
// @license MIT
 | 
			
		||||
// @description  添加一个按钮,点击获取插件的激活码
 | 
			
		||||
// @description  Add a button on the plugin homepage and click to get the plugin activation code
 | 
			
		||||
// @author       novice.li
 | 
			
		||||
// @match        https://plugins.jetbrains.com/plugin/*
 | 
			
		||||
// @grant        GM_setClipboard
 | 
			
		||||
@@ -14,189 +14,19 @@
 | 
			
		||||
// @connect localhost
 | 
			
		||||
// ==/UserScript==
 | 
			
		||||
 | 
			
		||||
var elmGetter = function() {
 | 
			
		||||
    const win = window.unsafeWindow || document.defaultView || window;
 | 
			
		||||
    const doc = win.document;
 | 
			
		||||
    const listeners = new WeakMap();
 | 
			
		||||
    let mode = 'css';
 | 
			
		||||
    let $;
 | 
			
		||||
    const elProto = win.Element.prototype;
 | 
			
		||||
    const matches = elProto.matches ||
 | 
			
		||||
        elProto.matchesSelector ||
 | 
			
		||||
        elProto.webkitMatchesSelector ||
 | 
			
		||||
        elProto.mozMatchesSelector ||
 | 
			
		||||
        elProto.oMatchesSelector;
 | 
			
		||||
    const MutationObs = win.MutationObserver ||
 | 
			
		||||
        win.WebkitMutationObserver ||
 | 
			
		||||
        win.MozMutationObserver;
 | 
			
		||||
    function addObserver(target, callback) {
 | 
			
		||||
        const observer = new MutationObs(mutations => {
 | 
			
		||||
            for (const mutation of mutations) {
 | 
			
		||||
                if (mutation.type === 'attributes') {
 | 
			
		||||
                    callback(mutation.target);
 | 
			
		||||
                    if (observer.canceled) return;
 | 
			
		||||
                }
 | 
			
		||||
                for (const node of mutation.addedNodes) {
 | 
			
		||||
                    if (node instanceof Element) callback(node);
 | 
			
		||||
                    if (observer.canceled) return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        observer.canceled = false;
 | 
			
		||||
        observer.observe(target, {childList: true, subtree: true, attributes: true});
 | 
			
		||||
        return () => {
 | 
			
		||||
            observer.canceled = true;
 | 
			
		||||
            observer.disconnect();
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    function addFilter(target, filter) {
 | 
			
		||||
        let listener = listeners.get(target);
 | 
			
		||||
        if (!listener) {
 | 
			
		||||
            listener = {
 | 
			
		||||
                filters: new Set(),
 | 
			
		||||
                remove: addObserver(target, el => listener.filters.forEach(f => f(el)))
 | 
			
		||||
            };
 | 
			
		||||
            listeners.set(target, listener);
 | 
			
		||||
 | 
			
		||||
async function findElementWithRetry(cssSelector) {
 | 
			
		||||
    const maxAttempts = 50;
 | 
			
		||||
    for (let attempts = 0; attempts < maxAttempts; attempts++) {
 | 
			
		||||
        const element = document.querySelector(cssSelector);
 | 
			
		||||
        if (element) {
 | 
			
		||||
            return element;
 | 
			
		||||
        }
 | 
			
		||||
        listener.filters.add(filter);
 | 
			
		||||
        await new Promise(resolve => setTimeout(resolve, 100));
 | 
			
		||||
    }
 | 
			
		||||
    function removeFilter(target, filter) {
 | 
			
		||||
        const listener = listeners.get(target);
 | 
			
		||||
        if (!listener) return;
 | 
			
		||||
        listener.filters.delete(filter);
 | 
			
		||||
        if (!listener.filters.size) {
 | 
			
		||||
            listener.remove();
 | 
			
		||||
            listeners.delete(target);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    function query(all, selector, parent, includeParent, curMode) {
 | 
			
		||||
        switch (curMode) {
 | 
			
		||||
            case 'css':
 | 
			
		||||
                const checkParent = includeParent && matches.call(parent, selector);
 | 
			
		||||
                if (all) {
 | 
			
		||||
                    const queryAll = parent.querySelectorAll(selector);
 | 
			
		||||
                    return checkParent ? [parent, ...queryAll] : [...queryAll];
 | 
			
		||||
                }
 | 
			
		||||
                return checkParent ? parent : parent.querySelector(selector);
 | 
			
		||||
            case 'jquery':
 | 
			
		||||
                let jNodes = $(includeParent ? parent : []);
 | 
			
		||||
                jNodes = jNodes.add([...parent.querySelectorAll('*')]).filter(selector);
 | 
			
		||||
                if (all) return $.map(jNodes, el => $(el));
 | 
			
		||||
                return jNodes.length ? $(jNodes.get(0)) : null;
 | 
			
		||||
            case 'xpath':
 | 
			
		||||
                const ownerDoc = parent.ownerDocument || parent;
 | 
			
		||||
                selector += '/self::*';
 | 
			
		||||
                if (all) {
 | 
			
		||||
                    const xPathResult = ownerDoc.evaluate(selector, parent, null, 7, null);
 | 
			
		||||
                    const result = [];
 | 
			
		||||
                    for (let i = 0; i < xPathResult.snapshotLength; i++) {
 | 
			
		||||
                        result.push(xPathResult.snapshotItem(i));
 | 
			
		||||
                    }
 | 
			
		||||
                    return result;
 | 
			
		||||
                }
 | 
			
		||||
                return ownerDoc.evaluate(selector, parent, null, 9, null).singleNodeValue;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    function isJquery(jq) {
 | 
			
		||||
        return jq && jq.fn && typeof jq.fn.jquery === 'string';
 | 
			
		||||
    }
 | 
			
		||||
    function getOne(selector, parent, timeout) {
 | 
			
		||||
        const curMode = mode;
 | 
			
		||||
        return new Promise(resolve => {
 | 
			
		||||
            const node = query(false, selector, parent, false, curMode);
 | 
			
		||||
            if (node) return resolve(node);
 | 
			
		||||
            let timer;
 | 
			
		||||
            const filter = el => {
 | 
			
		||||
                const node = query(false, selector, el, true, curMode);
 | 
			
		||||
                if (node) {
 | 
			
		||||
                    removeFilter(parent, filter);
 | 
			
		||||
                    timer && clearTimeout(timer);
 | 
			
		||||
                    resolve(node);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            addFilter(parent, filter);
 | 
			
		||||
            if (timeout > 0) {
 | 
			
		||||
                timer = setTimeout(() => {
 | 
			
		||||
                    removeFilter(parent, filter);
 | 
			
		||||
                    resolve(null);
 | 
			
		||||
                }, timeout);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
        get currentSelector() {
 | 
			
		||||
            return mode;
 | 
			
		||||
        },
 | 
			
		||||
        get(selector, ...args) {
 | 
			
		||||
            let parent = typeof args[0] !== 'number' && args.shift() || doc;
 | 
			
		||||
            if (mode === 'jquery' && parent instanceof $) parent = parent.get(0);
 | 
			
		||||
            const timeout = args[0] || 0;
 | 
			
		||||
            if (Array.isArray(selector)) {
 | 
			
		||||
                return Promise.all(selector.map(s => getOne(s, parent, timeout)));
 | 
			
		||||
            }
 | 
			
		||||
            return getOne(selector, parent, timeout);
 | 
			
		||||
        },
 | 
			
		||||
        each(selector, ...args) {
 | 
			
		||||
            let parent = typeof args[0] !== 'function' && args.shift() || doc;
 | 
			
		||||
            if (mode === 'jquery' && parent instanceof $) parent = parent.get(0);
 | 
			
		||||
            const callback = args[0];
 | 
			
		||||
            const curMode = mode;
 | 
			
		||||
            const refs = new WeakSet();
 | 
			
		||||
            for (const node of query(true, selector, parent, false, curMode)) {
 | 
			
		||||
                refs.add(curMode === 'jquery' ? node.get(0) : node);
 | 
			
		||||
                if (callback(node, false) === false) return;
 | 
			
		||||
            }
 | 
			
		||||
            const filter = el => {
 | 
			
		||||
                for (const node of query(true, selector, el, true, curMode)) {
 | 
			
		||||
                    const _el = curMode === 'jquery' ? node.get(0) : node;
 | 
			
		||||
                    if (refs.has(_el)) break;
 | 
			
		||||
                    refs.add(_el);
 | 
			
		||||
                    if (callback(node, true) === false) {
 | 
			
		||||
                        return removeFilter(parent, filter);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            addFilter(parent, filter);
 | 
			
		||||
        },
 | 
			
		||||
        create(domString, ...args) {
 | 
			
		||||
            const returnList = typeof args[0] === 'boolean' && args.shift();
 | 
			
		||||
            const parent = args[0];
 | 
			
		||||
            const template = doc.createElement('template');
 | 
			
		||||
            template.innerHTML = domString;
 | 
			
		||||
            const node = template.content.firstElementChild;
 | 
			
		||||
            if (!node) return null;
 | 
			
		||||
            parent ? parent.appendChild(node) : node.remove();
 | 
			
		||||
            if (returnList) {
 | 
			
		||||
                const list = {};
 | 
			
		||||
                node.querySelectorAll('[id]').forEach(el => list[el.id] = el);
 | 
			
		||||
                list[0] = node;
 | 
			
		||||
                return list;
 | 
			
		||||
            }
 | 
			
		||||
            return node;
 | 
			
		||||
        },
 | 
			
		||||
        selector(desc) {
 | 
			
		||||
            switch (true) {
 | 
			
		||||
                case isJquery(desc):
 | 
			
		||||
                    $ = desc;
 | 
			
		||||
                    return mode = 'jquery';
 | 
			
		||||
                case !desc || typeof desc.toLowerCase !== 'function':
 | 
			
		||||
                    return mode = 'css';
 | 
			
		||||
                case desc.toLowerCase() === 'jquery':
 | 
			
		||||
                    for (const jq of [window.jQuery, window.$, win.jQuery, win.$]) {
 | 
			
		||||
                        if (isJquery(jq)) {
 | 
			
		||||
                            $ = jq;
 | 
			
		||||
                            break;
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                    return mode = $ ? 'jquery' : 'css';
 | 
			
		||||
                case desc.toLowerCase() === 'xpath':
 | 
			
		||||
                    return mode = 'xpath';
 | 
			
		||||
                default:
 | 
			
		||||
                    return mode = 'css';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}();
 | 
			
		||||
    throw new Error(`Element with selector '${cssSelector}' not found after ${maxAttempts} attempts.`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
(async function () {
 | 
			
		||||
    'use strict';
 | 
			
		||||
    GM_addStyle(`
 | 
			
		||||
@@ -227,17 +57,16 @@ var elmGetter = function() {
 | 
			
		||||
 | 
			
		||||
    let pluginDetail = await fetch('https://plugins.jetbrains.com/api/plugins/' + pluginId).then(r => r.json());
 | 
			
		||||
 | 
			
		||||
    const parentElement = await elmGetter.get('.plugin-header__controls-panel > div:first-child');
 | 
			
		||||
    const parentElement = await findElementWithRetry('.plugin-header__controls-panel > div:first-child');
 | 
			
		||||
 | 
			
		||||
    let newElement = document.createElement('div');
 | 
			
		||||
    newElement.classList.toggle('wt-col-inline');
 | 
			
		||||
    newElement.innerHTML = `<button class="jetbra-button" type="button">点击生成激活码</button>`;
 | 
			
		||||
    newElement.innerHTML = `<button class="jetbra-button" type="button">CLICK TO GENERATE ACTIVATION CODE</button>`;
 | 
			
		||||
    parentElement.appendChild(newElement)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    newElement.addEventListener('click', async () => {
 | 
			
		||||
        if (pluginDetail.purchaseInfo === undefined) {
 | 
			
		||||
            window.alert('此插件不是付费插件');
 | 
			
		||||
            window.alert('This plugin is not a paid plugin in the market');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        let data = {
 | 
			
		||||
@@ -268,7 +97,7 @@ var elmGetter = function() {
 | 
			
		||||
            onload: function (response) {
 | 
			
		||||
                let license = JSON.parse(response.responseText).license
 | 
			
		||||
                GM_setClipboard(license, 'text');
 | 
			
		||||
                window.alert('激活码已复制到剪切版');
 | 
			
		||||
                window.alert('The activation code has been copied to your clipboard');
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    })
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user