您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
悬浮窗显示选择题、填空题、判断题、连线题答案,口语参考;
当前为
// ==UserScript== // @name WELearn英语网课答案显示 // @namespace http://tampermonkey.net/ // @version 0.5.1 // @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'; const USER_SETTINGS = { // autoSolve: false, //自动答题开关,还未完成 // solveInterval: 3000, //自动答题间隔,单位毫秒 checkInterval: 3000, //答案查询间隔,单位毫秒;多久检测一次页面是否改变 showReference: true, //是否显示听力、口语参考 containerColor: 'rgba(255,255,255,0.95)', //悬浮窗背景色 debugMode: true, //调试用,正常使用不用开 }; var container, title, bufferUrl, bufferTag, realOrder = 1; 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 ANSWER_TYPES = [ 'et-tof', //判断题 'et-blank', //问答题+填空题 'et-select', //下拉选择题 'et-choice', //选择题(二选一,多选) 'et-matching', //连线题 'et-reference', //口语参考 'wordDeclaration', //高职单词测试 'correctresponse value', //identifier类型 ]; function create_container() { 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:" + USER_SETTINGS.containerColor + "; width=400px;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 drag_box(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 empty_container() { container.innerHTML = ''; container.appendChild(title); is_show(); } function is_show() { container.childNodes.length > 1 ? container.style.visibility = 'visible' : container.style.visibility = 'hidden'; realOrder = 1; bufferTag = undefined; } function get_current_url() { let currentUrl; try { currentUrl = document.querySelector('div.courseware_main_1').firstElementChild.src; } catch (error) { currentUrl = top.frames[0].location.href; } return currentUrl; } function is_change() { let currentUrl = get_current_url(); if (currentUrl != bufferUrl) { empty_container(); determine_course_type(currentUrl); } bufferUrl = currentUrl; } function determine_course_type(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'; query_manifest(manifestUrl, identifier, courseInfo); } else if (ORIGIN.includes(courseInfo)) { //直接在原始页面查找 setTimeout(() => { let answers = top.frames[0].document.querySelectorAll('[data-solution]'); add_to_container('', answers); is_show(); }, 2000); } else { //默认(视听说) answerUrl = 'https://centercourseware.sflep.com/' + courseInfo + '/data' + identifier + '.html'; send_ajax_request(answerUrl); } } function query_manifest(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; send_ajax_request(answerUrl); } }); } function send_ajax_request(answerUrl) { GM_xmlhttpRequest({ method: "GET", url: answerUrl, onload: response => { let html = response.response; let htmlDOM = PARSER.parseFromString(html, 'text/html'); if (USER_SETTINGS.debugMode) { console.log(htmlDOM); } parse_ajax_response(htmlDOM); } }); } function parse_ajax_response(htmlDOM) { empty_container(); ANSWER_TYPES.map(answerType => htmlDOM.querySelectorAll(answerType)).forEach(answers => add_to_container(htmlDOM, answers)); is_show(); } function isRepeat(answerNode) { let parentElement = answerNode, parentTag; let webFlag = 0; let mobileFlag = 0; try { for (let i = 0; i < 9; i++) { if (i > 0) { parentElement = parentElement.parentElement; } parentTag = parentElement.tagName; if (USER_SETTINGS.debugMode) console.log(parentTag); if (parentTag == 'ET-MOBILE-ONLY') { mobileFlag += 1; } if (parentTag == 'ET-WEB-ONLY') { webFlag += 1; } } } catch (error) { if (USER_SETTINGS.debugMode) console.log(error); } finally { if (webFlag && mobileFlag) { //针对web下嵌套mobile的题目,如视听说2的3-2-3 if (webFlag > 1) { //针对4重嵌套,unit test常见 return true; } else { return false; } } else if (webFlag) { //web和mobile只留其一,这里保留mobile,丢弃web return true; } else { return false; } } } function add_to_container(htmlDOM, answers) { if (answers.length > 0) { for (let i = 0; i < answers.length; i++) { if (USER_SETTINGS.debugMode) { console.log(answers[i]); } let content = document.createElement('div'); let hr = document.createElement('hr'); // let br = document.createElement('br') let parentTag, web = false; let tag = answers[i].tagName; switch (tag) { case 'ET-BLANK': if (isRepeat(answers[i])) continue; content.textContent = answers[i].textContent.split("|")[0]; if (USER_SETTINGS.autoSolve) { //et-blank span span[style].value填空题 // //et-blank span.blank //et-blank textarea.blank问答题 //对于et类型,都先清空在输入,因为可能重复显示 //是否有必要实现逐个单词录入效果? //是否有必要实现打字音效 } break; case 'ET-TOF': //et-tof span.controls case 'ET-SELECT': case 'ET-CHOICE': if (isRepeat(answers[i])) //针对有只有inline的情况(视听说2 4-2),也就是说,不能跳 if (answers[i].hasAttribute('inline')) continue; //针对视听说2 7-1重复, //et-choice li.textContent //多选,需要分块解决tbody et-choice div span case 'ET-MATCHING': if (USER_SETTINGS.debugMode) console.log(isRepeat(answers[i])) if (isRepeat(answers[i])) { continue; } content.textContent = answers[i].getAttribute('key'); try { if (!content.textContent.length) content.textContent = answers[i].firstElementChild.textContent; } catch (error) { content.textContent = 'Answers will vary.'; } break; case 'ET-REFERENCE': if (!USER_SETTINGS.showReference) continue; 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; } //input[onfocus].value填空 //label[for].textContent选择 //document.querySelectorAll('input[style]')直接与identifier对应选择 //textarea[onchange] })(); 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; } } })(); //ul[data-itemtype] li 选择题 //input[data-itemtype]填空题 //最好有通解 break; } if (content.textContent.length) { let order; //控制序号的宽度一致 if (realOrder < 10) { order = ' ' + String(realOrder); } else { order = String(realOrder); } content.textContent = order + '、' + content.textContent; realOrder += 1; } else { continue; } content.setAttribute('style', "margin: 10px 10px; color: orange; font-size: medium;" + "font-family:Georgia, 'Times New Roman', Times, serif;white-space:pre-wrap; "); // if ((bufferTag !== tag) && (bufferTag !== undefined)) { // content.innerHTML = '<hr>' += content.innerHTML; container.appendChild(hr); } container.appendChild(content); content.offsetWidth; //强制浏览器刷新悬浮窗宽度 bufferTag = tag; } } } create_container(); drag_box(title, container); setInterval(is_change, USER_SETTINGS.checkInterval); })();