Timer freezing; Text test form support

This commit is contained in:
Egor Guslyancev 2024-04-27 06:38:11 -03:00
parent ef1275e408
commit f4323c16b3
GPG key ID: D7E709AA465A55F9

430
user.js
View file

@ -2,7 +2,7 @@
// @name Sorryops
// @name:ru Сориупс
// @namespace https://git.disroot.org/electromagneticcyclone/sorryops
// @version 20240424.2
// @version 20240427.1
// @description Collect and reuse ORIOKS test answers
// @description:ru Скрипт для сбора и переиспользования ответов на тесты ОРИОКС
// @icon https://orioks.miet.ru/favicon.ico
@ -21,18 +21,23 @@
// @updateURL https://update.greasyfork.org/scripts/481036/Sorryops.meta.js
// ==/UserScript==
/* Labels */
var all_labels = {
en: {
l: "English",
settings_title: "Settings",
script_language: "Language",
auto_answer: "Auto answer",
auto_answer_no: "No",
auto_answer_first: "First",
auto_answer_random: "Random",
display_answer: "Display answer near variant",
stop_timer: "Freeze and hide timer",
register_keyboard_keys: "Register hotkeys",
copy_answers: "Copy results to the clipboard",
append_question_number: "Show question numbers in the final report",
accumulator_enable: "Accumulate test results in one field",
accumulator_prefix: "Accumulated results prefix (test number)",
auto_continue: "Auto continue (DANGEROUS!!! Will be disabled after an hour. Press `d` to disable)",
auto_restart: "Auto restart (DANGEROUS!!! Will be disabled after an hour. Press `d` to disable. Make sure you have infinite attempts)",
},
@ -40,13 +45,16 @@ var all_labels = {
l: "Русский",
settings_title: "Настройки",
script_language: "Язык",
auto_answer: "Автоответчик",
auto_answer: "Автовыбор ответа",
auto_answer_no: "Нет",
auto_answer_first: "Первый",
auto_answer_random: "Случайный",
display_answer: "Отображать ответ рядом с вариантом",
stop_timer: "Заморозить и скрыть таймер",
register_keyboard_keys: "Горячие клавиши",
copy_answers: "Копировать результаты в буфер обмена",
append_question_number: "Отображать номер вопроса в финальном отчёте",
accumulator_enable: "Собирать отчёты в одно поле",
accumulator_prefix: "Префикс перенесённого отчёта (номер теста)",
auto_continue: "Автопродолжение (ОПАСНО!!! Отключается через час. Нажмите `d`, чтобы остановить)",
auto_restart: "Автоперезапуск (ОПАСНО!!! Отключается через час. Нажмите `d`, чтобы остановить. Убедитесь, что количество попыток неограничено)",
},
@ -67,6 +75,10 @@ if (labels == undefined) {
labels = all_labels.ru;
}
/* End Labels */
/* Config */
var config = new GM_config({
id: 'config',
title: labels.settings_title,
@ -74,20 +86,33 @@ var config = new GM_config({
script_language: {
label: labels.script_language,
type: 'select',
options: [ '-', all_labels.en.l, all_labels.ru.l ],
options: [
'-',
all_labels.en.l,
all_labels.ru.l,
],
default: '-',
},
auto_answer: {
label: labels.auto_answer,
type: 'select',
options: [ 'No', 'First', 'Random' ],
default: 'No',
options: [
labels.auto_answer_no,
labels.auto_answer_first,
labels.auto_answer_random,
],
default: labels.auto_answer_no,
},
display_answer: {
label: labels.display_answer,
type: 'checkbox',
default: true,
},
stop_timer: {
label: labels.stop_timer,
type: 'checkbox',
default: true,
},
register_keyboard_keys: {
label: labels.register_keyboard_keys,
type: 'checkbox',
@ -108,11 +133,6 @@ var config = new GM_config({
type: 'checkbox',
default: false,
},
accumulator_prefix: {
label: labels.accumulator_prefix,
type: 'text',
default: "",
},
auto_continue: {
label: labels.auto_continue,
type: 'checkbox',
@ -134,6 +154,7 @@ var config = new GM_config({
},
events: {
init: function() {
GM_setValue('stop_timer', this.get('stop_timer'));
if (this.get('auto_continue') && (this.get('auto_answer') == "No")) {
this.set('auto_continue', false);
}
@ -164,20 +185,55 @@ var config = new GM_config({
},
});
var answers = [];
var variant, hash;
var testID = (() => {
var url = document.URL;
url = url.slice(url.indexOf("idKM=") + 5);
url = url.slice(0, url.indexOf("&"));
return url;
})();
GM_registerMenuCommand('Script Settings', () => {
GM_registerMenuCommand(labels.settings_title, () => {
config.open();
});
window.addEventListener('load', actionFunction);
/* End Config */
/* Server */
// Local
function S_setValue(field, value) {
var v = GM_getValue("server", value);
}
// Local
function S_getValue(field, default_value) {
var v = GM_getValue("server", default_value);
}
/* End Server */
/* Stop timer */
if (GM_getValue('stop_timer', true)) {
var i, pbox;
var pboxes = document.getElementsByTagName('p');
for (i = 0; i < pboxes.length; i++) {
pbox = pboxes[i];
if (pbox.textContent.includes("Осталось:")) {
pbox.parentNode.remove();
document.getElementsByTagName('hr')[0].remove();
var injectFakeTimer = function(window) {
window.setInterval = (f, t) => {
return window.setInterval(f, 10^999);
};
}
var scriptFakeTimer = document.createElement('script');
scriptFakeTimer.setAttribute("type", "application/javascript");
scriptFakeTimer.textContent = '(' + injectFakeTimer + ')(window);';
document.body.appendChild(scriptFakeTimer);
break;
}
}
}
/* End Stop timer */
/* Events */
window.addEventListener('load', main);
window.onkeydown = (e) => {
if ((e.key == "Enter") && config.get('register_keyboard_keys')) {
press_continue_btn();
@ -189,6 +245,24 @@ window.onkeydown = (e) => {
}
};
/* End Events */
/* Page properties */
// const success = -1487162948;
var answers = [];
var variant, hash, type;
var testID = (() => {
var url = document.URL;
url = url.slice(url.indexOf("idKM=") + 5);
url = url.slice(0, url.indexOf("&"));
return url;
})();
/* End properties */
/* Functions */
// https://stackoverflow.com/a/15710692
function hashCode(s) {
return s.split("").reduce(function(a, b) {
@ -197,138 +271,6 @@ function hashCode(s) {
}, 0);
}
function update_variant() {
var i, pbox;
var chosen_answer = "";
for (i = 0; i < answers.length; i++) {
chosen_answer += answers[i].checked ? answers[i].value : "";
}
chosen_answer = chosen_answer.split('').sort().join('');
var pboxes = document.getElementsByTagName('p');
const display_answer = config.get('display_answer');
for (i = 0; i < pboxes.length; i++) {
pbox = pboxes[i];
if (pbox.textContent.includes("Вопрос:")) {
pbox.innerHTML = "<i>(Вариант <input onfocus='this.select();' id='variant' value='" + hash + (display_answer == true ? (" " + chosen_answer) : "") + "' readonly>)</i><br>Вопрос:";
break;
}
}
var question_num = undefined;
for (i = 0; i < pboxes.length; i++) {
pbox = pboxes[i];
if (pbox.textContent.includes("Текущий вопрос: ")) {
question_num = pbox.textContent.slice(variant.indexOf("Текущий вопрос: ") + 16);
break;
}
}
var tests = GM_getValue('tests', new Object());
if (tests[testID] === undefined) {
tests[testID] = new Object();
}
tests[testID][hash] = [question_num, chosen_answer];
GM_setValue('tests', tests);
}
function test_form_handler() {
var i;
var objects = new Object();
var boxes = document.getElementsByTagName('input');
var form = document.getElementById('testform-answer');
for (i = 0; i < boxes.length; i++) {
if (boxes[i].type === 'checkbox' | boxes[i].type === 'radio') {
var span = document.createElement('span');
span.innerHTML =
boxes[i].type === 'radio' && boxes[i].value == "1"
? "<b>" + boxes[i].value + ")</b> "
: boxes[i].value + ") ";
boxes[i].parentNode.insertBefore(span, boxes[i]);
objects[boxes[i].value] = boxes[i];
}
}
const sorted_objects = Object.keys(objects).sort().reduce(
(obj, key) => {
obj[key] = objects[key];
return obj;
}, {}
);
for (var key in sorted_objects) {
sorted_objects[key].parentNode.remove();
form.appendChild(sorted_objects[key].parentNode);
answers.push(sorted_objects[key]);
}
const auto_answer = config.get('auto_answer');
var answer;
if (auto_answer == 'Random') {
if (answers[0].type === 'radio') {
var chosen_answer = Math.floor(Math.random() * answers.length);
answers[chosen_answer].click();
} else {
var pick = Math.floor(Math.random() * (Math.pow(2, answers.length) - 1)) + 1;
for (i = 0; i < answers.length; i++) {
if(pick & Math.pow(2, i)) {
answers[i].click();
}
}
}
} else if (auto_answer == 'First') {
answers[0].click();
}
variant = document.getElementById('w0').parentNode.textContent;
variant = variant.slice(variant.indexOf("Вопрос:"));
hash = hashCode(variant);
update_variant();
form.addEventListener('click', update_variant);
}
function result_page_handler() {
var i;
var correct = variant.slice(variant.indexOf("Число верных ответов: ") + 22);
correct = correct.slice(0, correct.indexOf("\n"));
var test = GM_getValue('tests', new Object())[testID];
if (test === undefined) {
return;
}
var printer = "";
var sorted_test = [];
for (var hash in test) {
sorted_test.push([hash].concat(test[hash]));
}
sorted_test.sort((a, b) => {return a[1] - b[1]});
console.log(sorted_test);
for (i = 0; i < sorted_test.length; i++) {
printer += (config.get('append_question_number') ? (sorted_test[i][1] + ") ") : "") + sorted_test[i][0] + " " + sorted_test[i][2] + "\n";
}
printer += correct;
if (config.get('copy_answers')) {
GM_setClipboard(printer);
}
if (config.get('accumulator_enable')) {
var acc = GM_getValue('accumulated_answers', "");
if (acc != "") {
acc += "\n\n";
}
var prefix = config.get('accumulator_prefix');
if (prefix != "") {
acc += prefix + "\n";
}
acc += printer;
GM_setValue('accumulated_answers', acc);
printer = acc;
}
printer = "<textarea readonly style='resize:none; width:fit-content; height:fit-content' rows='" + String(Object.keys(test).length + 1) + "' cols='50' onfocus='this.select();' id='answers'>" + printer + "</textarea>";
var pboxes = document.getElementsByTagName('p');
for (i = 0; i < pboxes.length; i++) {
var pbox = pboxes[i];
if (pbox.textContent.includes("Попытка ")) {
pbox.outerHTML += printer;
break;
}
}
var clear = GM_getValue('clear_tests', new Object());
clear[testID] = true;
GM_setValue('clear_tests', clear);
}
function DB_cleaner() {
var clear = GM_getValue('clear_tests', new Object());
var tests = GM_getValue('tests', new Object());
@ -360,7 +302,183 @@ function press_continue_btn() {
}
}
function actionFunction() {
function calculate_variant_hash() {
variant = document.getElementById('w0').parentNode.textContent;
variant = variant.slice(variant.indexOf("Вопрос:"));
hash = hashCode(variant);
}
function update_variant() {
var i, pbox;
var chosen_answer = "";
switch (type) {
case 'checkbox':
case 'radio': {
for (i = 0; i < answers.length; i++) {
chosen_answer += answers[i].checked ? answers[i].value : "";
}
chosen_answer = chosen_answer.split('').sort().join('');
} break;
case 'text': {
for (i = 0; i < answers.length; i++) {
chosen_answer += "[" + answers[i].value + "]";
}
}
}
var pboxes = document.getElementsByTagName('p');
const display_answer = config.get('display_answer');
for (i = 0; i < pboxes.length; i++) {
pbox = pboxes[i];
if (pbox.textContent.includes("Вопрос:")) {
pbox.innerHTML = "<i>(Вариант <input onfocus='this.select();' id='variant' value='" + hash + (display_answer == true ? (" " + chosen_answer) : "") + "' readonly>)</i><br>Вопрос:";
break;
}
}
var question_num = undefined;
for (i = 0; i < pboxes.length; i++) {
pbox = pboxes[i];
if (pbox.textContent.includes("Текущий вопрос: ")) {
question_num = pbox.textContent.slice(variant.indexOf("Текущий вопрос: ") + 16);
break;
}
}
var tests = GM_getValue('tests', new Object());
if (tests[testID] === undefined) {
tests[testID] = new Object();
}
tests[testID][hash] = [question_num, chosen_answer];
GM_setValue('tests', tests);
}
/* End Functions */
/* Handlers */
function test_form_handler() {
var i;
var boxes = [];
var objects = new Object();
var form = document.getElementById('testform-answer');
var manual_form = document.getElementById('testform-answer-0');
if (form != null) {
boxes = form.getElementsByTagName('input');
} else if (manual_form != null) {
i = 1;
while (manual_form != null) {
boxes.push(manual_form);
manual_form = document.getElementById('testform-answer-' + i++);
}
console.log(boxes);
}
type = boxes[0].type;
console.log(type);
switch (type) {
case 'checkbox':
case 'radio': {
for (i = 0; i < boxes.length; i++) {
var answerHash = hashCode(boxes[i].parentNode.innerText)
var span = document.createElement('span');
span.innerHTML =
boxes[i].type === 'radio' && boxes[i].value == "1"
? "<b>" + boxes[i].value + ")</b> "
: boxes[i].value + ") ";
boxes[i].parentNode.insertBefore(span, boxes[i]);
objects[boxes[i].value] = boxes[i];
}
const sorted_objects = Object.keys(objects).sort().reduce(
(obj, key) => {
obj[key] = objects[key];
return obj;
}, {}
);
for (var key in sorted_objects) {
sorted_objects[key].parentNode.remove();
form.appendChild(sorted_objects[key].parentNode);
answers.push(sorted_objects[key]);
}
calculate_variant_hash();
var correct_answer = S_getValue(testID + "." + hash + ".correct", undefined);
var incorrect_answers = S_getValue(testID + "." + hash + ".incorrect", undefined);
const auto_answer = config.get('auto_answer');
if (auto_answer == labels.auto_answer_random) {
if (answers[0].type === 'radio') {
var chosen_answer = Math.floor(Math.random() * answers.length);
answers[chosen_answer].click();
} else {
var pick = Math.floor(Math.random() * (Math.pow(2, answers.length) - 1)) + 1;
for (i = 0; i < answers.length; i++) {
if(pick & Math.pow(2, i)) {
answers[i].click();
}
}
}
} else if (auto_answer == labels.auto_answer_first) {
answers[0].click();
}
} break;
case 'text': {
answers = boxes;
calculate_variant_hash();
} break;
}
update_variant();
for (i = 0; i < answers.length; i++) {
answers[i].addEventListener('change', update_variant);
}
}
function result_page_handler() {
var i;
var correct = variant.slice(variant.indexOf("Число верных ответов: ") + 22);
correct = correct.slice(0, correct.indexOf("\n"));
var test = GM_getValue('tests', new Object())[testID];
if (test === undefined) {
return;
}
var printer = "";
var sorted_test = [];
for (var hash in test) {
sorted_test.push([hash].concat(test[hash]));
}
sorted_test.sort((a, b) => {return a[1] - b[1]});
console.log(sorted_test);
for (i = 0; i < sorted_test.length; i++) {
printer += (config.get('append_question_number') ? (sorted_test[i][1] + ") ") : "") + sorted_test[i][0] + " " + sorted_test[i][2] + "\n";
}
printer += correct;
if (config.get('copy_answers')) {
GM_setClipboard(printer);
}
if (config.get('accumulator_enable')) {
var acc = GM_getValue('accumulated_answers', "");
if (acc != "") {
acc += "\n\n";
}
var prefix = testID;
if (prefix != "") {
acc += prefix + "\n";
}
acc += printer;
GM_setValue('accumulated_answers', acc);
printer = acc;
}
printer = "<textarea readonly style='resize:none; width:fit-content; height:fit-content' rows='" + String(Object.keys(test).length + 1) + "' cols='50' onfocus='this.select();' id='answers'>" + printer + "</textarea>";
var pboxes = document.getElementsByTagName('p');
for (i = 0; i < pboxes.length; i++) {
var pbox = pboxes[i];
if (pbox.textContent.includes("Попытка ")) {
pbox.outerHTML += printer;
break;
}
}
var clear = GM_getValue('clear_tests', new Object());
clear[testID] = true;
GM_setValue('clear_tests', clear);
}
/* End Handlers */
function main() {
var old_time, cur_time;
variant = document.getElementById('w0').parentNode.textContent;
if (variant.includes("Вопрос:")) {