// ==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);
})();