计蒜客助手 Jisuanke Helper

1. 取消复制限制; 2. 选择题显示序号(一般情况最小的几个是答案); 3. 跳过强制等待; 4. 双击单行或块代码区域复制代码; 5. 跳过点击直接复制提示内容

目前為 2020-02-19 提交的版本,檢視 最新版本

// ==UserScript==
// @name         计蒜客助手 Jisuanke Helper
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  1. 取消复制限制; 2. 选择题显示序号(一般情况最小的几个是答案); 3. 跳过强制等待; 4. 双击单行或块代码区域复制代码; 5. 跳过点击直接复制提示内容
// @author       yusanshi
// @source       https://gist.github.com/yusanshi/981b5926851d4cde3d67536b279cbf34
// @match        http://www.jisuanke.com/course/*
// @match        https://www.jisuanke.com/course/*
// @grant        none
// @run-at       document-start
// @require      https://cdn.jsdelivr.net/gh/colxi/getEventListeners/src/getEventListeners.min.js
// ==/UserScript==

(function () {
    'use strict';

    // Run continually
    setInterval(() => {
        // Remove disabled and oncopy attribute
        removeCls('jsk-disabled');
        for (let elem of ['disabled', 'oncopy', 'oncut']) {
            removeAttr(elem);
        }

        // Delete line numbers to avoid its being copied when using free copy
        for (let selector of ['#guide', '#lint', '#container-content']) {
            for (let elem of document.querySelectorAll(`${selector} .CodeMirror-linenumber`)) {
                elem.remove();
            }
        }

        // Remove mousedown event handler
        for (let selector of ['#guide', '#lint', '#container-content']) {
            for (let elem of document.querySelectorAll(`${selector} .CodeMirror-scroll`)) {
                customRemoveEventLister(elem, 'mousedown');
            }
        }

        // Remove selectstart event handler
        for (let selector of ['#guide', '#lint', '#container-content']) {
            for (let elem of document.querySelectorAll(`${selector} .CodeMirror-lines`)) {
                customRemoveEventLister(elem.querySelector('div'), 'selectstart');
            }
        }

        // Double click to copy
        for (let i of ['#guide', '#lint', '#container-content']) {
            for (let j of ['code', '.CodeMirror-scroll']) {
                for (let elem of document.querySelectorAll(`${i} ${j}`)) {
                    elem.ondblclick = () => {
                        copyTextToClipboard(elem.innerText);
                    }
                }
            }
        }

        // Skip waiting
        for (let elem of document.querySelectorAll('[data-unlocked]')) {
            elem.setAttribute('data-unlocked', '999');
        }

    }, 500);


    window.onload = () => {
        // Add number prompts for multiple choice problem
        for (let elem of document.querySelectorAll('[num]')) {
            const span = document.createElement('span');
            span.style.color = 'green';
            span.innerText = elem.getAttribute('num');
            elem.insertAdjacentElement('afterbegin', span);
        }

        // Skip clicking hint to copy its text directly
        const hint = document.querySelector('#hint');
        if (hint) {
            const button = document.createElement('button');
            button.innerText = 'Copy hint directly';
            button.className = 'jsk-btn jsk-btn-success hint-btn';
            button.style.marginBottom = '0.5rem';
            button.onclick = () => {
                // Simulate clicking and closing the popup window, in order to
                // make hint.querySelector('.CodeMirror-scroll') fullfilled.
                // Looks argly, a better approach may exist
                document.querySelector('#hint-btn').click();
                hint.querySelector('.jsk-close').click();
                for (let elem of hint.querySelectorAll(`.CodeMirror-linenumber`)) {
                    elem.remove();
                }
                // Copy last code area if multiple code areas in #lint are present
                const allCode = hint.querySelectorAll('.CodeMirror-scroll');
                copyTextToClipboard(allCode[allCode.length - 1].innerText);
            }
            hint.insertAdjacentElement('afterbegin', button);
        }
    }

    function customRemoveEventLister(target, listenerType) {
        const listeners = target.getEventListeners(listenerType);
        if (typeof listeners !== 'undefined') {
            for (let event of listeners) {
                target.removeEventListener(event.type, event.listener, event.useCapture);
            }
        }
    }

    function removeCls(cls) {
        for (let elem of document.querySelectorAll(`.${cls}`)) {
            elem.classList.remove(cls);
        }
    }

    function removeAttr(attr) {
        for (let elem of document.querySelectorAll(`[${attr}]`)) {
            elem.removeAttribute(attr);
        }
    }

    // https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
    function copyTextToClipboard(text) {
        if (!navigator.clipboard) {
            fallbackCopyTextToClipboard(text);
            return;
        }
        navigator.clipboard.writeText(text).then(function () {
            console.log('Async: Copying to clipboard was successful!');
        }, function (err) {
            console.error('Async: Could not copy text: ', err);
        });
    }

    function fallbackCopyTextToClipboard(text) {
        const textArea = document.createElement("textarea");
        textArea.value = text;
        textArea.style.position = "fixed"; //avoid scrolling to bottom
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();

        try {
            const successful = document.execCommand('copy');
            const msg = successful ? 'successful' : 'unsuccessful';
            console.log('Fallback: Copying text command was ' + msg);
        } catch (err) {
            console.error('Fallback: Oops, unable to copy', err);
        }
        document.body.removeChild(textArea);
    }

})();