Greasy Fork

Greasy Fork is available in English.

WELearn英语网课答案显示

悬浮窗显示选择题、填空题答案,口语参考文本,支持单元测试

当前为 2020-03-27 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         WELearn英语网课答案显示
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  悬浮窗显示选择题、填空题答案,口语参考文本,支持单元测试
// @author       SSmJaE
// @match        https://course.sflep.com/*
// @match        https://centercourseware.sflep.com/*
// @match        https://welearn.sflep.com/*
// @grant        GM_xmlhttpRequest
// @connect      *
// @license      MIT
// ==/UserScript==
(function () {
    'use strict';

    var container, title, bufferUrl;
    var parser = new DOMParser();
    const manifest = [
        'new%20century%20college%20english%20secedition%20integration%202',
        'an%20integrated%20skills%20course%20(2nd%20edition)%202%20for%20vocational%20college%20english',
        'an%20integrated%20skills%20course%202',
    ];
    const origin = [
        'new%20target%20college%20english%20integrated%20course%202',
        'new%20progressive%20college%20english%20integrated%20course%202',
    ]

    function createContainer() {
        container = document.createElement('div');
        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: #fff; min-width: 250px;max-width:400px; max-height: 500px; min-height: 200px;overflow:auto;")
        container.style.visibility = 'hidden';
        document.body.appendChild(container);

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

    function makeDraggable(elem) {
        document.mouseState = 'up'
        elem.mouseState = 'up'
        elem.lastMousePosY = null
        elem.lastMousePosX = null
        elem.proposedNewPosY = parseInt(elem.style.top, 10)
        elem.proposedNewPosX = parseInt(elem.style.left, 10)
        document.onmousedown = _ => {
            document.mouseState = 'down'
        }

        document.onmouseup = _ => {
            document.mouseState = 'up'
            elem.mouseState = 'up'
        }
        elem.onmousedown = e => {
            elem.lastMousePosY = e.pageY
            elem.lastMousePosX = e.pageX
            elem.mouseState = 'down'
            document.mouseState = 'down'
            document.onselectstart = e => {
                e.preventDefault()
                return false
            }
        }
        elem.onmouseup = e => {
            elem.mouseState = 'up'
            document.mouseState = 'up'
            document.onselectstart = null
        }
        const getAtInt = (obj, attrib) => parseInt(obj.style[attrib], 10)
        document.onmousemove = e => {
            if ((document.mouseState === 'down') && (elem.mouseState === 'down')) {
                elem.proposedNewPosY = getAtInt(elem.parentElement, 'top') + e.pageY - elem.lastMousePosY
                elem.proposedNewPosX = getAtInt(elem.parentElement, 'left') + e.pageX - elem.lastMousePosX
                if (elem.proposedNewPosY < 0) {
                    elem.parentElement.style.top = "0px"
                } else if (elem.proposedNewPosY > window.innerHeight - getAtInt(elem.parentElement, 'height')) {
                    elem.parentElement.style.top = window.innerHeight - getAtInt(elem.parentElement, 'height') + 'px'
                } else {
                    elem.parentElement.style.top = elem.proposedNewPosY + 'px'
                }
                if (elem.proposedNewPosX < 0) {
                    elem.parentElement.style.left = "0px"
                } else if (elem.proposedNewPosX > window.innerWidth - getAtInt(elem.parentElement, 'width')) {
                    elem.parentElement.style.left = window.innerWidth - getAtInt(elem.parentElement, 'width') + 'px'
                } else {
                    elem.parentElement.style.left = elem.proposedNewPosX + 'px'
                }
                elem.lastMousePosY = e.pageY
                elem.lastMousePosX = e.pageX
            }
        }
    }

    function addToContainer(htmlDOM, answers) {
        if (answers.length > 0) {
            for (let i = 0; i < answers.length; i++) {

                let content = document.createElement('div');
                let tag = answers[i].tagName;

                if (tag == 'ET-BLANK') {
                    content.textContent = answers[i].textContent;
                }
                if (tag == 'ET-CHOICE' || tag == 'ET-MATCHING') {
                    content.textContent = answers[i].getAttribute('key');
                }
                if (tag == 'ET-REFERENCE') {
                    content.innerHTML = answers[i].innerHTML;
                }
                if (tag == 'VALUE') {
                    let identifier = answers[i].textContent
                    if (identifier.length == 36) {
                        let selector = '[identifier="' + identifier + '"]';
                        content.textContent = htmlDOM.querySelector(selector).textContent;

                    } else {

                        content.textContent = answers[i].textContent;
                    }
                }
                if (answers[i].hasAttribute('data-solution')) {
                    let answer = answers[i].getAttribute('data-solution');
                    if (!answer.length) {
                        content.textContent = answers[i].firstElementChild.textContent;
                    } else {
                        content.textContent = answer;
                    }
                }
                content.setAttribute('style', "margin: 10px 10px; color: orange; font-size: medium; ")
                container.appendChild(content);
            }
        }
    }

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

    function parseAjax(htmlDOM) {
        container.innerHTML = '';
        container.appendChild(title);
        let blank = htmlDOM.querySelectorAll('et-blank'); //问答题+填空题
        let choice = htmlDOM.querySelectorAll('et-choice'); //选择题(二选一,多选)
        let matching = htmlDOM.querySelectorAll('et-matching'); //连线题
        let reference = htmlDOM.querySelectorAll('et-reference'); //口语参考
        let identifier = htmlDOM.querySelectorAll('correctresponse value'); //identifier类型
        addToContainer(htmlDOM, blank);
        addToContainer(htmlDOM, choice);
        addToContainer(htmlDOM, matching);
        addToContainer(htmlDOM, reference);
        addToContainer(htmlDOM, identifier);
        isShow();
    }




    function getManifest(manifestUrl, identifier, courseInfo) {
        let answerUrl;
        GM_xmlhttpRequest({
            method: "GET",
            url: manifestUrl,
            onload: answerUrl = 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');

                let answerUrl = 'https://centercourseware.sflep.com/' + courseInfo + '/' + resource;
                getAjax(answerUrl);
                return answerUrl;
            }
        });
        return answerUrl;
    }


    function getCurrentUrl() {
        let answerUrl = document.querySelector('div.courseware_main_1').firstElementChild.src;
        return answerUrl;
    }

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

    function getResource(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';
            let answerUrl = getManifest(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';
            getAjax(answerUrl);
        }
    }

    function isChange() {
        let currentUrl = getCurrentUrl();
        if (currentUrl != bufferUrl) {
            container.innerHTML = '';
            container.appendChild(title);
            getResource(currentUrl);
        }
        bufferUrl = currentUrl;
    }

    createContainer();
    makeDraggable(title);
    isChange();

    setInterval(isChange, 5000);
})();