// ==UserScript==
// @name wjx_autofill
// @namespace _s7util__
// @version 0.1.18
// @description 根据用户设定,自动填写问卷星问卷
// @author shc0743
// @match http*://*.wjx.top/*
// @match http*://*.wjx.com/*
// @match http*://*.wjx.cn/*
// @match http*://survey.coreland.net/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// @supportURL mailto:shc0743@outlook.com?subject=wjx_autofill%20Report
// @license GPL-3.0
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// Your code here...
var only_run_in_top_frame = true;
try {
let unwritable_list = [
{
object: window.document,
key: 'oncontextmenu'
},
{
object: window.document,
key: 'ondragstart'
},
{
object: window.document,
key: 'onselectstart'
},
];
for (let i of unwritable_list) {
Object.defineProperty(i.object, i.key, {
get() { return null },
set(value) { void (value) },
enumerable: false,
configurable: true
});
}
}
catch (error) {
console.warn(error);
}
function DCL () {
/* **** [BEGIN] Script **** */
if (only_run_in_top_frame && (window.top != window.self)) return null;
if (location.host.includes('survey.coreland.net')) {
location.host = 'ks.wjx.top'
return;
}
if (location.pathname.startsWith('/vm/')) {
location = location.href.replace('/vm/', '/vj/');
return;
}
/* **** [BEGIN] 根元素创建 **** */
var root = document.createElement('div');
document.body.append(root);
/* **** [END] 根元素创建 **** */
/* **** [BEGIN] 数据声明 **** */
var panel_class = '__' + randstr(8);
var myops_classn = '__opts' + randstr(4);
var mydlg_classn = '__' + randstr(8);
var myhovbn_classn = '__btn_hover_' + randstr(4);
var mybnchecked_classn = '__btn_checked_' + randstr(4);
var bgwhite_classn = '__bgwhite_' + randstr(4);
var mytimer_classn = '__' + randstr(8);
var mytedit_classn;
var mysett_classn;
var sess_q_ans = '__wjx_autofill_enter_q_answer_mode';
var sess_autofill = '__wjx_autofill_execute_autofill';
var sess_settings = '__wjx_autofill_open_settings';
var sess_lastpage = '__wjx_autofill_last_page';
var sess_shwtimer = '__wjx_autofill_show_timer';
var szDataKeyName = '__wjx_autofill_datas_part';
var nAvailableStorageId_regexp = /([^A-z0-9])|\[|\]|\^|\`|\\/igm;
var nAvailableStorageId = '0';
nAvailableStorageId = location.pathname.replace(
nAvailableStorageId_regexp, '_');
var nTempStorageId = '0_temp';
{
let str = randstr(8);
mytedit_classn = '__t' + str;
mysett_classn = '__s' + str;
}
/* **** [END] 数据声明 **** */
/* **** [BEGIN] CSS **** */
var style1 = document.createElement('style');
style1.innerHTML = `
/* Global styles */
* {
user-select: text !important;
-webkit-user-select: text !important;
-moz-user-select: text !important;
-comment-comment: "Enable selecting";
}
*[disabled] {
cursor: not-allowed !important;
}
/* Class styles */
.${panel_class}
, .${mytedit_classn}, .${mysett_classn}
, .${mytimer_classn}
{
display: block;
text-align: center;
position: fixed;
box-shadow: 0 0 5px 0;
background: rgba(255, 255, 255, 0.9);
padding: 5px 5px;
font-size: 13px;
}
.${panel_class} {
z-index: 1048571;
left: 10px;
bottom: 10px;
border: 1px solid #cccccc;
}
.${mytedit_classn}, .${mysett_classn} {
position: fixed;
left: 50%;
top: 50%;
min-width: 50%;
min-height: 50%;
transform: translate(-50%, -50%);
border: 2px solid #aaa;
z-index: 1048572;
}
.${mytedit_classn} div[data-container],
.${mysett_classn} div[data-container] {
overflow: auto;
}
.${mytedit_classn} div[data-container] button {
display: block;
width: 100%;
margin-top: 5px;
padding: 3px 3px 3px 3px;
}
.${mytedit_classn} div[data-container] button[data-code]::after {
content: " (" attr(data-code) ")";
}
.${mytedit_classn} div[data-title] button.h,
.${mytedit_classn} div[data-title] button.x,
.${mydlg_classn} div[data-title] button.h,
.${mydlg_classn} div[data-title] button.x {
width: 22px;
height: 22px;
}
.${panel_class} a {
display: block;
color: blue;
cursor: pointer;
text-decoration: none;
margin-top: 3px;
}
.${panel_class} a:hover {
color: #f90;
background: #dddddd;
text-decoration: underline;
}
.${myops_classn} {
margin: 1px 1px;
padding: 3px 3px;
}
.${mydlg_classn} .x {
position: absolute;
right: 5px;
}
.${mydlg_classn} a, .${mydlg_classn} button {
cursor: pointer;
}
.${mydlg_classn} hr {
border-style: inset;
border-width: 1px;
}
.${mytimer_classn} {
right: 50px;
top: 50px;
z-index: 1048572;
color: black;
}
.${mytimer_classn} div[data-title] {
text-align: right;
}
.${mytimer_classn} button.x {
cursor: pointer;
background: white;
border-radius: 100%;
border: 0;
}
.${mytimer_classn} div[data-container] {
font-size: 15px;
}
.${mytimer_classn} button.x:hover {
background: #cccccc;
}
.${myhovbn_classn} {
border: 2px solid #ffffff;
}
.${myhovbn_classn}:hover {
border: 2px dashed;
}
.${bgwhite_classn} {
background: #ffffff;
}
.${mybnchecked_classn} {
background: rgba(221, 221, 221, 0.9);
}
`; // style1.innerHTML
root.append(style1);
/* **** [END] CSS **** */
/* **** [BEGIN] 面板UI **** */
var panel = document.createElement('div');
panel.classList.add(panel_class);
panel.innerHTML = `<div>wjx_autofill</div>
<div class="${myops_classn}"></div>`;
root.append(panel);
let p_fieldset = panel.querySelector(`.${myops_classn}`);
let op_list = {
"进入编辑模式": function () {
sessionStorage.setItem(sess_q_ans, '1');
location.reload();
},
"执行自动填写": function () {
sessionStorage.setItem(sess_autofill, '1');
location.reload();
},
"显示所有问题": function () {
showAllQuestions();
arguments[0].remove();
},
"打开计时器": function () {
sessionStorage.setItem(sess_shwtimer, '1');
exec_showtimer();
},
"设置": function () {
sessionStorage.setItem(sess_settings, '1');
location.reload();
},
"关闭": function () {
panel.style.display = 'none';
},
}; // let op_list
if (p_fieldset) {
for (let i in op_list) {
let a = document.createElement('a');
a.href = 'javascript:void(0)';
a.innerHTML = i;
a.__op = i;
a.onclick = function (ev) {
(ev || event).preventDefault();
try { op_list[this.__op](this); }
catch (err) {
console.error(
'Error executing operation '
+ i + ':', err);
};
}
p_fieldset.append(a);
}
} // if (p_fieldset)
/* **** [END] 面板UI **** */
/* **** [BEGIN] 储存检测 **** */
if (sessionStorage.getItem(sess_q_ans)) {
sessionStorage.removeItem(sess_q_ans);
exec_q_ans();
} // if (sessionStorage.getItem(sess_q_ans))
if (sessionStorage.getItem(szDataKeyName + nTempStorageId)) {
exec_check_temp_data_change();
} // if (sessionStorage.getItem(szDataKeyName + nTempStorageId))
if (sessionStorage.getItem(sess_settings)) {
sessionStorage.removeItem(sess_settings);
exec_showSettingsPanel();
} // if (sessionStorage.getItem(sess_settings))
if (sessionStorage.getItem(sess_autofill)) {
sessionStorage.removeItem(sess_autofill);
exec_autofill();
} // if (sessionStorage.getItem(sess_autofill))
if (sessionStorage.getItem(sess_shwtimer)) {
exec_showtimer();
} // if (sessionStorage.getItem(sess_shwtimer))
/* **** [END] 储存检测 **** */
/* **** [BEGIN] 功能逻辑 **** */
function exec_q_ans() {
let t_edit = document.createElement('div');
t_edit.innerHTML = `
<div data-title>
<span>编辑器</span>
<button class=h>-</button><button class=x>x</button>
</div>
<hr data-hr1 />
<div data-container></div>
`;
t_edit.classList.add(mytedit_classn);
t_edit.classList.add(mydlg_classn);
let hideb = t_edit.querySelector('button.h');
if (hideb) {
hideb.setAttribute('style', 'position:absolute;right:30px');
hideb.onclick = function () {
this.parentElement.parentElement.style.display = 'none';
let el = document.createElement('button');
el.innerHTML = '编辑器';
el.setAttribute('style', `position:fixed;z-index:1048572;` +
`left:2px;bottom:2px;background:white;`);
root.append(el);
el.onclick = function () {
hideb.parentElement.parentElement.style.display = '';
this.remove();
};
}
} // if (hideb)
let x = t_edit.querySelector('button.x');
if (x) x.onclick = e => location.reload();
root.append(t_edit);
let uanswers = {};
let saveChanges = function (forever = true) {
let obj = sessionStorage;
let nAvailableStorageId2 = nAvailableStorageId;
if (forever) {
obj = localStorage;
} else {
nAvailableStorageId2 = nTempStorageId;
}
let u2 = obj.getItem(szDataKeyName + nAvailableStorageId2) || '{}';
try { u2 = JSON.parse(u2) }
catch (err) { u2 = {} };
let o3 = u2[location.pathname] || {};
for (let i in uanswers) {
o3[i] = uanswers[i];
}
u2[location.pathname] = o3;
obj.setItem(szDataKeyName + nAvailableStorageId2, JSON.stringify(u2));
} // let saveChanges = function (forever = true)
let container = t_edit.querySelector('div[data-container]');
if (container) {
container.style.maxHeight = myCalcDlgMaxHeight(t_edit);
let div_goto = document.createElement('div');
div_goto.innerHTML = `
<b>转到:</b><span> </span>
<input type="number" min="0" placeholder="输入 0 转到完成页面" />
<button data-go>转到</button>
`;
div_goto.style.textAlign = 'left';
container.append(div_goto);
let container2 = document.createElement('div');
container.append(container2);
let input1 = document.createElement('input');
input1.type = 'text';
input1.placeholder = 'Input operation code';
input1.style.display = 'block';
input1.style.marginTop = '20px';
container.append(input1);
let last_id = -1;
let qs = document.querySelectorAll('.div_question');
let NextQuestion = null;
let _tmp_t_type = '';
let _tmp_uanswer = '';
let ranswers = null;
{
let data = localStorage.getItem(szDataKeyName + nAvailableStorageId);
if (data) {
try {
data = JSON.parse(data)[location.pathname];
if (data) ranswers = data;
}
catch (err) { }
}
}
let btn_goto = div_goto.querySelector('button[data-go]');
if (btn_goto) {
btn_goto.style.border = '1px solid #000';
btn_goto.style.display = 'inline';
btn_goto.style.width = 'auto';
btn_goto.style.marginTop = '0';
btn_goto.onclick = function () {
var inp = this.parentElement.querySelector('input');
if (!inp) return;
last_id = inp.value - 2;
NextQuestion();
}
}
let inputhandler = function (ev) {
let dcs = container.querySelectorAll('button[data-code]');
if (dcs.length > 9) return; // 多于9个选项,跳过
let _btn1 = container.querySelector(
'button[data-code="' + this.value.toUpperCase() + '"]'
);
if (_btn1) {
this.value = '';
return _btn1.click();
}
}
let inputhandler_kd = function (ev) {
try {
if (ev.keyCode == 13) {
if (this.value == '') {
let a = container.querySelector('button[data-ok]');
if (a) a.click();
return;
}
let _btn1 = container.querySelector(
'button[data-code="' + this.value.toUpperCase() + '"]'
);
if (_btn1) {
this.value = '';
return _btn1.click();
}
return;
}
}
catch (err) {
console.warn('Error processing keydown:', err);
}
}
input1.onkeydown = inputhandler_kd;
input1.oninput = inputhandler;
let qs_did = {};
let handler_func = function (resolve, reject) {
if (!qs) reject(new Error('Cannot find questions'));
++last_id;
if (!qs[last_id]) {
// 做完了
//console.log(uanswers);
container2.innerHTML = `
<div><button data-c data-code="C">检查答案</button></div>
<div><button data-s data-code="S">保存并继续</button></div>
<div><button data-x data-code="X">保存并关闭</button></div>
<div><button data-g data-code="G">放弃更改</button></div>
<div><button data-b data-code="B">上一题</button></div>
`;
let
btn1 = container.querySelector('button[data-c]'),
btn2 = container.querySelector('button[data-s]'),
btn3 = container.querySelector('button[data-x]'),
btn4 = container.querySelector('button[data-g]'),
btn5 = container.querySelector('button[data-b]');
if (btn1) {
btn1.onclick = function () {
let subm =
document.getElementById('submit_button') ||
document.querySelector('.submitbutton');
if (!subm) {
this.innerHTML = '无法检查答案。请手动点击提交';
return;
}
sessionStorage.setItem(sess_lastpage, location.pathname);
saveChanges(false);
scrollToBottom();
DelayExecute(1000).then(() => {
subm.click();
btn1.disabled = true;
});
};
}
if (btn2) {
btn2.onclick = _ => {
saveChanges();
sessionStorage.setItem(sess_q_ans, '1');
location.reload();
};
}
if (btn3) {
btn3.onclick = _ => {
saveChanges();
location.reload();
};
}
if (btn4) {
btn4.onclick = _ => {
location.reload();
};
}
if (btn5) {
btn5.onclick = _ => {
last_id -= 2;
if (last_id < -1) last_id = -1;
NextQuestion();
};
}
return resolve(false);
}; // if (!qs[last_id])
let qtitle = qs[last_id].querySelector('.div_title_question');
if (!qtitle) reject('Cannot locate question title');
let text1 = qtitle.innerText;
container2.innerHTML = `
<div style="font-size: larger;">${last_id + 1}. <b>${text1}</b></div>
<div data-details></div>
<br />
<div><button data-next data-ok data-code="N">下一题</button></div>
<div><button data-back data-ok data-code="B">上一题</button></div>
`;
let btn = container2.querySelector('button[data-next]');
if (btn) {
btn.onclick = function () {
uanswers[text1] = _tmp_uanswer;
NextQuestion();
}
} // if (btn)
let btnb = container2.querySelector('button[data-back]');
if (btnb) {
btnb.onclick = function () {
last_id -= 2;
if (last_id < -1) last_id = -1;
NextQuestion();
}
} // if (btnb)
input1.focus();
let dets = container2.querySelector('div[data-details]');
if (dets) {
dets.style.textAlign = 'left';
let div1 = document.createElement('div');
let div2 = document.createElement('div');
let div3 = document.createElement('div');
dets.append(div1);
dets.append(div2);
dets.append(div3);
div1.style.color = 'red';
div1.innerHTML = '类型: <b></b>';
let b1 = div1.querySelector('b');
try {
if (qtitle.parentElement.parentElement
.querySelector('textarea') ||
qtitle.parentElement.parentElement
.querySelector('input[type="text"]')) {
b1.innerHTML = '填空题';
_tmp_t_type = 'fl'; // fill blank
}
else if (qtitle.parentElement.parentElement
.querySelector('input[type="radio"]')) {
b1.innerHTML = '单选题';
_tmp_t_type = 'oc'; // one choice
}
else if (qtitle.parentElement.parentElement
.querySelector('input[type="checkbox"]')) {
b1.innerHTML = '多选题';
_tmp_t_type = 'mc'; // multi choice
}
} // try
catch (err) {
console.warn('Error while processing type:', err);
} // try {...} catch (err)
_tmp_uanswer = uanswers[text1];
if (_tmp_t_type == 'fl') {
// 填空
let i1 = document.createElement('input');
i1.type = 'text';
i1.placeholder = '输入答案, 然后按 Enter';
i1.style.marginTop = '3px';
i1.style.fontSize = 'larger';
i1.style.width = container2.clientWidth - 5 + 'px';
i1.myelement =
qtitle.parentElement.parentElement
.querySelector('textarea') ||
qtitle.parentElement.parentElement
.querySelector('input[type="text"]');
i1.oninput = function () {
_tmp_uanswer = this.myelement.value = this.value;
};
i1.onkeydown = function (ev) {
if (ev.keyCode == 13) {
_tmp_uanswer = this.value;
container.querySelector('button[data-ok]').click();
this.myelement.value = this.value;
}
};
if (ranswers && (!qs_did[last_id])) {
if (ranswers[text1]) {
_tmp_uanswer = i1.myelement.value =
i1.value = ranswers[text1];
qs_did[last_id] = true;
}
}
if (_tmp_uanswer) {
i1.value = _tmp_uanswer;
}
div2.append(i1);
i1.focus();
} // if (_tmp_t_type == 'fl')
else if (_tmp_t_type == 'oc' || _tmp_t_type == 'mc') {
// 获取选项
let ops;
if (_tmp_t_type == 'oc') {
ops = qtitle.parentElement.parentElement
.querySelectorAll('input[type="radio"]');
} else {
ops = qtitle.parentElement.parentElement
.querySelectorAll('input[type="checkbox"]');
}
if (ops) {
for (let i in ops) {
// 遍历选项
let j = document.createElement('button');
// j.style.background = 'white';
j.classList.add(bgwhite_classn);
j.classList.add(myhovbn_classn);
div2.append(j);
try {
j.innerText = ops[i]
.parentElement
.querySelector('label')
.innerText;
j.setAttribute('data-code', parseInt(i) + 1);
} // try
catch (err) {
j.remove();
continue;
} // try {...} catch (err)
if (j.innerText.length >= 2 &&
/[A-Z]/.test(j.innerText.substring(0, 1)) &&
j.innerText.substring(1, 2) == '.') {
j.innerText = j.innerText.substring(2);
}
if (_tmp_uanswer) { // 恢复 上一题
if (_tmp_t_type == 'oc') { // 单选
if (_tmp_uanswer == j.innerText) {
j.classList.add(mybnchecked_classn);
ops[i].click();
}
}
else if (_tmp_uanswer[j.innerText]) { // 多选
j.classList.add(mybnchecked_classn);
j._checked = true;
let el = ops[i]
.parentElement
.querySelector('label');
let jq = ops[i]
.parentElement
.querySelector('.jqChecked');
if (el && (!jq)) { el.click(); }
}
}
if (_tmp_t_type == 'oc') {
// 单选的处理
j.myelement = ops[i];
j.onclick = function () {
let k =
this.parentElement
.querySelectorAll('button[data-code]');
if (k) {
for (let l of k) {
l.classList.remove(mybnchecked_classn);
}
}
this.classList.add(mybnchecked_classn);
this.myelement.click();
_tmp_uanswer = this.innerText;
}
if (ranswers) {
// 以用户新的答案为准
if (ranswers[text1] == j.innerText && (!uanswers[text1])) {
j.classList.add(mybnchecked_classn);
if (!ops[i].parentElement.querySelector('.jqChecked')) {
j.myelement.click(); // 没有选中时把它选中
}
_tmp_uanswer = j.innerText;
qs_did[last_id] = true;
}
}
} else {
// 多选的处理
j.myelement = ops[i].parentElement.querySelector('label');
j.onclick = function () {
_tmp_uanswer = _tmp_uanswer || {};
this._checked = !this._checked;
this.classList[this._checked ? 'add' : 'remove']
(mybnchecked_classn);
this._checked ?
_tmp_uanswer[this.innerText] = 1 :
delete _tmp_uanswer[this.innerText];
if (this.myelement) {
let jqChecked = this
.myelement
.parentElement
.querySelector('.jqChecked');
if ((!this._checked) && jqChecked) {
this.myelement.click();
}
if (this._checked && (!jqChecked)) {
this.myelement.click();
}
}
} // j.onclick
if (ranswers) {
// 以用户新的答案为准
if (ranswers[text1] && (!uanswers[text1])) {
if (ranswers[text1][j.innerText]) {
qs_did[last_id] = true;
_tmp_uanswer = _tmp_uanswer || {};
_tmp_uanswer[j.innerText] = 1;
j.classList.add(mybnchecked_classn);
j._checked = true;
let jqChecked = ops[i]
.parentElement
.querySelector('.jqChecked');
if (j.myelement && (!jqChecked)) {
j.myelement.click();
}
}
}
} // if (ranswers)
} // if (_tmp_t_type == 'oc') {...} else
} // for (let i in ops)
} // if (ops)
} // else if (_tmp_t_type == 'oc' || _tmp_t_type == 'mc')
} // if (dets)
return resolve(true);
}; // let handler_func = function (resolve, reject)
let err_func = function (e) {
console.error(e);
container2.innerHTML = `<div style="color:red">
无法载入数据。 请尝试
<button data-d="retry">重试</button>
或
<button data-d="reload">重新加载页面</button>
。</div>
<div>调试信息: ${e}</div>`;
let btn1 = container2.querySelector('[data-d="retry"]'),
btn2 = container2.querySelector('[data-d="reload"]');
if (btn1 && btn2) {
btn1.onclick = function () {
--last_id;
NextQuestion();
}
btn2.onclick = function () {
sessionStorage.setItem('${sess_q_ans}', '1');
location.reload();
}
}
}; // let err_func
NextQuestion = function () {
return new Promise(handler_func).then(v => { }, err_func);
};
NextQuestion();
} // if (container)
} // function exec_q_ans()
function exec_check_temp_data_change() {
try {
let szLastPage = sessionStorage.getItem(sess_lastpage)
|| location.pathname;
let uanswers = JSON.parse(
sessionStorage.getItem(
szDataKeyName + nTempStorageId
)
)[szLastPage] || {};
//console.log(uanswers);
let confbox = document.createElement('div');
let _ss = {
position: 'fixed',
right: '10px', bottom: '10px',
border: '1px solid black',
zIndex: 1048572,
background: 'white',
textAlign: 'center',
fontSize: '14px',
};
for (let i in _ss) {
confbox.style[i] = _ss[i];
}
confbox.classList.add(mydlg_classn);
confbox.innerHTML = `
<b style="display: block;">是否保存您所做的更改?</b>
<button data-s style="display: block;">保存</button>
<button data-d style="display: block;">详细信息</button>
<button data-g style="display: block;">放弃</button>
`;
root.append(confbox);
let s = confbox.querySelector('[data-s]'),
d = confbox.querySelector('[data-d]'),
g = confbox.querySelector('[data-g]');
if (s && d && g) {
g.onclick = function () {
sessionStorage.removeItem(sess_lastpage);
sessionStorage.removeItem(szDataKeyName + nTempStorageId);
location.reload();
}
s.onclick = function () {
let kn = szLastPage.replace(
nAvailableStorageId_regexp, '_');
let u2 = localStorage.getItem(
szDataKeyName + kn
) || '{}';
try { u2 = JSON.parse(u2) }
catch (err) { u2 = {} };
let o3 = u2[szLastPage] || {};
for (let i in uanswers) {
o3[i] = uanswers[i];
}
u2[szLastPage] = o3;
localStorage.setItem(
szDataKeyName + kn,
JSON.stringify(u2));
g.click();
}
d.onclick = function () {
let el = document.createElement('div');
this.disabled = !!el;
root.append(el);
el.classList.add(mydlg_classn);
el.classList.add(mytedit_classn);
el.innerHTML = `
您的数据:<br>
<textarea rows=8></textarea><br>
错题:<br>
<div data-wrongs>
</div>
`;
let ta/*textarea*/ = el.querySelector('textarea'),
wr = el.querySelector('[data-wrongs]');
ta.value = sessionStorage.getItem(
szDataKeyName + nTempStorageId);
ta.style.width = el.clientWidth - 5 + 'px';
}
}
}
catch (err) {
console.warn('Invalid data found in sessionStorage.');
}
} // function exec_check_temp_data_change()
function exec_showSettingsPanel() {
let setp = document.createElement('div');
setp.classList.add(mysett_classn);
setp.classList.add(mydlg_classn);
setp.innerHTML = `
<div data-title>
<span>设 置</span>
<button class=h>-</button><button class=x>x</button>
</div>
<hr data-hr1 />
<div data-container></div>
`;
root.append(setp);
let hideb = setp.querySelector('button.h');
if (hideb) {
hideb.setAttribute('style', 'position:absolute;right:30px');
hideb.onclick = function () {
this.parentElement.parentElement.style.display = 'none';
let el = document.createElement('button');
el.innerHTML = '设置窗口';
el.setAttribute('style', `position:fixed;z-index:1048572;` +
`left:2px;bottom:2px;background:white;`);
root.append(el);
el.onclick = function () {
hideb.parentElement.parentElement.style.display = '';
this.remove();
};
}
} // if (hideb)
let x = setp.querySelector('button.x');
if (x) x.onclick = () => location.reload();
let container = setp.querySelector('div[data-container]');
if (container) {
container.style.maxHeight = myCalcDlgMaxHeight(setp);
container.style.textAlign = 'left';
container.innerHTML = `
<style>
.${mysett_classn} [data-panel] {
border: 1px solid #cccccc;
padding: 5px 5px;
margin-bottom: 20px;
}
/*.${mysett_classn} [data-panel] b {
position: absolute;
left: 10px;
}*/
</style>
<div data-panel>
<div><b>通用</b></div>
<hr />
<div>TODO</div>
</div>
<div data-panel>
<div><b>数据</b></div>
<hr />
<div>
<div>
<span>当前保存的数据:</span>
<select data-select1></select>
<button data-exportdata>导出数据</button>
<button data-importdata>导入数据</button>
<br />
<button data-deletedata disabled>删除数据</button>
<button data-deletedatas>删除所有</button>
<button data-savedata disabled>保存更改</button>
<button data-format disabled>
<span>格式化 空格数量</span>
<input type=number min=0 max=10 value=4 />
</button>
</div>
<div>
<textarea data-saveddata rows=8></textarea>
</div>
<br />
</div>
</div>
<div style="text-align: right;">
<button data-s>保存</button>
<button data-c>取消</button>
</div>
`;
let saveddata = container.querySelector('textarea[data-saveddata]'),
select1 = container.querySelector('select[data-select1]'),
btn_savedata = container.querySelector('button[data-savedata]'),
btn_formatdata = container.querySelector('button[data-format]'),
btn_exportdata = container.querySelector('button[data-exportdata]'),
btn_importdata = container.querySelector('button[data-importdata]'),
btn_save = container.querySelector('button[data-s]'),
btn_close = container.querySelector('button[data-c]'),
btn_deleted = container.querySelector('button[data-deletedata]'),
btn_deleteds = container.querySelector('button[data-deletedatas]'),
lcsDataNames = [];
if (btn_save) {
btn_save.onclick = function () {
if (btn_savedata) btn_savedata.click();
if (btn_close) btn_close.click();
}
} // if (btn_save)
if (btn_close) {
btn_close.onclick = () => location.reload();
} // if (btn_close)
if (btn_deleteds) {
btn_deleteds.onclick = function () {
if (!confirm("确定删除保存的数据?")) return false;
for (let i in localStorage) {
if (i.indexOf(szDataKeyName) == 0) {
localStorage.removeItem(i);
}
}
sessionStorage.setItem(sess_settings, '1');
location.reload();
}
} // if (btn_deleteds)
if (btn_exportdata) {
btn_exportdata.onclick = function () {
let el = document.createElement('div');
el.classList.add(mydlg_classn);
el.classList.add(mytedit_classn);
el.innerHTML = `
<div data-title>
<span>导出数据</span>
</div>
<hr data-hr1 />
<div data-container style="display: flex; flex-direction: column;">
<p>将以下数据保存到您的计算机。</p>
<textarea></textarea>
<p><button data-d>下载</button></p>
<p><button data-c>复制</button></p>
<p><button data-x>关闭</button></p>
</div>
`;
root.append(el);
let container = el.querySelector('[data-container]');
let ta = el.querySelector('textarea');
let dl = el.querySelector('button[data-d]');
let cl = el.querySelector('button[data-x]');
let cp = el.querySelector('button[data-c]');
let obj = {};
container.style.maxHeight = myCalcDlgMaxHeight(el);
for (let i in localStorage) {
if (i.indexOf(szDataKeyName) == 0) {
obj[i] = localStorage[i];
}
}
ta.value = JSON.stringify(obj);
ta.readOnly = true;
ta.style.width = el.clientWidth - 5 + 'px';
ta.style.flexBasis = el.clientHeight + 'px';
cl.onclick = function () {
el.remove();
}
cp.onclick = function () {
let errhand = function (err) {
let oldInner = cp.innerHTML;
cp.disabled = true;
cp.innerHTML = '<span style="color:red">' +
'复制失败 (<span data-reason></span>)</span>';
setTimeout(() => {
cp.disabled = false;
cp.innerHTML = oldInner;
}, 2000);
let span = cp.querySelector('span[data-reason]');
if (span) {
span.innerText = String(err);
}
}
try {
navigator.clipboard.writeText(ta.value)
.then(function () {
let oldInner = cp.innerHTML;
cp.disabled = true;
cp.innerHTML = '复制成功';
setTimeout(() => {
cp.disabled = false;
cp.innerHTML = oldInner;
}, 1000);
}, function (error) {
errhand(error);
})
}
catch (err) {
errhand(err);
}
}
dl.onclick = function () {
let blob = new Blob([ta.value]);
let link = document.createElement('a');
link.download = new Date().toString() + '.txt';
link.href = URL.createObjectURL(blob);
link.click();
//URL.revokeObjectURL(link.href);
}
} // btn_exportdata.onclick
} // if (btn_exportdata)
if (btn_importdata) {
btn_importdata.onclick = function () {
let el = document.createElement('div');
el.classList.add(mydlg_classn);
el.classList.add(mytedit_classn);
el.innerHTML = `
<div data-title>
<span>导入数据</span>
</div>
<hr data-hr1 />
<div data-container style="display: flex; flex-direction: column;">
<p>输入要导入的数据:</p>
<textarea></textarea>
<button data-i>导入</button>
<button data-x>取消</button>
</div>
`;
root.append(el);
let container = el.querySelector('[data-container]');
let ta = el.querySelector('textarea');
let cl = el.querySelector('button[data-x]');
let im = el.querySelector('button[data-i]');
container.style.maxHeight = myCalcDlgMaxHeight(el);
ta.style.width = el.clientWidth - 5 + 'px';
ta.style.flexBasis = el.clientHeight + 'px';
cl.onclick = function () {
el.remove();
}
im.onclick = function () {
if (!confirm('确定导入以下数据?\n' +
'如果现有数据与以下数据重复,现有数据将被覆盖。\n' +
'恶意数据可能损害您的答题结果!\n' +
'\n确定继续吗?'
)) return;
this.disabled = true;
let i = this.parentElement.querySelector('textarea');
let obj = {};
try {
obj = JSON.parse(i.value);
}
catch (err) {
let oldInner = this.innerHTML;
this.innerHTML = '<span style="color:red">数据无效</span>';
this.disabled = true;
setTimeout(() => {
this.innerHTML = oldInner;
this.disabled = false;
}, 1000);
return;
}
/* obj example:
{
"__wjx_autofill_datas_parttest1":
"{\"test1\":{\"1\":\"B\",\"2\":\"C\"}}"
}
*/
let old = {};
for (let i in localStorage) {
try {
if (i.indexOf(szDataKeyName) == 0) {
old[i] = JSON.parse(localStorage[i]);
}
}
catch (e) { continue; }
}
/* old example:
{"__prefix_test1":{"test1":{"a":"b"}}}
unlucky example:
{"__prefix_test1":123}
*/
for (let j in obj) {
// j example: "__wjx_autofill_datas_parttest1"
try {
let str2 = j;
if (typeof (old[str2]) != 'object') {
old[str2] = {};
}
let dat = null;
try {
dat = JSON.parse(obj[j]);
}
catch (err) {
continue;
}
if (!dat) continue;
// console.log(dat);
/* obj example:
{
"__wjx_autofill_datas_parttest1":
"{\"test1\":{\"1\":\"B\",\"2\":\"C\"}}"
}
dat example:
{"test1":{"1":"B","2":"C"}}
old example:
{"__prefix_test1":{"test1":{"a":"b"}}}
str2 example:
"__prefix_test1"
*/
for (let kn in dat) {
// kn example: "test1"
try {
for (let k in dat[kn]) {
if (typeof (old[str2][kn]) != 'object') {
old[str2][kn] = {};
}
old[str2][kn][k] = dat[kn][k];
}
}
catch (err) {
continue;
}
}
let str = JSON.stringify(old[str2]);
console.log(str2, '\n', str, '\n', old[str2]);
localStorage.setItem(str2, str);
} // try
catch (err) {
console.warn(err);
continue;
}
}
el.remove();
sessionStorage.setItem(sess_settings, '1');
// if(!window.debugging)
location.reload();
} // im.onclick
} /* btn_importdata.onclick */
} // if (btn_importdata)
if (select1) {
for (let i in localStorage) {
if (i.indexOf(szDataKeyName) == 0) {
lcsDataNames.push(i);
}
}
if (lcsDataNames.length == 0) {
select1.innerHTML = `<option>未存储任何数据</option>`;
if (btn_deleteds) btn_deleteds.disabled = true;
}
else {
select1.innerHTML = `<option>请选择</option>`;
for (let i of lcsDataNames) {
let j = document.createElement('option');
j.innerText = j.value = i.replace(szDataKeyName, '');
select1.append(j);
}
}
{
let j = document.createElement('option');
j.innerText = '新建...'; j.value = 'Data_New';
select1.append(j);
}
select1.onchange = function () {
saveddata.setAttribute('rows', '8');
if (btn_deleted) btn_deleted.disabled = false;
if (btn_formatdata) btn_formatdata.disabled = false;
saveddata.oninput = () => btn_savedata.disabled = false;
if (this.value == 'Data_New') {
let el2 = document.createElement('input');
el2.type = 'text';
el2.placeholder = 'Data name';
select1.replaceWith(el2);
select1.remove();
select1 = el2;
saveddata.value = '';
return;
}
saveddata.value = localStorage.getItem(
szDataKeyName + this.value
) || ((function () {
saveddata.setAttribute('rows', '1');
if (btn_deleted) btn_deleted.disabled = true;
if (btn_savedata) btn_savedata.disabled = true;
if (btn_formatdata) btn_formatdata.disabled = true;
saveddata.oninput = null;
return '未存储任何数据';
})());
} // select1.onchange
} // if (select1)
if (saveddata) {
saveddata.style.fontFamily = 'Consolas, sans-serif';
saveddata.style.width = container.clientWidth - 5 + 'px';
saveddata.value = lcsDataNames.length ? '请选择' : '未存储任何数据';
if (btn_savedata) {
btn_savedata.onclick = function () {
try {
if (select1.value == '') {
this.disabled = true;
this.innerHTML = '<span style="color:red">数据名无效</span>';
setTimeout(function () {
this.disabled = false;
btn_savedata.innerHTML = '保存更改';
}, 1000);
return;
}
JSON.parse(saveddata.value);
localStorage.setItem(
szDataKeyName + select1.value,
saveddata.value);
sessionStorage.setItem(sess_settings, '1');
location.reload();
}
catch (err) {
this.disabled = true;
this.innerHTML = '<span style="color:red">数据无效</span>';
setTimeout(function () {
btn_savedata.innerHTML = '保存更改';
}, 1000);
}
}
}
if (btn_deleted) {
btn_deleted.onclick = function () {
if (!confirm(`确定删除 ${select1.value}?`)) return false;
localStorage.removeItem(szDataKeyName + select1.value);
sessionStorage.setItem(sess_settings, '1');
location.reload();
}
}
if (btn_formatdata) {
btn_formatdata.onclick = function () {
let se = this.querySelector('input');
let sc = 4;
se ? sc = Number(se.value) : 0;
try {
saveddata.value = JSON.stringify(
JSON.parse(saveddata.value),
null, sc);
}
catch (err) {
this.disabled = true;
let oldInner = this.innerHTML;
this.innerHTML = '<span style="color:red">数据无效</span>';
setTimeout(function () {
btn_formatdata.innerHTML = oldInner;
btn_formatdata.disabled = false;
}, 1000);
}
} // btn_formatdata.onclick
} // if (btn_formatdata)
} // if (saveddata)
} // if (container)
} // function exec_showSettingsPanel()
function exec_autofill() {
let onerror = function (err) {
let div = document.createElement('div');
div.classList.add(mytedit_classn);
div.classList.add(mydlg_classn);
div.innerHTML = `
<div data-title>无法自动填写</div>
<hr />
<div>
<div style="color: red;"><b>发生了一个错误,导致无法自动填写。</b></div>
<p>
<b style="display: block;">错误详情:</b><br />
<div data-d style="border: 1px solid #aaa;"></div>
</p>
<div data-container>
<button data-r style="display: block;">重试</button>
<button data-g style="display: block;">放弃</button>
</div>
</div>
`;
root.append(div);
div.querySelector('[data-r]').onclick = function () {
sessionStorage.setItem(sess_autofill, '1');
location.reload();
}
div.querySelector('[data-g]').onclick =
() => location.reload();
div.querySelector('[data-d]').innerText = err;
}; // let onerror
let myreport = function (nTotal, nOk) {
let div = document.createElement('div');
div.classList.add(mytedit_classn);
div.classList.add(mydlg_classn);
div.innerHTML = `
<div data-title>操作完成</div>
<hr />
<div>
<div><b>操作已完成。</b></div>
<p>
<b style="display: block;">详情:</b><br />
<div style="border: 1px solid #aaa;">
<div>总计 <b>${nTotal}</b> 个</div>
<div>成功 <b>${nOk}</b> 个</div>
<div>失败 <b>${nTotal - nOk}</b> 个</div>
</div>
</p>
<div data-container>
<button data-s style="display: block;">提交</button>
<button data-c style="display: block;">关闭</button>
</div>
</div>
`;
root.append(div);
div.querySelector('[data-s]').onclick = function () {
let subm =
document.getElementById('submit_button') ||
document.querySelector('.submitbutton');
if (!subm) {
this.innerHTML = '无法自动提交。请手动点击提交';
return;
}
scrollToBottom();
DelayExecute(100).then(function () {
subm.click();
div.remove();
});
}
div.querySelector('[data-c]').onclick = function () {
div.remove();
}
} // let myreport
new Promise(function (resolve, reject) {
let data = localStorage.getItem(szDataKeyName + nAvailableStorageId);
if (!data) reject('数据错误: 数据不存在');
try {
data = JSON.parse(data)[location.pathname];
if (!data) reject('数据错误: 找不到数据')
return resolve(data);
}
catch (err) {
reject('数据错误: 无法解析数据');
}
}) // new Promise
.then(function (data) {
// let successful_count = 0;
let last_id = -1;
let qs = document.querySelectorAll('.div_question');
let NextQuestion = null;
let handler_func = function (resolve, reject) {
if (!qs) reject('找不到问题');
++last_id;
if (!qs[last_id]) {
// 做完了
let successful_count = 0;
// 计算成功数量,这里不能在做的时候计算,否则有bug
// 原因:多选题有多个元素是 .jqChecked
for (let i of qs) {
let el = null;
el = i.querySelector('textarea') ||
i.querySelector('input[type="text"]');
if (el) {
if (el.value != '') {
successful_count++;
}
continue;
}
el = i.querySelectorAll('input[type="radio"]');
if (el.length == 0) {
el = i.querySelectorAll('input[type="checkbox"]');
}
// console.log('Element: ', i, '\nElements: ', el);
if (el) {
for (let j of el) {
if (j.parentElement.querySelector('.jqChecked')) {
successful_count++;
break;
}
continue;
}
}
}
myreport(qs.length, successful_count);
return resolve(false);
};
let qtitle = qs[last_id].querySelector('.div_title_question');
if (!qtitle) reject('Cannot locate question title');
let text1 = qtitle.innerText;
let answer = data[text1];
//console.log(text1, ':', answer);
if (!answer) {
NextQuestion();
return resolve(2);
}
let _tmp_t_type = '';
try {
if (qtitle.parentElement.parentElement
.querySelector('textarea') ||
qtitle.parentElement.parentElement
.querySelector('input[type="text"]')) {
_tmp_t_type = 'fl'; // fill blank
}
else if (qtitle.parentElement.parentElement
.querySelector('input[type="radio"]')) {
_tmp_t_type = 'oc'; // one choice
}
else if (qtitle.parentElement.parentElement
.querySelector('input[type="checkbox"]')) {
_tmp_t_type = 'mc'; // multi choice
}
}
catch (err) {
console.warn('Error while processing type:', err);
}
if (_tmp_t_type == 'fl') {
// 填空
(qtitle.parentElement.parentElement
.querySelector('textarea') ||
qtitle.parentElement.parentElement
.querySelector('input[type="text"]'))
.value = answer;
// successful_count++;
}
else if (_tmp_t_type == 'oc' || _tmp_t_type == 'mc') {
do {
// 获取选项
let ops;
if (_tmp_t_type == 'oc') {
ops = qtitle.parentElement.parentElement
.querySelectorAll('input[type="radio"]');
} else {
ops = qtitle.parentElement.parentElement
.querySelectorAll('input[type="checkbox"]');
}
if (!ops) break;
for (let i in ops) {
// 遍历选项
let text2 = '';
try {
text2 = ops[i]
.parentElement
.querySelector('label')
.innerText;
if (text2.length >= 2 &&
/[A-Z]/.test(text2.substring(0, 1)) &&
text2.substring(1, 2) == '.') {
text2 = text2.substring(2);
}
if (
(_tmp_t_type == 'oc' && text2 != answer)
||
(_tmp_t_type == 'mc' && (!(answer[text2])))
) {
continue;
}
}
catch (err) {
continue;
}
if (_tmp_t_type == 'oc') {
// 单选的处理
ops[i].click();
// successful_count++;
} else {
// 多选的处理
let myelement =
ops[i].parentElement.querySelector('label');
if (myelement) {
myelement.click();
// successful_count++;
}
}
}
} while (0);
}
NextQuestion();
return resolve(true);
};
NextQuestion = function () {
return new Promise(handler_func).then(v => { }, onerror);
}
NextQuestion();
// data
}, onerror) // new Promise(...).then
} // function exec_autofill()
function exec_showtimer() {
if (root.querySelector('.' + mytimer_classn)) {
return root.querySelector('.' + mytimer_classn).remove();
}
let el = document.createElement('div');
el.classList.add(mytimer_classn);
el.innerHTML = `
<div data-title>
<button class=x>x</button>
</div>
<hr />
<div data-container>
<div>
<span class=h></span>
<span>:</span>
<span class=m></span>
<span>:</span>
<span class=s></span>
</div>
<!--div>
<button>暂停所有计时器</button>
</div-->
</div>
`;
root.append(el);
let
x = el.querySelector('.x'),
h = el.querySelector('.h'),
m = el.querySelector('.m'),
s = el.querySelector('.s');
let timeBegin = new Date();
let intervalId = setInterval(function () {
let timeNow = (new Date() - timeBegin) / 1000;
s.innerText = Math.floor(timeNow % 60);
m.innerText = Math.floor(timeNow % (60*60) / 60);
h.innerText = Math.floor(timeNow / (60*60));
}, 1000);
x.onclick = function () {
sessionStorage.removeItem(sess_shwtimer);
clearInterval(intervalId);
el.remove();
};
} // function exec_showtimer()
function showAllQuestions() {
let style2 = document.createElement('style');
style2.innerHTML = `
fieldset.fieldset,
#submit_button {
display: block !important;
}
`;
root.append(style2);
let submit_table = document.getElementById('submit_table');
if (submit_table) submit_table.style.display = '';
} // function showAllQuestions()
/* **** [END] 功能逻辑 **** */
/* **** [BEGIN] 辅助功能 **** */
function randstr(len = 1, text = null) {
var t = text || ("0123456789abcdef" +
"ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
a = t.length,
n = "";
for (let i = 0; i < len; i++) {
n += t.charAt(Math.floor(Math.random() * a));
}
return n;
} // function randstr
function myCalcDlgMaxHeight (dlg_element) {
let _heig = 0;
let _title = dlg_element.querySelector('div[data-title]');
if (_title) {
_heig += _title.offsetHeight;
}
let _hr1 = dlg_element.querySelector('hr[data-hr1]');
if (_hr1) {
_heig += _hr1.offsetHeight;
}
{ _heig += 22; }
return dlg_element.clientHeight - _heig + 'px';
} // function myCalcDlgMaxHeight
function scrollToBottom() {
return window.scroll({
behavior: 'smooth',
top: (document.body || document.documentElement).scrollHeight
});
} // function scrollToBottom()
function DelayExecute(timeout = 0) {
return new Promise(resolve => setTimeout(resolve, timeout));
} // function DelayExecute(timeout = 0)
/* **** [END] 辅助功能 **** */
/* **** [END] Script **** */
return 0;
}
if (document.readyState == 'loading') {
window.addEventListener('DOMContentLoaded', DCL);
} else {
DCL();
}
})();