WELearn英语网课答案显示

悬浮窗显示选择题、填空题、判断题、连线题答案,口语参考

目前為 2020-05-03 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         WELearn英语网课答案显示
// @namespace    http://tampermonkey.net/
// @version      0.4.7
// @description  悬浮窗显示选择题、填空题、判断题、连线题答案,口语参考
// @author       SSmJaE
// @match        https://course.sflep.com/*
// @match        https://welearn.sflep.com/*
// @match        https://centercourseware.sflep.com/*
// @grant        GM_xmlhttpRequest
// @connect      *
// @license      MIT
// @compatible   chrome
// ==/UserScript==
(function () {
    'use strict';

    var container, title, bufferUrl;
    const containerColor = 'rgba(255,255,255,0.95)'; //悬浮窗背景色
    const checkInterval = 3000; //答案查询间隔,单位毫秒
    const PARSER = new DOMParser();
    const MANIFEST = [
        'new%20century%20college%20english%20secedition%20integration%201',
        'new%20century%20college%20english%20secedition%20integration%202',
        'new%20century%20college%20english%20secedition%20integration%203',
        'new%20century%20college%20english%20secedition%20integration%204',
        'an%20integrated%20skills%20course%20(2nd%20edition)%201%20for%20vocational%20college%20english',
        'an%20integrated%20skills%20course%20(2nd%20edition)%202%20for%20vocational%20college%20english',
        'an%20integrated%20skills%20course%20(2nd%20edition)%203%20for%20vocational%20college%20english',
        'an%20integrated%20skills%20course%20(2nd%20edition)%204%20for%20vocational%20college%20english',
        'an%20integrated%20skills%20course%201',
        'an%20integrated%20skills%20course%202',
    ];
    const ORIGIN = [
        'new%20target%20college%20english%20integrated%20course%201',
        'new%20target%20college%20english%20integrated%20course%202',
        'new%20target%20college%20english%20integrated%20course%203',
        'new%20target%20college%20english%20integrated%20course%204',
        'new%20progressive%20college%20english%20integrated%20course%201',
        'new%20progressive%20college%20english%20integrated%20course%202',
        'new%20progressive%20college%20english%20integrated%20course%203',
        'new%20progressive%20college%20english%20integrated%20course%204',
    ]
    const answerTypes = [
        'et-tof', //判断题
        'et-blank', //问答题+填空题
        'et-select', //下拉选择题
        'et-choice', //选择题(二选一,多选)
        'et-matching', //连线题
        'et-reference', //口语参考
        'correctresponse value', //identifier类型
        'wordDeclaration', //高职单词测试
    ];

    function createContainer() {
        container = document.createElement('div');
        container.id = 'container';
        container.setAttribute('style', "top: 100px; left: 100px; margin: 0 auto; z-index: 99; border-radius: 8px;" +
            " box-shadow: 0 11px 15px -7px rgba(0,0,0,.2), 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12);" +
            " position: absolute; background:" + containerColor + "; min-width: 150px;max-width:400px; max-height: 500px; min-height: 100px;overflow:auto;")
        container.style.visibility = 'hidden';
        if (!top.document.querySelector('#container')) {
            top.document.body.appendChild(container);
        }

        title = document.createElement('div');
        title.textContent = '参考答案';
        title.setAttribute("style", "background: rgba(0,0,0,0); height: 25px; margin-top: 10px; text-align: center; font-size: x-large;cursor:move;");
        container.appendChild(title);
    }

    function dragBox(drag, wrap) {
        function getCss(ele, prop) {
            return parseInt(window.getComputedStyle(ele)[prop]);
        }

        var initX, initY,
            dragable = false,
            wrapLeft = getCss(wrap, "left"),
            wrapRight = getCss(wrap, "top");

        drag.addEventListener("mousedown", function (e) {
            dragable = true;
            initX = e.clientX;
            initY = e.clientY;
        }, false);

        document.addEventListener("mousemove", function (e) {
            if (dragable === true) {
                var nowX = e.clientX,
                    nowY = e.clientY,
                    disX = nowX - initX,
                    disY = nowY - initY;
                wrap.style.left = wrapLeft + disX + "px";
                wrap.style.top = wrapRight + disY + "px";
            }
        });

        drag.addEventListener("mouseup", function (e) {
            dragable = false;
            wrapLeft = getCss(wrap, "left");
            wrapRight = getCss(wrap, "top");
        }, false);

    };

    function emptyContainer() {
        container.innerHTML = '';
        container.appendChild(title);
        isShow();
    }

    function isShow() {
        container.childNodes.length > 1 ? container.style.visibility = 'visible' : container.style.visibility = 'hidden';
    }

    function getCurrentUrl() {
        let currentUrl;
        try {
            currentUrl = document.querySelector('div.courseware_main_1').firstElementChild.src;
        } catch (error) {
            currentUrl = top.frames[0].location.href;
        }
        return currentUrl;
    }

    function isChange() {
        let currentUrl = getCurrentUrl();
        if (currentUrl != bufferUrl) {
            emptyContainer();
            determineCourseType(currentUrl);
        }
        bufferUrl = currentUrl;
    }

    function determineCourseType(answerUrl) {
        let courseInfo = /com\/(.*?)\//.exec(answerUrl)[1];
        let identifier;
        try {
            identifier = /#(.*)\?/.exec(answerUrl)[1];
        } catch (error) {}

        if (MANIFEST.includes(courseInfo)) { //需要查询名单的
            let manifestUrl = 'https://centercourseware.sflep.com/' + courseInfo + '/resource/manifest.xml';
            queryManifest(manifestUrl, identifier, courseInfo);
        } else if (ORIGIN.includes(courseInfo)) { //直接在当前页面查找的
            setTimeout(() => {
                let answers = top.frames[0].document.querySelectorAll('[data-solution]');
                addToContainer('', answers);
                isShow();
            }, 2000);
        } else { //默认(视听说)
            answerUrl = 'https://centercourseware.sflep.com/' + courseInfo + '/data' + identifier + '.html';
            sendAjaxRequest(answerUrl);
        }
    }

    function queryManifest(manifestUrl, identifier, courseInfo) {
        GM_xmlhttpRequest({
            method: "GET",
            url: manifestUrl,
            onload: response => {
                let html = response.response;
                let htmlDOM = PARSER.parseFromString(html, 'text/html');
                let selector = 'resource[identifier="' + identifier + '"] file';
                let resource = htmlDOM.querySelector(selector).getAttribute('href').replace('.html', '.xml').replace('.htm', '');
                let answerUrl = 'https://centercourseware.sflep.com/' + courseInfo + '/' + resource;
                sendAjaxRequest(answerUrl);
            }
        });
    }

    function sendAjaxRequest(answerUrl) {
        GM_xmlhttpRequest({
            method: "GET",
            url: answerUrl,
            onload: response => {
                let html = response.response;
                let htmlDOM = PARSER.parseFromString(html, 'text/html');
                // console.log(htmlDOM);
                parseAjaxResponse(htmlDOM);
            }
        });
    }

    function parseAjaxResponse(htmlDOM) {
        emptyContainer();
        answerTypes.map(answerType => htmlDOM.querySelectorAll(answerType)).forEach(answers => addToContainer(htmlDOM, answers));
        isShow();
    }

    function addToContainer(htmlDOM, answers) {
        if (answers.length > 0) {
            for (let i = 0; i < answers.length; i++) {
                let content = document.createElement('div');
                // let br = document.createElement('br')
                let tag = answers[i].tagName;
                switch (tag) {
                    case 'ET-BLANK':
                        content.textContent = answers[i].textContent;
                        break;
                    case 'ET-TOF':
                    case 'ET-SELECT':
                    case 'ET-CHOICE':
                    case 'ET-MATCHING':
                        content.textContent = answers[i].getAttribute('key');
                        break;
                    case 'ET-REFERENCE':
                    case 'WORDDECLARATION':
                        content.innerHTML = answers[i].innerHTML;
                        break;
                    case 'VALUE':
                        (() => {
                            let identifier = answers[i].textContent;
                            if (identifier.length == 36) { //选择题
                                if (answers[i].textContent.length == 36) {
                                    let selector = '[identifier="' + identifier + '"]';
                                    try {
                                        content.textContent = htmlDOM.querySelector(selector).textContent;
                                    } catch (error) {
                                        content.textContent = answers[i].textContent; //高职第七八单元填空
                                    }
                                } else { //高职,非精编,综合,单元测试
                                    content.textContent = answers[i].textContent;
                                }

                            } else if (identifier.length > 200) { //纠错题
                                let selectors = identifier.split(',');
                                for (let i = 0; i < selectors.length; i++) {
                                    let selector = '[identifier="' + selectors[i] + '"]';
                                    content.innerHTML += htmlDOM.querySelector(selector).textContent + "<br>";
                                }
                            } else { //填空题
                                content.textContent = answers[i].textContent;
                            }
                        })();
                        break;
                    default:
                        (() => {
                            if (answers[i].hasAttribute('data-solution')) {
                                let answer = answers[i].getAttribute('data-solution');
                                if (!answer.length) {
                                    try {
                                        content.textContent = answers[i].firstElementChild.textContent;
                                    } catch (error) {
                                        content.textContent = answers[i].textContent;
                                    }
                                } else {
                                    content.textContent = answer;
                                }
                            }
                        })();
                        break;
                }
                if (content.textContent.length) {
                    content.textContent = String(i + 1) + '、' + content.textContent
                }
                content.setAttribute('style', "margin: 10px 10px; color: orange; font-size: medium;" +
                    "font-family:Georgia, 'Times New Roman', Times, serif; ");
                container.appendChild(content);

            }
        }
    }

    createContainer();
    dragBox(title, container);
    isChange();
    setInterval(isChange, checkInterval);
})();