Greasy Fork is available in English.
悬浮窗显示选择题、填空题、判断题、连线题答案,口语参考;
当前为
// ==UserScript==
// @name WELearn英语网课答案显示
// @namespace http://tampermonkey.net/
// @version 0.5
// @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: false, //调试用,正常使用不用开
};
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 = false;
let mobileFlag = false;
try {
for (let i = 0; i < 7; i++) {
if (i > 0) {
parentElement = parentElement.parentElement;
}
parentTag = parentElement.tagName;
if (USER_SETTINGS.debugMode) console.log(parentTag);
if (parentTag == 'ET-MOBILE-ONLY') {
mobileFlag = true;
}
if (parentTag == 'ET-WEB-ONLY') {
webFlag = true;
}
}
} catch (error) {
if (USER_SETTINGS.debugMode) console.log(error);
} finally {
if (webFlag && mobileFlag) { //针对web下嵌套mobile的题目,如视听说2的3-2-3
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 = '无固定答案';
}
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);
is_change();
setInterval(is_change, USER_SETTINGS.checkInterval);
})();