From 17e42cb17fe7380431fb20c412c9d3062f529bd7 Mon Sep 17 00:00:00 2001
From: mrfry
Date: Sun, 13 Sep 2020 08:58:14 +0200
Subject: [PATCH] Changed fixer to prettier
---
.eslintrc.js | 19 +
.prettierrc.js | 6 +
stable.user.js | 4339 ++++++++++++++++++++++++++----------------------
3 files changed, 2402 insertions(+), 1962 deletions(-)
create mode 100644 .eslintrc.js
create mode 100644 .prettierrc.js
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..19a2236
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,19 @@
+module.exports = {
+ env: {
+ browser: true,
+ es6: true,
+ node: true,
+ jest: true,
+ },
+ extends: ["eslint:recommended"],
+ globals: {
+ Atomics: "readonly",
+ SharedArrayBuffer: "readonly",
+ },
+ rules: {
+ "no-undef": ["warn"],
+ eqeqeq: ["warn", "smart"],
+ "no-unused-vars": "off",
+ "no-prototype-builtins": "off",
+ },
+};
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..937b387
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,6 @@
+module.exports = {
+ trailingComma: "es5",
+ tabWidth: 4,
+ semi: true,
+ singleQuote: false,
+};
diff --git a/stable.user.js b/stable.user.js
index 91a7e9d..0018c4a 100755
--- a/stable.user.js
+++ b/stable.user.js
@@ -50,2025 +50,2440 @@
// TODO:
// grabboxes test on quiz page
-(function() { // eslint-disable-line
- // GM functions, only to disable ESLINT errors
- /* eslint-disable */
- const a = Main
- function getVal (name) { return GM_getValue(name) }
- function setVal (name, val) { return GM_setValue(name, val) }
- function delVal (name) { return GM_deleteValue(name) }
- function openInTab (address, options) { GM_openInTab(address, options) }
- function xmlhttpRequest (opts) { GM_xmlhttpRequest(opts) }
- function info () { return GM_info }
- /* eslint-enable */
+(function() {
+ // eslint-disable-line
+ // GM functions, only to disable ESLINT errors
+ /* eslint-disable */
+ const a = Main;
+ const usf = unsafeWindow;
+ function getVal(name) {
+ return GM_getValue(name);
+ }
+ function setVal(name, val) {
+ return GM_setValue(name, val);
+ }
+ function delVal(name) {
+ return GM_deleteValue(name);
+ }
+ function openInTab(address, options) {
+ GM_openInTab(address, options);
+ }
+ function xmlhttpRequest(opts) {
+ GM_xmlhttpRequest(opts);
+ }
+ function info() {
+ return GM_info;
+ }
+ /* eslint-enable */
- var addEventListener // add event listener function
- let serverAdress = 'https://qmining.frylabs.net/'
- let apiAdress = 'https://api.frylabs.net/'
- const ircAddress = 'https://kiwiirc.com/nextclient/irc.sub.fm/#qmining'
+ var addEventListener; // add event listener function
+ let serverAdress = "https://qmining.frylabs.net/";
+ let apiAdress = "https://api.frylabs.net/";
+ const ircAddress = "https://kiwiirc.com/nextclient/irc.sub.fm/#qmining";
- // forcing pages for testing. unless you test, do not set these to true!
- // only one of these should be true for testing
- const forceTestPage = false
- const forceResultPage = false
- const forceDefaultPage = false
- const logElementGetting = false
- const log = true
+ // forcing pages for testing. unless you test, do not set these to true!
+ // only one of these should be true for testing
+ const forceTestPage = false;
+ const forceResultPage = false;
+ const forceDefaultPage = false;
+ const logElementGetting = false;
+ const log = true;
- const motdShowCount = 3 /* Ammount of times to show motd */
- let infoExpireTime = 60 // Every n seconds basic info should be loaded from server
- var motd = ''
- var lastestVersion = ''
- var subjInfo
+ const motdShowCount = 3; /* Ammount of times to show motd */
+ let infoExpireTime = 60; // Every n seconds basic info should be loaded from server
+ var motd = "";
+ var lastestVersion = "";
+ var subjInfo;
- if (getVal('ISDEVEL')) {
- infoExpireTime = 1
- serverAdress = 'http://localhost:8080/'
- apiAdress = 'http://localhost:80/'
- }
-
- const huTexts = {
- lastChangeLog: '',
- fatalError: 'Fatál error. Check console (f12). Kattints az üzenetre az összes kérdés/válaszért manuális kereséshez!',
- consoleErrorInfo: 'Itteni hibák 100% a moodle hiba. Kivéve, ha oda van írva hogy script error ;) Ha ilyesmi szerepel itt, akkor olvasd el a segítség szekciót!',
- freshStartWarning: 'Moodle teszt userscript:1.5.0 verzió: a script mostantól XMLHTTP kéréseket küld szerver fele! Erre a userscript futtató kiegészítőd is figyelmeztetni fog! Ha ez történik, a script rendes működése érdekében engedélyezd (Always allow domain)! Ha nem akarod, hogy ez történjen, akkor ne engedélyezd, vagy a menüben válaszd ki a "helyi fájl használata" opciót!
Elküldött adatok: minden teszt után a kérdés-válasz páros. Fogadott adatok: Az összes eddig ismert kérdés. Érdemes help-et elolvasni!!!
Ez az ablak frissités után eltűnik. Ha nem, akkor a visza gombbal próbálkozz.
',
- noResult: 'Nincs találat :( Kattints az üzenetre az összes kérdés/válaszért manuális kereséshez!',
- videoHelp: 'Miután elindítottad: Play/pause: space. Seek: Bal/jobb nyíl.',
- menuButtonText: 'Kérdések Menu',
- couldntLoadDataPopupMenuText: 'A kérdéseket nem lehetett beolvasni, ellenőrizd hogy elérhető-e a szerver',
- showGreetingOnEveryPage: 'Üdvözlő üzenet mutatása minden oldalon',
- close: 'Bezárás',
- help: 'Help',
- websiteBugreport: 'Weboldal / Bug report',
- contribute: 'Contribute',
- donate: 'Donate',
- retry: 'Újrapróbálás',
- ircButton: 'IRC',
- invalidPW: 'Hibás jelszó: ',
- search: 'Keresés ...',
- loading: 'Betöltés ...',
- login: 'Belépés',
- requestPWInsteadOfLogin: 'Jelszó igénylés',
- contributeTitle: 'Hozzájárulás a script és weboldal fejleszétéshez',
- newPWTitle: 'Új jelszó új felhasználónak',
- pwRequest: 'Új jelszó',
- noServer: 'Nem elérhető a szerver!',
- noUser: 'Nem vagy bejelentkezve!',
- noServerConsoleMessage: `Nem elérhető a szerver, vagy kis eséllyel kezeletlen hiba történt! Ha elérhető a weboldal, akkor ott meg bírod nézni a kérdéseket itt: ${serverAdress}legacy`
- }
-
- var texts = huTexts
-
- // : question-classes {{{
- const specialChars = [ '&', '\\+' ]
-
- const assert = (val) => {
- if (!val) { throw new Error('Assertion failed') }
- }
-
- class StringUtils {
- RemoveStuff (value, removableStrings, toReplace) {
- removableStrings.forEach((x) => {
- var regex = new RegExp(x, 'g')
- value = value.replace(regex, toReplace || '')
- })
- return value
+ if (getVal("ISDEVEL")) {
+ infoExpireTime = 1;
+ serverAdress = "http://localhost:8080/";
+ apiAdress = "http://localhost:80/";
}
- SimplifyQuery (q) {
- assert(q)
-
- var result = q.replace(/\n/g, ' ').replace(/\s/g, ' ')
- return this.RemoveUnnecesarySpaces(result)
- }
-
- ShortenString (toShorten, ammount) {
- assert(toShorten)
-
- var result = ''
- var i = 0
- while (i < toShorten.length && i < ammount) {
- result += toShorten[i]
- i++
- }
- return result
- }
-
- ReplaceCharsWithSpace (val, char) {
- assert(val)
- assert(char)
-
- var toremove = this.NormalizeSpaces(val)
-
- var regex = new RegExp(char, 'g')
- toremove = toremove.replace(regex, ' ')
-
- return this.RemoveUnnecesarySpaces(toremove)
- }
-
- // removes whitespace from begining and and, and replaces multiple spaces with one space
- RemoveUnnecesarySpaces (toremove) {
- assert(toremove)
-
- toremove = this.NormalizeSpaces(toremove)
- while (toremove.includes(' ')) {
- toremove = toremove.replace(/ {2}/g, ' ')
- }
- return toremove.trim()
- }
-
- RemoveSpecialChars (value) {
- assert(value)
-
- return this.RemoveStuff(value, specialChars, ' ')
- }
-
- // if the value is empty, or whitespace
- EmptyOrWhiteSpace (value) {
- // replaces /n-s with "". then replaces spaces with "". if it equals "", then its empty, or only consists of white space
- if (value === undefined) { return true }
- return (value.replace(/\n/g, '').replace(/ /g, '').replace(/\s/g, ' ') === '')
- }
-
- // damn nonbreaking space
- NormalizeSpaces (input) {
- assert(input)
-
- return input.replace(/\s/g, ' ')
- }
-
- SimplifyStack (stack) {
- return this.SimplifyQuery(stack)
- }
- }
-
- const SUtils = new StringUtils()
-
- // : }}}
-
- // : DOM getting stuff {{{
- // all dom getting stuff are in this sections, so on
- // moodle dom change, stuff breaks here
-
- //Stealth by An0 with love
- function StealthOverlay() { //call this before the document scripts
- const document = window.document;
-
- const neverEqualPlaceholder = Symbol(`never equal`); //block probing for undefined values in the hooks
- let shadowRootHost = neverEqualPlaceholder;
- let shadowRootNewHost = neverEqualPlaceholder;
-
- const apply = Reflect.apply; //save some things in case they get hooked (only for unsafe contexts)
-
-
- if(unsafeWindow.Error.hasOwnProperty('stackTraceLimit')) {
- Reflect.defineProperty(unsafeWindow.Error, 'stackTraceLimit', { value: undefined, writable: false, enumerable: false, configurable: false });
- }
-
- const shadowGetHandler = { apply: (target, thisArg, argumentsList) => apply(target, (thisArg === shadowRootHost) ? shadowRootNewHost : thisArg, argumentsList) };
-
- const original_attachShadow = unsafeWindow.Element.prototype.attachShadow;
- const attachShadowProxy = new Proxy(original_attachShadow, shadowGetHandler);
- unsafeWindow.Element.prototype.attachShadow = attachShadowProxy;
-
- const getShadowRootProxy = new Proxy(Object.getOwnPropertyDescriptor(unsafeWindow.Element.prototype, 'shadowRoot').get, shadowGetHandler);
- Object.defineProperty(unsafeWindow.Element.prototype, 'shadowRoot', { get: getShadowRootProxy });
-
- const getHostHandler = { apply: function() { let result = apply(...arguments); return (result === shadowRootNewHost) ? shadowRootHost : result; } };
- const getHostProxy = new Proxy(Object.getOwnPropertyDescriptor(unsafeWindow.ShadowRoot.prototype, 'host').get, getHostHandler);
- Object.defineProperty(unsafeWindow.ShadowRoot.prototype, 'host', { get: getHostProxy });
-
-
- const shadowRootSetInnerHtml = Object.getOwnPropertyDescriptor(ShadowRoot.prototype, 'innerHTML').set;
- const documentFragmentGetChildren = Object.getOwnPropertyDescriptor(DocumentFragment.prototype, 'children').get;
- const documentGetBody = Object.getOwnPropertyDescriptor(Document.prototype, 'body').get;
- const nodeAppendChild = Node.prototype.appendChild;
-
- const overlay = document.createElement('div');
- overlay.style.cssText = "position:absolute;left:0;top:0";
-
- const addOverlay = () => {
- shadowRootHost = apply(documentGetBody, document, []);
- const shadowRoot = apply(original_attachShadow, shadowRootHost, [{mode:'closed'}]);
- apply(shadowRootSetInnerHtml, shadowRoot, [`
`]);
- shadowRootNewHost = apply(documentFragmentGetChildren, shadowRoot, [])[0];
- apply(nodeAppendChild, shadowRoot, [overlay]);
+ const huTexts = {
+ lastChangeLog: "",
+ fatalError:
+ "Fatál error. Check console (f12). Kattints az üzenetre az összes kérdés/válaszért manuális kereséshez!",
+ consoleErrorInfo:
+ "Itteni hibák 100% a moodle hiba. Kivéve, ha oda van írva hogy script error ;) Ha ilyesmi szerepel itt, akkor olvasd el a segítség szekciót!",
+ freshStartWarning:
+ 'Moodle teszt userscript:1.5.0 verzió: a script mostantól XMLHTTP kéréseket küld szerver fele! Erre a userscript futtató kiegészítőd is figyelmeztetni fog! Ha ez történik, a script rendes működése érdekében engedélyezd (Always allow domain)! Ha nem akarod, hogy ez történjen, akkor ne engedélyezd, vagy a menüben válaszd ki a "helyi fájl használata" opciót!
Elküldött adatok: minden teszt után a kérdés-válasz páros. Fogadott adatok: Az összes eddig ismert kérdés. Érdemes help-et elolvasni!!!
Ez az ablak frissités után eltűnik. Ha nem, akkor a visza gombbal próbálkozz.
',
+ noResult:
+ "Nincs találat :( Kattints az üzenetre az összes kérdés/válaszért manuális kereséshez!",
+ videoHelp:
+ "Miután elindítottad: Play/pause: space. Seek: Bal/jobb nyíl.",
+ menuButtonText: "Kérdések Menu",
+ couldntLoadDataPopupMenuText:
+ "A kérdéseket nem lehetett beolvasni, ellenőrizd hogy elérhető-e a szerver",
+ showGreetingOnEveryPage: "Üdvözlő üzenet mutatása minden oldalon",
+ close: "Bezárás",
+ help: "Help",
+ websiteBugreport: "Weboldal / Bug report",
+ contribute: "Contribute",
+ donate: "Donate",
+ retry: "Újrapróbálás",
+ ircButton: "IRC",
+ invalidPW: "Hibás jelszó: ",
+ search: "Keresés ...",
+ loading: "Betöltés ...",
+ login: "Belépés",
+ requestPWInsteadOfLogin: "Jelszó igénylés",
+ contributeTitle: "Hozzájárulás a script és weboldal fejleszétéshez",
+ newPWTitle: "Új jelszó új felhasználónak",
+ pwRequest: "Új jelszó",
+ noServer: "Nem elérhető a szerver!",
+ noUser: "Nem vagy bejelentkezve!",
+ noServerConsoleMessage: `Nem elérhető a szerver, vagy kis eséllyel kezeletlen hiba történt! Ha elérhető a weboldal, akkor ott meg bírod nézni a kérdéseket itt: ${serverAdress}legacy`,
};
- if (!document.body) {
- document.addEventListener('DOMContentLoaded', addOverlay);
- }
- else {
- addOverlay();
- }
- return overlay;
- }
+ var texts = huTexts;
- const overlay = StealthOverlay();
+ // : question-classes {{{
+ const specialChars = ["&", "\\+"];
-
- function createHoverOver(target) {
- const overlayElement = document.createElement('div');
- overlayElement.style.cssText = "position:fixed; pointer-events: none; user-select: none; z-index:10000";
- overlay.append(overlayElement);
- let currX, currY, currWidth, currHeight;
- const copyBoundingRect = () => {
- let { x, y, width, height } = target.getBoundingClientRect();
- if(x !== currX) { overlayElement.style.left = x + 'px'; currX = x; }
- if(y !== currY) { overlayElement.style.top = y + 'px'; currY = y; }
- if(width !== currWidth) { overlayElement.style.width = width + 'px'; currWidth = width; }
- if(height !== currHeight) { overlayElement.style.height = height + 'px'; currHeight = height; }
+ const assert = val => {
+ if (!val) {
+ throw new Error("Assertion failed");
+ }
};
- copyBoundingRect();
- const interval = setInterval(copyBoundingRect, 30);
- overlayElement.destroy = () => {
- clearInterval(interval);
- overlayElement.remove();
- };
- return overlayElement;
- }
+ class StringUtils {
+ RemoveStuff(value, removableStrings, toReplace) {
+ removableStrings.forEach(x => {
+ var regex = new RegExp(x, "g");
+ value = value.replace(regex, toReplace || "");
+ });
+ return value;
+ }
+ SimplifyQuery(q) {
+ assert(q);
- class QuestionsPageModell {
- GetAllQuestionsDropdown () {
- if (logElementGetting) { Log('getting dropdown question') }
- let items = document.getElementById('responseform').getElementsByTagName('p')[0].childNodes
- let r = ''
- items.forEach((item) => {
- if (item.tagName === undefined) { r += item.nodeValue }
- })
- return r
+ var result = q.replace(/\n/g, " ").replace(/\s/g, " ");
+ return this.RemoveUnnecesarySpaces(result);
+ }
+
+ ShortenString(toShorten, ammount) {
+ assert(toShorten);
+
+ var result = "";
+ var i = 0;
+ while (i < toShorten.length && i < ammount) {
+ result += toShorten[i];
+ i++;
+ }
+ return result;
+ }
+
+ ReplaceCharsWithSpace(val, char) {
+ assert(val);
+ assert(char);
+
+ var toremove = this.NormalizeSpaces(val);
+
+ var regex = new RegExp(char, "g");
+ toremove = toremove.replace(regex, " ");
+
+ return this.RemoveUnnecesarySpaces(toremove);
+ }
+
+ // removes whitespace from begining and and, and replaces multiple spaces with one space
+ RemoveUnnecesarySpaces(toremove) {
+ assert(toremove);
+
+ toremove = this.NormalizeSpaces(toremove);
+ while (toremove.includes(" ")) {
+ toremove = toremove.replace(/ {2}/g, " ");
+ }
+ return toremove.trim();
+ }
+
+ RemoveSpecialChars(value) {
+ assert(value);
+
+ return this.RemoveStuff(value, specialChars, " ");
+ }
+
+ // if the value is empty, or whitespace
+ EmptyOrWhiteSpace(value) {
+ // replaces /n-s with "". then replaces spaces with "". if it equals "", then its empty, or only consists of white space
+ if (value === undefined) {
+ return true;
+ }
+ return (
+ value
+ .replace(/\n/g, "")
+ .replace(/ /g, "")
+ .replace(/\s/g, " ") === ""
+ );
+ }
+
+ // damn nonbreaking space
+ NormalizeSpaces(input) {
+ assert(input);
+
+ return input.replace(/\s/g, " ");
+ }
+
+ SimplifyStack(stack) {
+ return this.SimplifyQuery(stack);
+ }
}
- GetAllQuestionsQtext () {
- if (logElementGetting) { Log('getting all questions qtext') }
- return document.getElementById('responseform').getElementsByClassName('qtext') // getting questions
+ const SUtils = new StringUtils();
+
+ // : }}}
+
+ // : DOM getting stuff {{{
+ // all dom getting stuff are in this sections, so on
+ // moodle dom change, stuff breaks here
+
+ //Stealth by An0 with love
+ function StealthOverlay() {
+ //call this before the document scripts
+ const document = window.document;
+
+ const neverEqualPlaceholder = Symbol(`never equal`); //block probing for undefined values in the hooks
+ let shadowRootHost = neverEqualPlaceholder;
+ let shadowRootNewHost = neverEqualPlaceholder;
+
+ const apply = Reflect.apply; //save some things in case they get hooked (only for unsafe contexts)
+
+ if (usf.Error.hasOwnProperty("stackTraceLimit")) {
+ Reflect.defineProperty(usf.Error, "stackTraceLimit", {
+ value: undefined,
+ writable: false,
+ enumerable: false,
+ configurable: false,
+ });
+ }
+
+ const shadowGetHandler = {
+ apply: (target, thisArg, argumentsList) =>
+ apply(
+ target,
+ thisArg === shadowRootHost ? shadowRootNewHost : thisArg,
+ argumentsList
+ ),
+ };
+
+ const original_attachShadow = usf.Element.prototype.attachShadow;
+ const attachShadowProxy = new Proxy(
+ original_attachShadow,
+ shadowGetHandler
+ );
+ usf.Element.prototype.attachShadow = attachShadowProxy;
+
+ const getShadowRootProxy = new Proxy(
+ Object.getOwnPropertyDescriptor(
+ usf.Element.prototype,
+ "shadowRoot"
+ ).get,
+ shadowGetHandler
+ );
+ Object.defineProperty(usf.Element.prototype, "shadowRoot", {
+ get: getShadowRootProxy,
+ });
+
+ const getHostHandler = {
+ apply: function() {
+ let result = apply(...arguments);
+ return result === shadowRootNewHost ? shadowRootHost : result;
+ },
+ };
+ const getHostProxy = new Proxy(
+ Object.getOwnPropertyDescriptor(
+ usf.ShadowRoot.prototype,
+ "host"
+ ).get,
+ getHostHandler
+ );
+ Object.defineProperty(usf.ShadowRoot.prototype, "host", {
+ get: getHostProxy,
+ });
+
+ const shadowRootSetInnerHtml = Object.getOwnPropertyDescriptor(
+ ShadowRoot.prototype,
+ "innerHTML"
+ ).set;
+ const documentFragmentGetChildren = Object.getOwnPropertyDescriptor(
+ DocumentFragment.prototype,
+ "children"
+ ).get;
+ const documentGetBody = Object.getOwnPropertyDescriptor(
+ Document.prototype,
+ "body"
+ ).get;
+ const nodeAppendChild = Node.prototype.appendChild;
+
+ const overlay = document.createElement("div");
+ overlay.style.cssText = "position:absolute;left:0;top:0";
+
+ const addOverlay = () => {
+ shadowRootHost = apply(documentGetBody, document, []);
+ const shadowRoot = apply(original_attachShadow, shadowRootHost, [
+ { mode: "closed" },
+ ]);
+ apply(shadowRootSetInnerHtml, shadowRoot, [
+ `
`,
+ ]);
+ shadowRootNewHost = apply(
+ documentFragmentGetChildren,
+ shadowRoot,
+ []
+ )[0];
+ apply(nodeAppendChild, shadowRoot, [overlay]);
+ };
+
+ if (!document.body) {
+ document.addEventListener("DOMContentLoaded", addOverlay);
+ } else {
+ addOverlay();
+ }
+ return overlay;
}
- GetAllQuestionsP () {
- if (logElementGetting) { Log('getting all questions by tag p') }
- return document.getElementById('responseform').getElementsByTagName('p')
+ const overlay = StealthOverlay();
+
+ function createHoverOver(target) {
+ const overlayElement = document.createElement("div");
+ overlayElement.style.cssText =
+ "position:fixed; pointer-events: none; user-select: none; z-index:10000";
+ overlay.append(overlayElement);
+ let currX, currY, currWidth, currHeight;
+ const copyBoundingRect = () => {
+ let { x, y, width, height } = target.getBoundingClientRect();
+ if (x !== currX) {
+ overlayElement.style.left = x + "px";
+ currX = x;
+ }
+ if (y !== currY) {
+ overlayElement.style.top = y + "px";
+ currY = y;
+ }
+ if (width !== currWidth) {
+ overlayElement.style.width = width + "px";
+ currWidth = width;
+ }
+ if (height !== currHeight) {
+ overlayElement.style.height = height + "px";
+ currHeight = height;
+ }
+ };
+ copyBoundingRect();
+ const interval = setInterval(copyBoundingRect, 30);
+ overlayElement.destroy = () => {
+ clearInterval(interval);
+ overlayElement.remove();
+ };
+ return overlayElement;
}
- GetFormulationClearfix () {
- if (logElementGetting) { Log('getting formulation clearfix lol') }
- return document.getElementsByClassName('formulation clearfix')
- }
-
- GetAnswerOptions () {
- if (logElementGetting) { Log('getting all answer options') }
- return this.GetFormulationClearfix()[0].childNodes[3].innerText
- }
-
- GetQuestionImages () {
- if (logElementGetting) { Log('getting question images') }
- return this.GetFormulationClearfix()[0].getElementsByTagName('img')
- }
-
- // this function should return the question, posible answers, and image names
- GetQuestionFromTest () {
- var questions // the important questions
- var allQuestions // all questions
- try {
- allQuestions = this.GetAllQuestionsQtext() // getting questions
- if (allQuestions.length === 0) {
- var ddq = this.GetAllQuestionsDropdown()
- if (SUtils.EmptyOrWhiteSpace(ddq)) {
- var questionData = ''
- for (var j = 0; j < allQuestions.length; j++) {
- let subAllQuestions = allQuestions[j].childNodes
- for (let i = 0; i < subAllQuestions.length; i++) {
- if (subAllQuestions[i].data !== undefined && !SUtils.EmptyOrWhiteSpace(subAllQuestions[i].data)) {
- questionData += subAllQuestions[i].data + ' ' // adding text to question data
+ class QuestionsPageModell {
+ GetAllQuestionsDropdown() {
+ if (logElementGetting) {
+ Log("getting dropdown question");
+ }
+ let items = document
+ .getElementById("responseform")
+ .getElementsByTagName("p")[0].childNodes;
+ let r = "";
+ items.forEach(item => {
+ if (item.tagName === undefined) {
+ r += item.nodeValue;
}
- }
+ });
+ return r;
+ }
+
+ GetAllQuestionsQtext() {
+ if (logElementGetting) {
+ Log("getting all questions qtext");
}
- questions = [questionData]
- } else { questions = [ddq] }
- } else {
- questions = []
- for (let i = 0; i < allQuestions.length; i++) {
- questions.push(allQuestions[i].innerText)
- }
- }
- } catch (e) {
- Exception(e, 'script error at getting question:')
- }
- var imgNodes = '' // the image nodes for questions
- try {
- imgNodes = this.GetQuestionImages() // getting question images, if there is any
- AddImageNamesToImages(imgNodes) // adding image names to images, so its easier to search for, or even guessing
- } catch (e) {
- Log(e)
- Log('Some error with images')
- }
-
- questions = questions.map((item) => {
- if (item) {
- return SUtils.ReplaceCharsWithSpace(item, '\n')
- }
- })
-
- return {
- imgnodes: imgNodes,
- allQ: allQuestions,
- q: questions
- }
- }
- }
-
- class ResultsPageModell {
- GetFormulationClearfix () {
- if (logElementGetting) { Log('getting formulation clearfix lol') }
- return document.getElementsByClassName('formulation clearfix')
- }
-
- GetGrade (i) {
- if (logElementGetting) { Log('getting grade') }
- const fcf = QPM.GetFormulationClearfix()[i]
- return fcf.parentNode.parentNode.childNodes[0].childNodes[2].innerText
- }
-
- DetermineQuestionType (nodes) {
- let qtype = ''
- let i = 0
-
- while (i < nodes.length && qtype === '') {
- let inps = nodes[i].getElementsByTagName('input')
-
- if (inps.length > 0) {
- qtype = inps[0].type
+ return document
+ .getElementById("responseform")
+ .getElementsByClassName("qtext"); // getting questions
}
- i++
- }
-
- return qtype
- }
-
- GetSelectAnswer (i) {
- if (logElementGetting) { Log('getting selected answer') }
- var t = document.getElementsByTagName('select')
- if (t.length > 0) {
- return t[i].options[t[i].selectedIndex].innerText
- }
- }
-
- GetCurrQuestion (i) {
- if (logElementGetting) { Log('getting curr questions by index: ' + i) }
- return document.getElementsByTagName('form')[0].childNodes[0].childNodes[i].childNodes[1].childNodes[0].innerText
- }
-
- GetFormResult () {
- if (logElementGetting) { Log('getting form result') }
- var t = document.getElementsByTagName('form')[0].childNodes[0].childNodes
- if (t.length > 0 && t[0].tagName === undefined) { // debreceni moodle
- return document.getElementsByTagName('form')[1].childNodes[0].childNodes
- } else {
- return t
- }
- }
-
- GetAnswerNode (i) {
- if (logElementGetting) { Log('getting answer node') }
-
- var results = this.GetFormResult() // getting results element
-
- var r = results[i].getElementsByClassName('answer')[0].childNodes
- var ret = []
- for (var j = 0; j < r.length; j++) {
- if (r[j].tagName !== undefined && r[j].tagName.toLowerCase() === 'div') { ret.push(r[j]) }
- }
-
- let qtype = this.DetermineQuestionType(ret)
-
- return {
- nodes: ret,
- type: qtype
- }
- }
-
- GetCurrentAnswer (i) {
- if (logElementGetting) { Log('getting curr answer by index: ' + i) }
- var results = this.GetFormResult() // getting results element
- var t = results[i].getElementsByClassName('formulation clearfix')[0].getElementsByTagName('span')
- if (t.length > 2) { return t[1].innerHTML.split('
')[1] }
- }
-
- GetQText (i) {
- if (logElementGetting) { Log('getting qtext by index: ' + i) }
- var results = this.GetFormResult() // getting results element
- return results[i].getElementsByClassName('qtext')
- }
-
- GetDropboxes (i) {
- if (logElementGetting) { Log('getting dropboxes by index: ' + i) }
- var results = this.GetFormResult() // getting results element
- return results[i].getElementsByTagName('select')
- }
-
- GetAllAnswer (index) {
- if (logElementGetting) { Log('getting all answers, ind: ' + index) }
- return document.getElementsByClassName('answer')[index].childNodes
- }
-
- GetPossibleAnswers (i) {
- if (logElementGetting) { Log('getting possible answers') }
- var results = this.GetFormResult() // getting results element
- var items = results[i].getElementsByTagName('label')
- var r = []
- for (var j = 0; j < items.length; j++) {
- const TryGetCorrect = (j) => {
- var cn = items[j].parentNode.className
- if (cn.includes('correct')) { return cn.includes('correct') && !cn.includes('incorrect') }
- }
- r.push({
- value: items[j].innerText,
- iscorrect: TryGetCorrect(j)
- })
- }
- return r
- }
-
- GetAnswersFromGrabBox (i) {
- try {
- if (logElementGetting) { Log('testing if question is grab-box') }
- let results = this.GetFormResult() // getting results element
- let t = results[i].getElementsByClassName('dragitems')[0].childNodes
- if (t.length !== 1) { Log('grab box drag items group length is not 1!'); Log(results[i].getElementsByClassName('dragitems')[0]) }
- let placedItems = t[0].getElementsByClassName('placed')
- let res = []
- for (let i = 0; i < placedItems.length; i++) {
- let item = placedItems[i]
- res.push({
- text: item.innerText,
- left: item.style.left,
- top: item.style.top
- })
- }
- return res
- } catch (e) {
-
- }
- }
-
- GetRightAnswerIfCorrectShown (i) {
- if (logElementGetting) { Log('getting right answer if correct shown') }
- var results = this.GetFormResult() // getting results element
- return results[i].getElementsByClassName('rightanswer')
- }
-
- GetWrongAnswerIfCorrectNotShown (i) {
- if (logElementGetting) { Log('getting wrong answer if correct not shown') }
- var results = this.GetFormResult() // getting results element
- var n = results[i].getElementsByTagName('i')[0].parentNode
- if (n.className.includes('incorrect')) { return results[i].getElementsByTagName('i')[0].parentNode.innerText } else { return '' }
- }
-
- GetRightAnswerIfCorrectNotShown (i) {
- if (logElementGetting) { Log('Getting right answer if correct not shown') }
- var results = this.GetFormResult() // getting results element
- var n = results[i].getElementsByTagName('i')[0].parentNode
- if (n.className.includes('correct') && !n.className.includes('incorrect')) {
- return results[i].getElementsByTagName('i')[0].parentNode.innerText
- }
- }
-
- GetFormCFOfResult (result) {
- if (logElementGetting) { Log('getting formulation clearfix') }
- return result.getElementsByClassName('formulation clearfix')[0]
- }
-
- GetResultText (i) {
- if (logElementGetting) { Log('getting result text') }
- var results = this.GetFormResult() // getting results element
- return this.GetFormCFOfResult(results[i]).getElementsByTagName('p')
- }
-
- GetResultImage (i) {
- if (logElementGetting) { Log('getting result image') }
- var results = this.GetFormResult() // getting results element
- return this.GetFormCFOfResult(results[i]).getElementsByTagName('img')
- }
-
- // gets the question from the result page
- // i is the index of the question
- GetQuestionFromResult (i) {
- var temp = this.GetQText(i)
- var currQuestion = ''
- if (temp.length > 0) {
- currQuestion = temp[0].innerText // adding the question to curr question as .q
- } else {
- // this is black magic fuckery a bit
- if (this.GetDropboxes(i).length > 0) {
- var allNodes = this.GetResultText(i)
- currQuestion = ''
- for (var k = 0; k < allNodes.length; k++) {
- var allQuestions = this.GetResultText(i)[k].childNodes
- for (var j = 0; j < allQuestions.length; j++) {
- if (allQuestions[j].data !== undefined && !SUtils.EmptyOrWhiteSpace(allQuestions[j].data)) {
- currQuestion += allQuestions[j].data + ' '
- }
+ GetAllQuestionsP() {
+ if (logElementGetting) {
+ Log("getting all questions by tag p");
}
- }
- } else {
- try {
- currQuestion = this.GetCurrQuestion(i)
- } catch (e) {
- currQuestion = 'REEEEEEEEEEEEEEEEEEEEE' // this shouldnt really happen sry guys
- Log('Unable to get question in GetQuestionFromResult')
- }
- }
- }
- return currQuestion
- }
-
- // tries to get right answer from result page
- // i is the index of the question
- GetRightAnswerFromResult (i) {
- var fun = []
-
- // "húzza oda ..." skip
- fun.push((i) => {
- let temp = RPM.GetAnswersFromGrabBox(i)
- return temp.map((x) => {
- return x.text
- }).join(', ')
- })
-
- // the basic type of getting answers
- fun.push((i) => {
- var temp = RPM.GetRightAnswerIfCorrectShown(i) // getting risht answer
- if (temp.length > 0) { return temp[0].innerText } // adding the answer to curr question as .a
- })
-
- // if there is dropdown list in the current question
- fun.push((i) => {
- if (RPM.GetDropboxes(i).length > 0) { return RPM.GetCurrentAnswer(i) }
- })
-
- // if the correct answers are not shown, and the selected answer
- // is correct
- fun.push((i) => {
- return RPM.GetRightAnswerIfCorrectNotShown(i)
- })
-
- // if there is dropbox in the question
- fun.push((i) => {
- return RPM.GetSelectAnswer(i)
- })
-
- // if the correct answers are not shown, and the selected answer
- // is incorrect, and there are only 2 options
- fun.push((i) => {
- var possibleAnswers = RPM.GetPossibleAnswers(i)
- if (possibleAnswers.length === 2) {
- for (var k = 0; k < possibleAnswers.length; k++) {
- if (possibleAnswers[k].iscorrect === undefined) { return possibleAnswers[k].value }
- }
- }
- })
-
- // if everything fails
- fun.push((i) => {
- return undefined
- })
-
- var j = 0
- var currAnswer
- while (j < fun.length && SUtils.EmptyOrWhiteSpace(currAnswer)) {
- try {
- currAnswer = fun[j](i)
- } catch (e) {
- }
- j++
- }
-
- return currAnswer
- }
-
- GuessCorrectIn2LengthAnswersByIncorrect (items) {
- const first = items[0]
- const second = items[1]
- if (first.className.includes('incorrect')) {
- return second.innerText
- }
- if (second.className.includes('incorrect')) {
- return first.innerText
- }
- }
-
- GuessCorrectIn2LengthAnswersByPoints (i, items) {
- const first = {
- elem: items[0],
- val: items[0].childNodes[0].checked,
- text: items[0].innerText
- }
- const second = {
- elem: items[1],
- val: items[1].childNodes[0].checked,
- text: items[1].innerText
- }
-
- const grade = RPM.GetGrade(i) // 1,00 közül 1,00 leosztályozva
- const grades = grade.split(' ').reduce((acc, text) => {
- if (text.includes(',')) { // FIXME: fancy regexp
- acc.push(parseInt(text))
- } else if (text.includes('.')) { // FIXME: fancy regexp
- acc.push(parseInt(text))
- }
- return acc
- }, [])
-
- if (grades[0] === 1) {
- if (first.val) {
- return first.text
- } else {
- return second.text
- }
- } else {
- if (!first.val) {
- return first.text
- } else {
- return second.text
- }
- }
- }
-
- // version 2 of getting right answer from result page
- // i is the index of the question
- GetRightAnswerFromResultv2 (i) {
- try {
- var answerNodes = this.GetAnswerNode(i)
- let items = answerNodes.nodes
-
- if (answerNodes.type === 'checkbox') { return RPM.GetRightAnswerFromResult(i) }
-
- for (let j = 0; j < items.length; j++) {
- let cn = items[j].className
- if (cn.includes('correct') && !cn.includes('incorrect')) {
- return items[j].getElementsByTagName('label')[0].innerText
- }
- }
- if (items.length === 2) {
- const resByIncorrect = this.GuessCorrectIn2LengthAnswersByIncorrect(items)
- if (!resByIncorrect) {
- const resPoints = this.GuessCorrectIn2LengthAnswersByPoints(i, items)
- return resPoints
- }
- return resByIncorrect
- }
- } catch (e) {
- Log('error at new nodegetting, trying the oldschool way')
- }
- }
- }
-
- class MiscPageModell {
- GetCurrentSubjectName () {
- if (logElementGetting) { Log('getting current subjects name') }
- return document.getElementById('page-header').innerText.split('\n')[0] || ''
- }
-
- GetVideo () {
- if (logElementGetting) { Log('getting video stuff') }
- return document.getElementsByTagName('video')[0]
- }
-
- GetVideoElement () {
- if (logElementGetting) { Log('getting video element') }
- return document.getElementById('videoElement').parentNode
- }
-
- GetInputType (answers, i) {
- if (logElementGetting) { Log('getting input type') }
- return answers[i].getElementsByTagName('input')[0].type
- }
- }
-
- var QPM = new QuestionsPageModell()
- var RPM = new ResultsPageModell()
- var MPM = new MiscPageModell()
-
- // : }}}
-
- // : Main function {{{
- let timerStarted = false
-
- Main()
- function Main () {
- 'use strict'
- console.log('Moodle / E-Learning script')
- console.time('main')
- timerStarted = true
-
- if(document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', Init)
- }
- else {
- Init()
- }
- }
-
- function AfterLoad () {
- const url = location.href // eslint-disable-line
-
- try {
- if ((url.includes('/quiz/') && url.includes('attempt.php')) || forceTestPage) { // if the current page is a test
- HandleQuiz()
- } else if ((url.includes('/quiz/') && url.includes('review.php')) || forceResultPage) { // if the current window is a test-s result
- HandleResults(url)
- } else if ((!url.includes('/quiz/') && !url.includes('review.php') && !url.includes('.pdf')) ||
- (forceDefaultPage)) { // if the current window is any other window than a quiz or pdf.
- HandleUI(url)
- }
- } catch (e) {
- ShowMessage({
- m: texts.fatalError,
- isSimple: true
- }, undefined, () => {
- OpenErrorPage(e)
- })
-
- Exception(e, 'script error at main:')
- }
- if (url.includes('eduplayer')) { AddVideoHotkeys(url) } // adding video hotkeys
- Log(texts.consoleErrorInfo)
-
- if (timerStarted) {
- console.log('Moodle Test Script run time:')
- console.timeEnd('main')
- timerStarted = false
- }
-
- if (forceTestPage || forceResultPage || forceDefaultPage) {
- if (overlay.querySelector('#scriptMessage')) {
- overlay.querySelector('#scriptMessage').style.background = 'green'
- }
- }
- }
- // : }}}
-
- // : Main logic stuff {{{
-
- // : Loading {{{
- function HandleQminingSite (url) {
- try {
- const idInput = document.getElementById('cid')
- if (idInput) {
- idInput.value = getVal('clientId')
- }
- } catch (e) {
- console.info('Error filling client ID input', e)
- }
- try {
- const sideLinks = document.getElementById('sideBarLinks')
- if (!sideLinks) {
- return
- }
- Array.from(sideLinks.childNodes).forEach((link) => {
- link.addEventListener('mousedown', () => {
- FillFeedbackCID(url, link)
- })
- })
-
- FillFeedbackCID(url,
- document.getElementById('sideBarLinks').getElementsByClassName('active')[0]
- )
- } catch (e) {
- console.info('Error filling client ID input', e)
- }
- }
-
- function FillFeedbackCID (url, link) {
- try {
- if (link.id === 'feedback') {
- const cidSetInterval = setInterval(() => {
- const cid = document.getElementById('cid')
- if (cid) {
- cid.value = GetId() + '|' + info().script.version
- window.clearInterval(cidSetInterval)
- }
- }, 100)
- }
- } catch (e) {
- console.info('Error filling client ID input', e)
- }
- }
-
- function Init () {
- const url = location.href // eslint-disable-line
-
- if (url.includes(serverAdress.split('/')[2])) {
- HandleQminingSite(url)
- return
- }
-
- if (false) { // eslint-disable-line
- setVal('version16', undefined)
- setVal('version15', undefined)
- setVal('firstRun', undefined)
- setVal('showQuestions', undefined)
- setVal('showSplash', undefined)
- }
- // --------------------------------------------------------------------------------------
- // event listener fuckery
- // --------------------------------------------------------------------------------------
- try {
- // adding addeventlistener stuff, for the ability to add more event listeners for the same event
- addEventListener = (function () {
- if (document.addEventListener) {
- return function (element, event, handler) {
- element.addEventListener(event, handler, false)
- }
- } else {
- return function (element, event, handler) {
- element.attachEvent('on' + event, handler)
- }
- }
- }())
- } catch (e) {
- Exception(e, 'script error at addEventListener:')
- }
- VersionActions()
- if (!url.includes('.pdf')) { ShowMenu() }
- ConnectToServer(AfterLoad)
- }
-
- function Auth (pw) {
- SendXHRMessage('login', { pw: pw, script: true })
- .then((res) => {
- if (res.result === 'success') {
- ConnectToServer(AfterLoad)
- ClearAllMessages()
- resetMenu()
- } else {
- SafeGetElementById('infoMainDiv', (elem) => {
- elem.innerText = texts.invalidPW + pw
- })
- }
- })
- }
-
- function resetMenu () {
- SafeGetElementById('menuButtonDiv', (elem) => {
- elem.style.backgroundColor = '#262626'
- })
- SafeGetElementById('ircButton', (elem) => {
- elem.style.display = 'none'
- })
- SafeGetElementById('retryButton', (elem) => {
- elem.style.display = 'none'
- })
- SafeGetElementById('loginDiv', (elem) => {
- elem.style.display = 'none'
- })
- SafeGetElementById('infoMainDiv', (elem) => {
- elem.innerText = texts.loading
- })
- }
-
- function ConnectToServer (cwith) {
- ClearAllMessages()
- GetXHRInfos().then((inf) => {
- if (inf.result === 'nouser') {
- NoUserAction()
- return
- }
- lastestVersion = inf.version
- motd = inf.motd
- subjInfo = inf.subjinfo
- overlay.querySelector('#infoMainDiv').innerText = `${subjInfo.subjects} tárgy, ${subjInfo.questions} kérdés. Felh #${inf.uid}`
- // FIXME: if cwith() throws an unhandled error it sais server is not avaible
- cwith()
- }).catch(() => {
- NoServerAction()
- })
- }
-
- function NoUserAction () {
- SafeGetElementById('menuButtonDiv', (elem) => {
- elem.style.backgroundColor = '#44cc00'
- })
- SafeGetElementById('infoMainDiv', (elem) => {
- elem.innerText = texts.noUser
- if (getVal('clientId')) {
- elem.innerText += ` (${getVal('clientId')})`
- }
- })
- SafeGetElementById('loginDiv', (elem) => {
- elem.style.display = ''
- })
- }
-
- function NoServerAction () {
- SafeGetElementById('menuButtonDiv', (elem) => {
- elem.style.backgroundColor = 'red'
- })
- SafeGetElementById('infoMainDiv', (elem) => {
- elem.innerText = texts.noServer
- })
- SafeGetElementById('ircButton', (elem) => {
- elem.style.display = ''
- })
- SafeGetElementById('retryButton', (elem) => {
- elem.style.display = ''
- })
- Log(texts.noServerConsoleMessage)
- }
-
- function VersionActions () {
- // FOR TESTING ONLY
- // setVal("version15", true);
- // setVal("firstRun", true);
- // setVal("version16", true);
- // throw "asd";
-
- FreshStart()
- }
-
- // : Version action functions {{{
-
- function FreshStart () {
- var firstRun = getVal('firstRun') // if the current run is the frst
- if (firstRun === undefined || firstRun === true) {
- setVal('firstRun', false)
- ShowHelp() // showing help
-
- document.write(texts.freshStartWarning)
- document.close()
- throw new Error('something, so this stuff stops')
- }
- }
-
- // : }}}
-
- // : UI handling {{{
- function HandleUI (url) {
- // FIXME: normal string building with localisation :/
- var newVersion = false // if the script is newer than last start
-
- try {
- newVersion = info().script.version !== getVal('lastVerson')
- } catch (e) {
- Log('Some weird error trying to set new verison')
- }
-
- let showMOTD = false
- if (!SUtils.EmptyOrWhiteSpace(motd)) {
- var prevmotd = getVal('motd')
- if (prevmotd !== motd) {
- showMOTD = true
- setVal('motdcount', motdShowCount)
- setVal('motd', motd)
- } else {
- var motdcount = getVal('motdcount')
- if (motdcount === undefined) {
- setVal('motdcount', motdShowCount)
- motdcount = motdShowCount
+ return document
+ .getElementById("responseform")
+ .getElementsByTagName("p");
}
- motdcount--
- if (motdcount > 0) {
- showMOTD = true
- setVal('motdcount', motdcount)
- }
- }
- }
- let isNewVersionAvaible = lastestVersion !== undefined && info().script.version !== lastestVersion
- var greetMsg = '' // message to show at the end
- var timeout = null // the timeout. if null, it wont be hidden
-
- if (isNewVersionAvaible || newVersion || showMOTD) {
- greetMsg = 'Moodle/Elearning/KMOOC segéd v. ' + info().script.version + '. '
- }
- if (isNewVersionAvaible) {
- timeout = 5
- greetMsg += 'Új verzió elérhető: ' + lastestVersion
- timeout = undefined
- }
- if (newVersion) { // --------------------------------------------------------------------------------------------------------------
- greetMsg += 'Verzió frissítve ' + info().script.version + '-re. Changelog:\n' + texts.lastChangeLog
- setVal('lastVerson', info().script.version) // setting lastVersion
- }
- if (showMOTD) {
- greetMsg += '\nMOTD:\n' + motd
- timeout = null
- }
-
- ShowMessage({
- m: greetMsg,
- isSimple: true
- }, timeout) // showing message. If "m" is empty it wont show it, thats how showSplash works.
- }
-
- // : }}}
-
- // : Answering stuffs {{{
-
- function HandleQuiz () {
- var q = QPM.GetQuestionFromTest()
- var questions = q.q
- var imgNodes = q.imgnodes
- // ------------------------------------------------------------------------------------------------------
- let promises = []
- questions.forEach((x) => {
- let question = SUtils.EmptyOrWhiteSpace(x) ? '' : SUtils.RemoveUnnecesarySpaces(x) // simplifying question
- promises.push(GetXHRQuestionAnswer({
- q: question,
- data: GetImageDataFromImgNodes(imgNodes),
- subj: MPM.GetCurrentSubjectName()
- }))
- })
-
- // FIXME: promise.all promise resolve order same as original?
- Promise.all(promises).then((res) => {
- let answers = []
-
- res.forEach((result, j) => {
- var r = PrepareAnswers(result, j)
- if (r !== undefined) { answers.push(r) }
- HighLightAnswer(result, j) // highlights the answer for the current result
- })
-
- ShowAnswers(answers, q.q)
- })
- }
-
- function PrepareAnswers (result, j) {
- assert(result)
-
- if (result.length > 0) {
- var allMessages = [] // preparing all messages
- for (var k = 0; k < result.length; k++) {
- var msg = '' // the current message
- if ((getVal('showQuestions') === undefined) || getVal('showQuestions')) {
- msg += result[k].q.Q + '\n' // adding the question if yes
- }
- msg += result[k].q.A.replace(/, /g, '\n') // adding answer
- if (result[k].q.data.type === 'image') {
- msg += '\n\nKépek fenti válaszok sorrendjében: ' + result[k].q.data.images.join(', ') // if it has image part, adding that too
- }
- allMessages.push({
- m: msg,
- p: result[k].match
- })
- }
- return allMessages
- }
- }
-
- function ShowAnswers (answers, question) {
- assert(answers)
-
- if (answers.length > 0) { // if there are more than 0 answer
- ShowMessage(answers)
- } else {
- ShowMessage({
- m: texts.noResult,
- isSimple: true
- }, undefined, function () {
- OpenErrorPage({
- message: 'No result found',
- stack: JSON.stringify(question)
- })
- })
- }
- }
-
- // : }}}
-
- // : Quiz saving {{{
-
- function HandleResults (url) {
- SaveQuiz(
- GetQuiz(),
- ShowSaveQuizDialog
- ) // saves the quiz questions and answers
- }
-
- function ShowSaveQuizDialog (sendResult, sentData, newQuestions) {
- // FIXME: normal string building with localisation :/
- var msg = ''
- if (sendResult) {
- msg = 'Kérdések elküldve, katt az elküldött adatokért.'
- if (newQuestions > 0) {
- msg += ' ' + newQuestions + ' új kérdés'
- } else {
- msg += ' Nincs új kérdés'
- }
- } else {
- msg = 'Szerver nem elérhető, vagy egyéb hiba kérdések elküldésénél! (F12 -> Console)'
- }
- // showing a message wit the click event, and the generated page
- ShowMessage({
- m: msg,
- isSimple: true
- }, null, function () {
- let towrite = ''
- try {
- towrite += '
Elküldött adatok: ' + JSON.stringify(sentData)
- } catch (e) {
- towrite += 'Elküldött adatok: ' + sentData
- }
- document.write(towrite)
- document.close()
- })
- }
-
- // this should get the image url from a result page
- // i is the index of the question
- // FIXME: move this to RPM class ??? and refactor this
- function GetImageFormResult (i) {
- try {
- var imgElements = RPM.GetResultImage(i) // trying to get image
- var imgURL = [] // image urls
- for (var j = 0; j < imgElements.length; j++) {
- if (!imgElements[j].src.includes('brokenfile')) {
- var filePart = imgElements[j].src.split('/') // splits the link by "/"
- filePart = filePart[filePart.length - 1] // the last one is the image name
- imgURL.push(decodeURI(SUtils.ShortenString(filePart, 30)))
- }
- }
- if (imgURL.length > 0) {
- return imgURL
- }
- } catch (e) {
- Log("Couldn't get images from result")
- }
- }
-
- function GetDataFormResult (i) {
- let data = { type: 'simple' }
-
- let img = GetImageFormResult(i)
- let grabbox = RPM.GetAnswersFromGrabBox(i)
- if (img) {
- data = {
- type: 'image',
- images: img
- }
- }
- if (grabbox) {
- data = {
- type: 'grabbox',
- images: img,
- grabbox: grabbox
- }
- }
-
- return data
- }
-
- // saves the current quiz. questionData contains the active subjects questions
- function SaveQuiz (quiz, next) {
- try {
- let sentData = {}
- if (quiz.length === 0) {
- throw new Error('quiz length is zero!')
- }
- try {
- try {
- sentData.subj = MPM.GetCurrentSubjectName()
- } catch (e) {
- sentData.subj = 'NOSUBJ'
- Log('unable to get subject name :c')
- }
- sentData.version = info().script.version
- sentData.id = GetId()
- sentData.quiz = quiz
- console.log('SENT DATA', sentData)
- SendXHRMessage('isAdding', sentData).then((res) => {
- next(res.success, sentData, res.newQuestions)
- })
- } catch (e) {
- Exception(e, 'error at sending data to server.')
- }
- } catch (e) {
- Exception(e, 'script error at saving quiz')
- }
- }
-
- // getting quiz from finish page
- function GetQuiz () {
- try {
- var quiz = [] // final quiz stuff
- var results = RPM.GetFormResult() // getting results element
- for (var i = 0; i < results.length - 2; i++) {
- var question = {} // the current question
- // QUESTION --------------------------------------------------------------------------------------------------------------------
- question.Q = RPM.GetQuestionFromResult(i)
-
- // RIGHTANSWER ---------------------------------------------------------------------------------------------------------------------
- question.A = RPM.GetRightAnswerFromResultv2(i)
- if (question.A === undefined) { question.A = RPM.GetRightAnswerFromResult(i) }
- // DATA ---------------------------------------------------------------------------------------------------------------------
- question.data = GetDataFormResult(i)
-
- if (question.A !== undefined) {
- quiz.push(question) // adding current question to quiz
- } else {
- Log('error getting queston, no correct answer given, or its incorrect')
- Log(question)
- }
- }
- return quiz
- } catch (e) {
- Exception(e, 'script error at quiz parsing:')
- }
- }
-
- // : }}}
-
- // : Helpers {{{
-
- function GetImageDataFromImgNodes (imgs) {
- var questionImages = [] // the array for the image names in question
- for (var i = 0; i < imgs.length; i++) {
- if (!imgs[i].src.includes('brokenfile')) {
- var filePart = imgs[i].src.split('/') // splits the link by "/"
- filePart = filePart[filePart.length - 1] // the last one is the image name
- questionImages.push(decodeURI(SUtils.RemoveUnnecesarySpaces(SUtils.ShortenString(filePart, 30)))) // decodes uri codes, and removes exess spaces, and shortening it
- }
- }
- if (questionImages.length > 0) {
- return {
- type: 'image',
- images: questionImages
- }
- } else {
- return {
- type: 'simple'
- }
- }
- }
-
- // adds image names to image nodes
- function AddImageNamesToImages (imgs) {
- for (var i = 0; i < imgs.length; i++) {
- if (!imgs[i].src.includes('brokenfile')) {
- var filePart = imgs[i].src.split('/') // splits the link by "/"
- filePart = filePart[filePart.length - 1] // the last one is the image name
- var appedtTo = imgs[i].parentNode // it will be appended here
- var mainDiv = document.createElement('div')
- var fileName = SUtils.ShortenString(decodeURI(filePart), 15) // shortening name, couse it can be long as fuck
- var textNode = document.createTextNode('(' + fileName + ')')
- mainDiv.appendChild(textNode)
- appedtTo.appendChild(mainDiv)
- }
- }
- }
-
- // this function adds basic hotkeys for video controll.
- function AddVideoHotkeys (url) {
- var seekTime = 20
- document.addEventListener('keydown', function (e) {
- try {
- var video = MPM.GetVideo()
- var keyCode = e.keyCode // getting keycode
- if (keyCode === 32) { // if the keycode is 32 (space)
- e.preventDefault() // preventing default action (space scrolles down)
- if (video.paused && video.buffered.length > 0) {
- video.play()
- } else {
- video.pause()
- }
- }
- if (keyCode === 39) { // rigth : 39
- video.currentTime += seekTime
- }
- if (keyCode === 37) { // left : 37
- video.currentTime -= seekTime
- }
- } catch (err) {
- Log('Hotkey error.')
- Log(err.message)
- }
- })
- var toadd = MPM.GetVideoElement()
- var node = CreateNodeWithText(toadd, texts.videoHelp)
- node.style.margin = '5px 5px 5px 5px' // fancy margin
- }
-
- // removes stuff like " a. q1" -> "q1"
- function RemoveLetterMarking (inp) {
- let dotIndex = inp.indexOf('.')
- let doubledotIndex = inp.indexOf(':')
- let maxInd = 4 // inp.length * 0.2;
-
- if (dotIndex < maxInd) { return SUtils.RemoveUnnecesarySpaces(inp.substr(inp.indexOf('.') + 1, inp.length)) } else if (doubledotIndex < maxInd) { return SUtils.RemoveUnnecesarySpaces(inp.substr(inp.indexOf(':') + 1, inp.length)) } else { return inp }
- }
-
- // highlights the possible solutions to the current question
- function HighLightAnswer (results, currQuestionNumber) {
- try {
- if (results.length > 0) {
- var answers = RPM.GetAllAnswer(currQuestionNumber) // getting all answers
- var toColor = [] // the numberth in the array will be colored, and .length items will be colored
- var type = '' // type of the question. radio or ticbox or whatitscalled
- for (let i = 0; i < answers.length; i++) { // going thtough answers
- if (answers[i].tagName && answers[i].tagName.toLowerCase() === 'div') { // if its not null and is "div"
- var correct = results[0].q.A.toLowerCase() // getting current correct answer from data
- var answer = answers[i].innerText.replace(/\n/g, '').toLowerCase() // getting current answer
-
- // removing stuff like "a."
- answer = RemoveLetterMarking(answer)
-
- if (SUtils.EmptyOrWhiteSpace(correct) || SUtils.EmptyOrWhiteSpace(answer)) { continue }
-
- if (SUtils.NormalizeSpaces(SUtils.RemoveUnnecesarySpaces(correct)).includes(answer)) { // if the correct answer includes the current answer
- toColor.push(i) // adding the index
- type = MPM.GetInputType(answers, i) // setting the type
+ GetFormulationClearfix() {
+ if (logElementGetting) {
+ Log("getting formulation clearfix lol");
}
- }
+ return document.getElementsByClassName("formulation clearfix");
}
- if (results[0].match === 100) { // if the result is 100% correct
- if (type !== 'radio' || toColor.length === 1) { // FIXME why not radio
- for (let i = 0; i < toColor.length; i++) { // going through "toColor"
- let highlight = createHoverOver(answers[toColor[i]]);
- Object.assign(highlight.style, {
- border: "7px solid rgba(100, 240, 100, 0.8)",
- borderRadius: "10px",
- margin: "-13px 0 0 -8px"
- });
+
+ GetAnswerOptions() {
+ if (logElementGetting) {
+ Log("getting all answer options");
}
- }
- } // and coloring the correct index
- }
- } catch (e) { // catching errors. Sometimes there are random errors, wich i did not test, but they are rare, and does not break the main script.
- Log('script error at highlightin answer: ' + e.message)
- }
- }
-
- // : }}}
-
- function Log (value) {
- if (log) { console.log(value) }
- }
-
- function Exception (e, msg) {
- Log('------------------------------------------')
- Log(msg)
- Log(e.message)
- Log('------------------------------------------')
- Log(e.stack)
- Log('------------------------------------------')
- }
-
- // : }}}
-
- // : Minor UI stuff {{{
- function ClearAllMessages () {
- overlay.querySelectorAll('#scriptMessage').forEach(x => x.remove())
- }
-
- // shows a message with "msg" text, "matchPercent" tip and transp, and "timeout" time
- function ShowMessage (msgItem, timeout, funct) {
- // msgItem help:
- // [ [ {}{}{}{} ] [ {}{}{} ] ]
- // msgItem[] <- a questions stuff
- // msgItem[][] <- a questions relevant answers array
- // msgItem[][].p <- a questions precent
- // msgItem[][].m <- a questions message
- try {
- var defMargin = '0px 5px 0px 5px'
- var isSimpleMessage = false
- var simpleMessageText = ''
- if (msgItem.isSimple) { // parsing msgItem for easier use
- simpleMessageText = msgItem.m
- if (simpleMessageText === '') { // if msg is empty
- return
- }
- msgItem = [
- [{
- m: simpleMessageText
- }]
- ]
- isSimpleMessage = true
- }
-
- var appedtTo = overlay // will be appended here
- var width = window.innerWidth - window.innerWidth / 6 // with of the box
- var startFromTop = 25 // top distance
-
- var mainDiv = document.createElement('div') // the main divider, wich items will be attached to
- mainDiv.setAttribute('id', 'messageMainDiv')
- if (funct) { // if there is a function as parameter
- addEventListener(mainDiv, 'click', funct) // adding it as click
- }
- // lotsa crap style
- SetStyle(mainDiv, {
- position: 'fixed',
- zIndex: 999999,
- textAlign: 'center',
- width: width + 'px',
- padding: '0px',
- background: '#222d32',
- color: '#ffffff',
- borderColor: '#035a8f',
- border: 'none',
- top: (startFromTop) + 'px',
- left: (window.innerWidth - width) / 2 + 'px',
- opacity: '0.9'
- })
- mainDiv.setAttribute('id', 'scriptMessage')
- var matchPercent = msgItem[0][0].p
- if (isSimpleMessage) {
- var simpleMessageParagrapg = document.createElement('p') // new paragraph
- simpleMessageParagrapg.style.margin = defMargin // fancy margin
-
- var mesageNode = document.createElement('p') // new paragraph
- mesageNode.innerHTML = simpleMessageText.replace(/\n/g, '')
- simpleMessageParagrapg.appendChild(mesageNode)
- mesageNode.style.margin = defMargin // fancy margin
-
- mainDiv.appendChild(simpleMessageParagrapg) // adding text box to main div
- } else { // if its a fucking complicated message
- // TABLE SETUP ------------------------------------------------------------------------------------------------------------
- var table = document.createElement('table')
- table.style.width = '100%'
- // ROWS -----------------------------------------------------------------------------------------------------
- var rowOne = table.insertRow() // previous suggestion, question text, and prev question
- var rowTwo = table.insertRow() // next question button
- var rowThree = table.insertRow() // next suggetsion button
- // CELLS -----------------------------------------------------------------------------------------------------
- // row one
- var numberTextCell = rowOne.insertCell()
- var questionCell = rowOne.insertCell() // QUESTION CELL
- questionCell.setAttribute('id', 'questionCell')
- questionCell.rowSpan = 3
- questionCell.style.width = '90%'
- var prevQuestionCell = rowOne.insertCell()
- // row two
- var percentTextCell = rowTwo.insertCell()
- var nextQuestionCell = rowTwo.insertCell()
- // row three
- var prevSuggestionCell = rowThree.insertCell()
- var nextSuggestionCell = rowThree.insertCell()
- // adding finally
- mainDiv.appendChild(table)
- // PERCENT TEXT SETUP -----------------------------------------------------------------------------------------------------
- var percentTextBox = CreateNodeWithText(percentTextCell, '')
- percentTextBox.setAttribute('id', 'percentTextBox')
-
- if (matchPercent) { // if match percent param is not null
- percentTextBox.innerText = matchPercent + '%'
- }
- // NUMBER SETUP -----------------------------------------------------------------------------------------------------
- var numberTextBox = CreateNodeWithText(numberTextCell, '1.')
- numberTextBox.setAttribute('id', 'numberTextBox')
-
- // ANSWER NODE SETUP -------------------------------------------------------------------------------------------------------------
- var questionTextElement = CreateNodeWithText(questionCell, 'ur question goes here, mister OwO')
- questionTextElement.setAttribute('id', 'questionTextElement')
-
- // BUTTON SETUP -----------------------------------------------------------------------------------------------------------
- var currItem = 0
- var currRelevantQuestion = 0
-
- const GetRelevantQuestion = () => { // returns the currItemth questions currRelevantQuestionth relevant question
- return msgItem[currItem][currRelevantQuestion]
+ return this.GetFormulationClearfix()[0].childNodes[3].innerText;
}
- const ChangeCurrItemIndex = (to) => {
- currItem += to
- if (currItem < 0) {
- currItem = 0
- }
- if (currItem > msgItem.length - 1) {
- currItem = msgItem.length - 1
- }
- currRelevantQuestion = 0
+ GetQuestionImages() {
+ if (logElementGetting) {
+ Log("getting question images");
+ }
+ return this.GetFormulationClearfix()[0].getElementsByTagName("img");
}
- const ChangeCurrRelevantQuestionIndex = (to) => {
- currRelevantQuestion += to
- if (currRelevantQuestion < 0) {
- currRelevantQuestion = 0
- }
- if (currRelevantQuestion > msgItem[currItem].length - 1) {
- currRelevantQuestion = msgItem[currItem].length - 1
- }
- }
-
- const SetQuestionText = () => {
- var relevantQuestion = GetRelevantQuestion()
- questionTextElement.innerText = relevantQuestion.m
- if (currItem === 0 && currRelevantQuestion === 0) {
- numberTextBox.innerText = (currRelevantQuestion + 1) + '.'
- } else {
- numberTextBox.innerText = (currItem + 1) + './' + (currRelevantQuestion + 1) + '.'
- }
- percentTextBox.innerText = relevantQuestion.p + '%'
- }
-
- var buttonMargin = '2px 2px 2px 2px' // uniform button margin
- if (msgItem[currItem].length > 1) {
- // PREV SUGG BUTTON ------------------------------------------------------------------------------------------------------------
- var prevSuggButton = CreateNodeWithText(prevSuggestionCell, '<', 'button')
- prevSuggButton.style.margin = buttonMargin // fancy margin
-
- prevSuggButton.addEventListener('click', function () {
- ChangeCurrRelevantQuestionIndex(-1)
- SetQuestionText()
- })
- // NEXT SUGG BUTTON ------------------------------------------------------------------------------------------------------------
- var nextSuggButton = CreateNodeWithText(nextSuggestionCell, '>', 'button')
- nextSuggButton.style.margin = buttonMargin // fancy margin
-
- nextSuggButton.addEventListener('click', function () {
- ChangeCurrRelevantQuestionIndex(1)
- SetQuestionText()
- })
- }
- // deciding if has multiple questions ------------------------------------------------------------------------------------------------
- if (msgItem.length === 1) {
- SetQuestionText()
- } else { // if there are multiple items to display
- // PREV QUESTION BUTTON ------------------------------------------------------------------------------------------------------------
- var prevButton = CreateNodeWithText(prevQuestionCell, '^', 'button')
- prevButton.style.margin = buttonMargin // fancy margin
-
- // event listener
- prevButton.addEventListener('click', function () {
- ChangeCurrItemIndex(-1)
- SetQuestionText()
- })
- // NEXT QUESTION BUTTON ------------------------------------------------------------------------------------------------------------
- var nextButton = CreateNodeWithText(nextQuestionCell, 'ˇ', 'button')
- nextButton.style.margin = buttonMargin // fancy margin
-
- // event listener
- nextButton.addEventListener('click', function () {
- ChangeCurrItemIndex(1)
- SetQuestionText()
- })
- SetQuestionText()
- }
- }
- appedtTo.appendChild(mainDiv) // THE FINAL APPEND
-
- // setting some events
- // addEventListener(window, 'scroll', function () {
- // mainDiv.style.top = (pageYOffset + startFromTop) + 'px';
- // })
- addEventListener(window, 'resize', function () {
- mainDiv.style.left = (window.innerWidth - width) / 2 + 'px'
- })
- var timeOut
- if (timeout && timeout > 0) { // setting timeout if not zero or null
- timeOut = setTimeout(function () {
- mainDiv.parentNode.removeChild(mainDiv)
- }, timeout * 1000)
- }
- // middle click close event listener
- addEventListener(mainDiv, 'mousedown', function (e) {
- if (e.which === 2) {
- mainDiv.parentNode.removeChild(mainDiv)
- if (timeOut) {
- clearTimeout(timeOut)
- }
- }
- })
- } catch (e) {
- Exception(e, 'script error at showing message:')
- }
- }
-
- // shows a fancy menu
- function ShowMenu () {
- try {
- var appedtTo = overlay // will be appended here
-
- // mainDiv.style.left = (window.innerWidth - width) / 2 + 'px';
-
- var menuButtonDiv = document.createElement('div')
- menuButtonDiv.setAttribute('id', 'menuButtonDiv')
- SetStyle(menuButtonDiv, {
- width: '600px',
- // height: buttonHeight + 'px',
- top: (window.innerHeight - 120) + 'px',
- left: '10px',
- zIndex: 999999,
- position: 'fixed',
- textAlign: 'center',
- padding: '0px',
- margin: '0px',
- background: '#262626'
- })
-
- var tbl = document.createElement('table')
- tbl.style.margin = '5px 5px 5px 5px'
- tbl.style.textAlign = 'left'
- tbl.style.width = '98%'
- menuButtonDiv.appendChild(tbl)
-
- var buttonRow = tbl.insertRow()
- var buttonCell = buttonRow.insertCell()
- buttonCell.style.textAlign = 'center'
-
- let buttonStyle = {
- position: '',
- margin: '5px 5px 5px 5px',
- border: 'none',
- backgroundColor: '#222d32',
- color: '#ffffff',
- cursor: 'pointer'
- }
- // help button ----------------------------------------------------------------------------------------------------------------
- let helpButton = CreateNodeWithText(buttonCell, texts.help, 'button')
- SetStyle(helpButton, buttonStyle)
-
- helpButton.addEventListener('click', function () {
- ShowHelp()
- }) // adding clicktextNode
-
- // site link ----------------------------------------------------------------------------------------------------------------
-
- let contributeLink = CreateNodeWithText(buttonCell, texts.contribute, 'button')
- contributeLink.title = texts.contributeTitle
- SetStyle(contributeLink, buttonStyle)
-
- contributeLink.addEventListener('click', function () {
- openInTab(serverAdress + 'contribute?scriptMenu', {
- active: true
- })
- })
-
- // pw request ----------------------------------------------------------------------------------------------------------------
-
- let pwRequest = CreateNodeWithText(buttonCell, texts.pwRequest, 'button')
- pwRequest.title = texts.newPWTitle
- SetStyle(pwRequest, buttonStyle)
-
- pwRequest.addEventListener('click', function () {
- openInTab(serverAdress + 'pwRequest', {
- active: true
- })
- })
-
- // site link ----------------------------------------------------------------------------------------------------------------
-
- let siteLink = CreateNodeWithText(buttonCell, texts.websiteBugreport, 'button')
- SetStyle(siteLink, buttonStyle)
-
- siteLink.addEventListener('click', function () {
- openInTab(serverAdress + 'menuClick', {
- active: true
- })
- })
-
- // donate link ----------------------------------------------------------------------------------------------------------------
- let donateLink = CreateNodeWithText(buttonCell, texts.donate, 'button')
- SetStyle(donateLink, buttonStyle)
-
- donateLink.addEventListener('click', function () {
- openInTab(serverAdress + 'donate?scriptMenu', {
- active: true
- })
- })
-
- addEventListener(window, 'resize', function () {
- menuButtonDiv.style.top = (window.innerHeight - 70) + 'px'
- })
-
- // INFO TABEL --------------------------------------------------------------------
- var itbl = document.createElement('table')
- SetStyle(itbl, {
- margin: '5px 5px 5px 5px',
- textAlign: 'left',
- width: '98%'
- })
- menuButtonDiv.appendChild(itbl)
- var ibuttonRow = tbl.insertRow()
- var ibuttonCell = ibuttonRow.insertCell()
- ibuttonCell.style.textAlign = 'center'
-
- // INFO DIV ---------------------------------------------------------------------------------
- let infoDiv = CreateNodeWithText(ibuttonCell, texts.loading, 'span')
- infoDiv.setAttribute('id', 'infoMainDiv')
- SetStyle(infoDiv, {
- color: '#ffffff',
- margin: '5px'
- })
-
- // login div ----------------------------------------------------------------------------------------------------------------
- const loginDiv = document.createElement('div')
- loginDiv.style.display = 'none'
- loginDiv.setAttribute('id', 'loginDiv')
- const loginButton = document.createElement('button')
- loginButton.innerText = texts.login
- const loginInput = document.createElement('input')
- loginInput.type = 'text'
- loginInput.style.width = '400px'
- loginInput.style.textAlign = 'center'
- const clientId = getVal('clientId')
- if (clientId && clientId.toString()[0] !== '0') {
- loginInput.value = clientId || ''
- loginButton.innerText = texts.requestPWInsteadOfLogin
- }
- loginDiv.appendChild(loginInput)
- loginDiv.appendChild(loginButton)
-
- SetStyle(loginButton, buttonStyle)
-
- loginInput.addEventListener('keyup', (e) => {
- console.log(e.target.value)
- if (e.target.value === clientId) {
- loginButton.innerText = texts.requestPWInsteadOfLogin
- } else if (e.target.value !== '') {
- loginButton.innerText = texts.login
- }
- })
-
- loginButton.addEventListener('click', function () {
- if (loginInput.value === clientId.toString()) {
- openInTab(serverAdress + 'getVeteranPw?cid=' + clientId, {
- active: true
- })
- } else {
- Auth(loginInput.value)
- }
- })
-
- ibuttonCell.appendChild(loginDiv)
-
- // irc button ----------------------------------------------------------------------------------------------------------------
- let ircButton = CreateNodeWithText(ibuttonCell, texts.ircButton, 'button')
- SetStyle(ircButton, buttonStyle)
- ircButton.style.display = 'none'
- ircButton.setAttribute('id', 'ircButton')
-
- ircButton.addEventListener('click', function () {
- openInTab(ircAddress, {
- active: true
- })
- })
-
- // retry button ----------------------------------------------------------------------------------------------------------------
- let retryButton = CreateNodeWithText(ibuttonCell, texts.retry, 'button')
- SetStyle(retryButton, buttonStyle)
- retryButton.style.display = 'none'
- retryButton.setAttribute('id', 'retryButton')
-
- retryButton.addEventListener('click', function () {
- menuButtonDiv.style.background = '#262626'
- infoDiv.innerText = texts.loading
- retryButton.style.display = 'none'
- ircButton.style.display = 'none'
- ConnectToServer(AfterLoad)
- })
-
- // window resize event listener ---------------------------------------
- addEventListener(window, 'resize', function () {
- menuButtonDiv.style.top = (window.innerHeight - 70) + 'px'
- })
-
- // APPEND EVERYTHING
- appedtTo.appendChild(menuButtonDiv)
- } catch (e) {
- Exception(e, 'script error at showing menu:')
- }
- }
-
- // : }}}
-
- // : Generic utils {{{
- function GetId () {
- let currId = getVal('clientId')
- if (currId) {
- return currId
- } else {
- currId = new Date()
- currId = currId.getTime() + Math.floor(Math.random() * 1000000000000)
- currId = currId.toString().split('')
- currId.shift()
- currId = '0' + currId.join('')
- setVal('clientId', currId)
- return currId
- }
- }
-
- function SafeGetElementById (id, next) {
- let element = overlay.querySelector('#' + id)
- if (element) {
- next(element)
- } else {
- Log(`Unable to safe get element by id: ${id}`)
- }
- }
-
- function SetStyle (target, style) {
- Object.keys(style).sort().forEach((key) => {
- target.style[key] = style[key]
- })
- }
-
- function CreateNodeWithText (to, text, type) {
- var paragraphElement = document.createElement(type || 'p') // new paragraph
- var textNode = document.createTextNode(text)
- paragraphElement.appendChild(textNode)
- to.appendChild(paragraphElement)
- return paragraphElement
- }
-
- function GetXHRInfos () {
- const now = new Date().getTime()
- const lastCheck = getVal('lastInfoCheckTime')
- if (!lastCheck) {
- setVal('lastInfoCheckTime', now)
- }
-
- let lastInfo = { result: 'noLastInfo' }
- try {
- lastInfo = JSON.parse(getVal('lastInfo'))
- } catch (e) {
- }
- if (lastInfo.result !== 'success' || now > lastCheck + (infoExpireTime * 1000)) {
- return new Promise((resolve, reject) => {
- const url = apiAdress +
- 'infos?version=true&motd=true&subjinfo=true&cversion=' +
- info().script.version +
- '&cid=' + GetId()
-
- xmlhttpRequest({
- method: 'GET',
- url: url,
- crossDomain: true,
- xhrFields: { withCredentials: true },
- headers: {
- 'Content-Type': 'application/json'
- },
- onload: function (response) {
+ // this function should return the question, posible answers, and image names
+ GetQuestionFromTest() {
+ var questions; // the important questions
+ var allQuestions; // all questions
try {
- setVal('lastInfoCheckTime', now)
- const res = JSON.parse(response.responseText)
- setVal('lastInfo', response.responseText)
- resolve(res)
+ allQuestions = this.GetAllQuestionsQtext(); // getting questions
+ if (allQuestions.length === 0) {
+ var ddq = this.GetAllQuestionsDropdown();
+ if (SUtils.EmptyOrWhiteSpace(ddq)) {
+ var questionData = "";
+ for (var j = 0; j < allQuestions.length; j++) {
+ let subAllQuestions = allQuestions[j].childNodes;
+ for (let i = 0; i < subAllQuestions.length; i++) {
+ if (
+ subAllQuestions[i].data !== undefined &&
+ !SUtils.EmptyOrWhiteSpace(
+ subAllQuestions[i].data
+ )
+ ) {
+ questionData +=
+ subAllQuestions[i].data + " "; // adding text to question data
+ }
+ }
+ }
+ questions = [questionData];
+ } else {
+ questions = [ddq];
+ }
+ } else {
+ questions = [];
+ for (let i = 0; i < allQuestions.length; i++) {
+ questions.push(allQuestions[i].innerText);
+ }
+ }
} catch (e) {
- Log('Errro paring JSON in GetXHRInfos')
- Log(e)
- reject(e)
+ Exception(e, "script error at getting question:");
}
- },
- onerror: (e) => {
- Log('Info get Error', e)
- reject(e)
- }
- })
- })
- } else {
- return new Promise((resolve, reject) => {
+ var imgNodes = ""; // the image nodes for questions
+ try {
+ imgNodes = this.GetQuestionImages(); // getting question images, if there is any
+ AddImageNamesToImages(imgNodes); // adding image names to images, so its easier to search for, or even guessing
+ } catch (e) {
+ Log(e);
+ Log("Some error with images");
+ }
+
+ questions = questions.map(item => {
+ if (item) {
+ return SUtils.ReplaceCharsWithSpace(item, "\n");
+ }
+ });
+
+ return {
+ imgnodes: imgNodes,
+ allQ: allQuestions,
+ q: questions,
+ };
+ }
+ }
+
+ class ResultsPageModell {
+ GetFormulationClearfix() {
+ if (logElementGetting) {
+ Log("getting formulation clearfix lol");
+ }
+ return document.getElementsByClassName("formulation clearfix");
+ }
+
+ GetGrade(i) {
+ if (logElementGetting) {
+ Log("getting grade");
+ }
+ const fcf = QPM.GetFormulationClearfix()[i];
+ return fcf.parentNode.parentNode.childNodes[0].childNodes[2]
+ .innerText;
+ }
+
+ DetermineQuestionType(nodes) {
+ let qtype = "";
+ let i = 0;
+
+ while (i < nodes.length && qtype === "") {
+ let inps = nodes[i].getElementsByTagName("input");
+
+ if (inps.length > 0) {
+ qtype = inps[0].type;
+ }
+
+ i++;
+ }
+
+ return qtype;
+ }
+
+ GetSelectAnswer(i) {
+ if (logElementGetting) {
+ Log("getting selected answer");
+ }
+ var t = document.getElementsByTagName("select");
+ if (t.length > 0) {
+ return t[i].options[t[i].selectedIndex].innerText;
+ }
+ }
+
+ GetCurrQuestion(i) {
+ if (logElementGetting) {
+ Log("getting curr questions by index: " + i);
+ }
+ return document.getElementsByTagName("form")[0].childNodes[0]
+ .childNodes[i].childNodes[1].childNodes[0].innerText;
+ }
+
+ GetFormResult() {
+ if (logElementGetting) {
+ Log("getting form result");
+ }
+ var t = document.getElementsByTagName("form")[0].childNodes[0]
+ .childNodes;
+ if (t.length > 0 && t[0].tagName === undefined) {
+ // debreceni moodle
+ return document.getElementsByTagName("form")[1].childNodes[0]
+ .childNodes;
+ } else {
+ return t;
+ }
+ }
+
+ GetAnswerNode(i) {
+ if (logElementGetting) {
+ Log("getting answer node");
+ }
+
+ var results = this.GetFormResult(); // getting results element
+
+ var r = results[i].getElementsByClassName("answer")[0].childNodes;
+ var ret = [];
+ for (var j = 0; j < r.length; j++) {
+ if (
+ r[j].tagName !== undefined &&
+ r[j].tagName.toLowerCase() === "div"
+ ) {
+ ret.push(r[j]);
+ }
+ }
+
+ let qtype = this.DetermineQuestionType(ret);
+
+ return {
+ nodes: ret,
+ type: qtype,
+ };
+ }
+
+ GetCurrentAnswer(i) {
+ if (logElementGetting) {
+ Log("getting curr answer by index: " + i);
+ }
+ var results = this.GetFormResult(); // getting results element
+ var t = results[i]
+ .getElementsByClassName("formulation clearfix")[0]
+ .getElementsByTagName("span");
+ if (t.length > 2) {
+ return t[1].innerHTML.split("
")[1];
+ }
+ }
+
+ GetQText(i) {
+ if (logElementGetting) {
+ Log("getting qtext by index: " + i);
+ }
+ var results = this.GetFormResult(); // getting results element
+ return results[i].getElementsByClassName("qtext");
+ }
+
+ GetDropboxes(i) {
+ if (logElementGetting) {
+ Log("getting dropboxes by index: " + i);
+ }
+ var results = this.GetFormResult(); // getting results element
+ return results[i].getElementsByTagName("select");
+ }
+
+ GetAllAnswer(index) {
+ if (logElementGetting) {
+ Log("getting all answers, ind: " + index);
+ }
+ return document.getElementsByClassName("answer")[index].childNodes;
+ }
+
+ GetPossibleAnswers(i) {
+ if (logElementGetting) {
+ Log("getting possible answers");
+ }
+ var results = this.GetFormResult(); // getting results element
+ var items = results[i].getElementsByTagName("label");
+ var r = [];
+ for (var j = 0; j < items.length; j++) {
+ const TryGetCorrect = j => {
+ var cn = items[j].parentNode.className;
+ if (cn.includes("correct")) {
+ return (
+ cn.includes("correct") && !cn.includes("incorrect")
+ );
+ }
+ };
+ r.push({
+ value: items[j].innerText,
+ iscorrect: TryGetCorrect(j),
+ });
+ }
+ return r;
+ }
+
+ GetAnswersFromGrabBox(i) {
+ try {
+ if (logElementGetting) {
+ Log("testing if question is grab-box");
+ }
+ let results = this.GetFormResult(); // getting results element
+ let t = results[i].getElementsByClassName("dragitems")[0]
+ .childNodes;
+ if (t.length !== 1) {
+ Log("grab box drag items group length is not 1!");
+ Log(results[i].getElementsByClassName("dragitems")[0]);
+ }
+ let placedItems = t[0].getElementsByClassName("placed");
+ let res = [];
+ for (let i = 0; i < placedItems.length; i++) {
+ let item = placedItems[i];
+ res.push({
+ text: item.innerText,
+ left: item.style.left,
+ top: item.style.top,
+ });
+ }
+ return res;
+ } catch (e) {
+ console.info(e);
+ }
+ }
+
+ GetRightAnswerIfCorrectShown(i) {
+ if (logElementGetting) {
+ Log("getting right answer if correct shown");
+ }
+ var results = this.GetFormResult(); // getting results element
+ return results[i].getElementsByClassName("rightanswer");
+ }
+
+ GetWrongAnswerIfCorrectNotShown(i) {
+ if (logElementGetting) {
+ Log("getting wrong answer if correct not shown");
+ }
+ var results = this.GetFormResult(); // getting results element
+ var n = results[i].getElementsByTagName("i")[0].parentNode;
+ if (n.className.includes("incorrect")) {
+ return results[i].getElementsByTagName("i")[0].parentNode
+ .innerText;
+ } else {
+ return "";
+ }
+ }
+
+ GetRightAnswerIfCorrectNotShown(i) {
+ if (logElementGetting) {
+ Log("Getting right answer if correct not shown");
+ }
+ var results = this.GetFormResult(); // getting results element
+ var n = results[i].getElementsByTagName("i")[0].parentNode;
+ if (
+ n.className.includes("correct") &&
+ !n.className.includes("incorrect")
+ ) {
+ return results[i].getElementsByTagName("i")[0].parentNode
+ .innerText;
+ }
+ }
+
+ GetFormCFOfResult(result) {
+ if (logElementGetting) {
+ Log("getting formulation clearfix");
+ }
+ return result.getElementsByClassName("formulation clearfix")[0];
+ }
+
+ GetResultText(i) {
+ if (logElementGetting) {
+ Log("getting result text");
+ }
+ var results = this.GetFormResult(); // getting results element
+ return this.GetFormCFOfResult(results[i]).getElementsByTagName("p");
+ }
+
+ GetResultImage(i) {
+ if (logElementGetting) {
+ Log("getting result image");
+ }
+ var results = this.GetFormResult(); // getting results element
+ return this.GetFormCFOfResult(results[i]).getElementsByTagName(
+ "img"
+ );
+ }
+
+ // gets the question from the result page
+ // i is the index of the question
+ GetQuestionFromResult(i) {
+ var temp = this.GetQText(i);
+ var currQuestion = "";
+ if (temp.length > 0) {
+ currQuestion = temp[0].innerText; // adding the question to curr question as .q
+ } else {
+ // this is black magic fuckery a bit
+ if (this.GetDropboxes(i).length > 0) {
+ var allNodes = this.GetResultText(i);
+ currQuestion = "";
+ for (var k = 0; k < allNodes.length; k++) {
+ var allQuestions = this.GetResultText(i)[k].childNodes;
+ for (var j = 0; j < allQuestions.length; j++) {
+ if (
+ allQuestions[j].data !== undefined &&
+ !SUtils.EmptyOrWhiteSpace(allQuestions[j].data)
+ ) {
+ currQuestion += allQuestions[j].data + " ";
+ }
+ }
+ }
+ } else {
+ try {
+ currQuestion = this.GetCurrQuestion(i);
+ } catch (e) {
+ currQuestion = "REEEEEEEEEEEEEEEEEEEEE"; // this shouldnt really happen sry guys
+ Log("Unable to get question in GetQuestionFromResult");
+ }
+ }
+ }
+ return currQuestion;
+ }
+
+ // tries to get right answer from result page
+ // i is the index of the question
+ GetRightAnswerFromResult(i) {
+ var fun = [];
+
+ // "húzza oda ..." skip
+ fun.push(i => {
+ let temp = RPM.GetAnswersFromGrabBox(i);
+ return temp
+ .map(x => {
+ return x.text;
+ })
+ .join(", ");
+ });
+
+ // the basic type of getting answers
+ fun.push(i => {
+ var temp = RPM.GetRightAnswerIfCorrectShown(i); // getting risht answer
+ if (temp.length > 0) {
+ return temp[0].innerText;
+ } // adding the answer to curr question as .a
+ });
+
+ // if there is dropdown list in the current question
+ fun.push(i => {
+ if (RPM.GetDropboxes(i).length > 0) {
+ return RPM.GetCurrentAnswer(i);
+ }
+ });
+
+ // if the correct answers are not shown, and the selected answer
+ // is correct
+ fun.push(i => {
+ return RPM.GetRightAnswerIfCorrectNotShown(i);
+ });
+
+ // if there is dropbox in the question
+ fun.push(i => {
+ return RPM.GetSelectAnswer(i);
+ });
+
+ // if the correct answers are not shown, and the selected answer
+ // is incorrect, and there are only 2 options
+ fun.push(i => {
+ var possibleAnswers = RPM.GetPossibleAnswers(i);
+ if (possibleAnswers.length === 2) {
+ for (var k = 0; k < possibleAnswers.length; k++) {
+ if (possibleAnswers[k].iscorrect === undefined) {
+ return possibleAnswers[k].value;
+ }
+ }
+ }
+ });
+
+ // if everything fails
+ fun.push(i => {
+ return undefined;
+ });
+
+ var j = 0;
+ var currAnswer;
+ while (j < fun.length && SUtils.EmptyOrWhiteSpace(currAnswer)) {
+ try {
+ currAnswer = fun[j](i);
+ } catch (e) {
+ console.info(e);
+ }
+ j++;
+ }
+
+ return currAnswer;
+ }
+
+ GuessCorrectIn2LengthAnswersByIncorrect(items) {
+ const first = items[0];
+ const second = items[1];
+ if (first.className.includes("incorrect")) {
+ return second.innerText;
+ }
+ if (second.className.includes("incorrect")) {
+ return first.innerText;
+ }
+ }
+
+ GuessCorrectIn2LengthAnswersByPoints(i, items) {
+ const first = {
+ elem: items[0],
+ val: items[0].childNodes[0].checked,
+ text: items[0].innerText,
+ };
+ const second = {
+ elem: items[1],
+ val: items[1].childNodes[0].checked,
+ text: items[1].innerText,
+ };
+
+ const grade = RPM.GetGrade(i); // 1,00 közül 1,00 leosztályozva
+ const grades = grade.split(" ").reduce((acc, text) => {
+ if (text.includes(",")) {
+ // FIXME: fancy regexp
+ acc.push(parseInt(text));
+ } else if (text.includes(".")) {
+ // FIXME: fancy regexp
+ acc.push(parseInt(text));
+ }
+ return acc;
+ }, []);
+
+ if (grades[0] === 1) {
+ if (first.val) {
+ return first.text;
+ } else {
+ return second.text;
+ }
+ } else {
+ if (!first.val) {
+ return first.text;
+ } else {
+ return second.text;
+ }
+ }
+ }
+
+ // version 2 of getting right answer from result page
+ // i is the index of the question
+ GetRightAnswerFromResultv2(i) {
+ try {
+ var answerNodes = this.GetAnswerNode(i);
+ let items = answerNodes.nodes;
+
+ if (answerNodes.type === "checkbox") {
+ return RPM.GetRightAnswerFromResult(i);
+ }
+
+ for (let j = 0; j < items.length; j++) {
+ let cn = items[j].className;
+ if (cn.includes("correct") && !cn.includes("incorrect")) {
+ return items[j].getElementsByTagName("label")[0]
+ .innerText;
+ }
+ }
+ if (items.length === 2) {
+ const resByIncorrect = this.GuessCorrectIn2LengthAnswersByIncorrect(
+ items
+ );
+ if (!resByIncorrect) {
+ const resPoints = this.GuessCorrectIn2LengthAnswersByPoints(
+ i,
+ items
+ );
+ return resPoints;
+ }
+ return resByIncorrect;
+ }
+ } catch (e) {
+ Log("error at new nodegetting, trying the oldschool way");
+ }
+ }
+ }
+
+ class MiscPageModell {
+ GetCurrentSubjectName() {
+ if (logElementGetting) {
+ Log("getting current subjects name");
+ }
+ return (
+ document
+ .getElementById("page-header")
+ .innerText.split("\n")[0] || ""
+ );
+ }
+
+ GetVideo() {
+ if (logElementGetting) {
+ Log("getting video stuff");
+ }
+ return document.getElementsByTagName("video")[0];
+ }
+
+ GetVideoElement() {
+ if (logElementGetting) {
+ Log("getting video element");
+ }
+ return document.getElementById("videoElement").parentNode;
+ }
+
+ GetInputType(answers, i) {
+ if (logElementGetting) {
+ Log("getting input type");
+ }
+ return answers[i].getElementsByTagName("input")[0].type;
+ }
+ }
+
+ var QPM = new QuestionsPageModell();
+ var RPM = new ResultsPageModell();
+ var MPM = new MiscPageModell();
+
+ // : }}}
+
+ // : Main function {{{
+ let timerStarted = false;
+
+ Main();
+ function Main() {
+ "use strict";
+ console.log("Moodle / E-Learning script");
+ console.time("main");
+ timerStarted = true;
+
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", Init);
+ } else {
+ Init();
+ }
+ }
+
+ function AfterLoad() {
+ const url = location.href; // eslint-disable-line
+
try {
- resolve(lastInfo)
+ if (
+ (url.includes("/quiz/") && url.includes("attempt.php")) ||
+ forceTestPage
+ ) {
+ // if the current page is a test
+ HandleQuiz();
+ } else if (
+ (url.includes("/quiz/") && url.includes("review.php")) ||
+ forceResultPage
+ ) {
+ // if the current window is a test-s result
+ HandleResults(url);
+ } else if (
+ (!url.includes("/quiz/") &&
+ !url.includes("review.php") &&
+ !url.includes(".pdf")) ||
+ forceDefaultPage
+ ) {
+ // if the current window is any other window than a quiz or pdf.
+ HandleUI(url);
+ }
} catch (e) {
- Log('Errro paring JSON in GetXHRInfos, when using old data!')
- Log(e)
- reject(e)
+ ShowMessage(
+ {
+ m: texts.fatalError,
+ isSimple: true,
+ },
+ undefined,
+ () => {
+ OpenErrorPage(e);
+ }
+ );
+
+ Exception(e, "script error at main:");
+ }
+ if (url.includes("eduplayer")) {
+ AddVideoHotkeys(url);
+ } // adding video hotkeys
+ Log(texts.consoleErrorInfo);
+
+ if (timerStarted) {
+ console.log("Moodle Test Script run time:");
+ console.timeEnd("main");
+ timerStarted = false;
+ }
+
+ if (forceTestPage || forceResultPage || forceDefaultPage) {
+ if (overlay.querySelector("#scriptMessage")) {
+ overlay.querySelector("#scriptMessage").style.background =
+ "green";
+ }
}
- })
}
- }
+ // : }}}
- function GetXHRQuestionAnswer (question) {
- return new Promise((resolve, reject) => {
- let url = apiAdress + 'ask?'
- let params = []
- Object.keys(question).forEach((key) => {
- let val = question[key]
- if (typeof val !== 'string') {
- val = JSON.stringify(val)
+ // : Main logic stuff {{{
+
+ // : Loading {{{
+ function HandleQminingSite(url) {
+ try {
+ const idInput = document.getElementById("cid");
+ if (idInput) {
+ idInput.value = getVal("clientId");
+ }
+ } catch (e) {
+ console.info("Error filling client ID input", e);
}
- params.push(key + '=' + encodeURIComponent(val))
- })
- url += params.join('&') +
- '&cversion=' + info().script.version +
- '&cid=' + GetId()
+ try {
+ const sideLinks = document.getElementById("sideBarLinks");
+ if (!sideLinks) {
+ return;
+ }
+ Array.from(sideLinks.childNodes).forEach(link => {
+ link.addEventListener("mousedown", () => {
+ FillFeedbackCID(url, link);
+ });
+ });
- xmlhttpRequest({
- method: 'GET',
- url: url,
- onload: function (response) {
- try {
- let res = JSON.parse(response.responseText)
- // FIXME: check if res is a valid answer array
- // res.json({
- // result: r,
- // success: true
+ FillFeedbackCID(
+ url,
+ document
+ .getElementById("sideBarLinks")
+ .getElementsByClassName("active")[0]
+ );
+ } catch (e) {
+ console.info("Error filling client ID input", e);
+ }
+ }
+
+ function FillFeedbackCID(url, link) {
+ try {
+ if (link.id === "feedback") {
+ const cidSetInterval = setInterval(() => {
+ const cid = document.getElementById("cid");
+ if (cid) {
+ cid.value = GetId() + "|" + info().script.version;
+ window.clearInterval(cidSetInterval);
+ }
+ }, 100);
+ }
+ } catch (e) {
+ console.info("Error filling client ID input", e);
+ }
+ }
+
+ function Init() {
+ const url = location.href; // eslint-disable-line
+
+ if (url.includes(serverAdress.split("/")[2])) {
+ HandleQminingSite(url);
+ return;
+ }
+
+ // if (false) {
+ // // eslint-disable-line
+ // setVal("version16", undefined);
+ // setVal("version15", undefined);
+ // setVal("firstRun", undefined);
+ // setVal("showQuestions", undefined);
+ // setVal("showSplash", undefined);
+ // }
+ // --------------------------------------------------------------------------------------
+ // event listener fuckery
+ // --------------------------------------------------------------------------------------
+ try {
+ // adding addeventlistener stuff, for the ability to add more event listeners for the same event
+ addEventListener = (function() {
+ if (document.addEventListener) {
+ return function(element, event, handler) {
+ element.addEventListener(event, handler, false);
+ };
+ } else {
+ return function(element, event, handler) {
+ element.attachEvent("on" + event, handler);
+ };
+ }
+ })();
+ } catch (e) {
+ Exception(e, "script error at addEventListener:");
+ }
+ VersionActions();
+ if (!url.includes(".pdf")) {
+ ShowMenu();
+ }
+ ConnectToServer(AfterLoad);
+ }
+
+ function Auth(pw) {
+ SendXHRMessage("login", { pw: pw, script: true }).then(res => {
+ if (res.result === "success") {
+ ConnectToServer(AfterLoad);
+ ClearAllMessages();
+ resetMenu();
+ } else {
+ SafeGetElementById("infoMainDiv", elem => {
+ elem.innerText = texts.invalidPW + pw;
+ });
+ }
+ });
+ }
+
+ function resetMenu() {
+ SafeGetElementById("menuButtonDiv", elem => {
+ elem.style.backgroundColor = "#262626";
+ });
+ SafeGetElementById("ircButton", elem => {
+ elem.style.display = "none";
+ });
+ SafeGetElementById("retryButton", elem => {
+ elem.style.display = "none";
+ });
+ SafeGetElementById("loginDiv", elem => {
+ elem.style.display = "none";
+ });
+ SafeGetElementById("infoMainDiv", elem => {
+ elem.innerText = texts.loading;
+ });
+ }
+
+ function ConnectToServer(cwith) {
+ ClearAllMessages();
+ GetXHRInfos()
+ .then(inf => {
+ if (inf.result === "nouser") {
+ NoUserAction();
+ return;
+ }
+ lastestVersion = inf.version;
+ motd = inf.motd;
+ subjInfo = inf.subjinfo;
+ overlay.querySelector(
+ "#infoMainDiv"
+ ).innerText = `${subjInfo.subjects} tárgy, ${subjInfo.questions} kérdés. Felh #${inf.uid}`;
+ // FIXME: if cwith() throws an unhandled error it sais server is not avaible
+ cwith();
+ })
+ .catch(() => {
+ NoServerAction();
+ });
+ }
+
+ function NoUserAction() {
+ SafeGetElementById("menuButtonDiv", elem => {
+ elem.style.backgroundColor = "#44cc00";
+ });
+ SafeGetElementById("infoMainDiv", elem => {
+ elem.innerText = texts.noUser;
+ if (getVal("clientId")) {
+ elem.innerText += ` (${getVal("clientId")})`;
+ }
+ });
+ SafeGetElementById("loginDiv", elem => {
+ elem.style.display = "";
+ });
+ }
+
+ function NoServerAction() {
+ SafeGetElementById("menuButtonDiv", elem => {
+ elem.style.backgroundColor = "red";
+ });
+ SafeGetElementById("infoMainDiv", elem => {
+ elem.innerText = texts.noServer;
+ });
+ SafeGetElementById("ircButton", elem => {
+ elem.style.display = "";
+ });
+ SafeGetElementById("retryButton", elem => {
+ elem.style.display = "";
+ });
+ Log(texts.noServerConsoleMessage);
+ }
+
+ function VersionActions() {
+ // FOR TESTING ONLY
+ // setVal("version15", true);
+ // setVal("firstRun", true);
+ // setVal("version16", true);
+ // throw "asd";
+
+ FreshStart();
+ }
+
+ // : Version action functions {{{
+
+ function FreshStart() {
+ var firstRun = getVal("firstRun"); // if the current run is the frst
+ if (firstRun === undefined || firstRun === true) {
+ setVal("firstRun", false);
+ ShowHelp(); // showing help
+
+ document.write(texts.freshStartWarning);
+ document.close();
+ throw new Error("something, so this stuff stops");
+ }
+ }
+
+ // : }}}
+
+ // : UI handling {{{
+ function HandleUI(url) {
+ // FIXME: normal string building with localisation :/
+ var newVersion = false; // if the script is newer than last start
+
+ try {
+ newVersion = info().script.version !== getVal("lastVerson");
+ } catch (e) {
+ Log("Some weird error trying to set new verison");
+ }
+
+ let showMOTD = false;
+ if (!SUtils.EmptyOrWhiteSpace(motd)) {
+ var prevmotd = getVal("motd");
+ if (prevmotd !== motd) {
+ showMOTD = true;
+ setVal("motdcount", motdShowCount);
+ setVal("motd", motd);
+ } else {
+ var motdcount = getVal("motdcount");
+ if (motdcount === undefined) {
+ setVal("motdcount", motdShowCount);
+ motdcount = motdShowCount;
+ }
+
+ motdcount--;
+ if (motdcount > 0) {
+ showMOTD = true;
+ setVal("motdcount", motdcount);
+ }
+ }
+ }
+ let isNewVersionAvaible =
+ lastestVersion !== undefined &&
+ info().script.version !== lastestVersion;
+ var greetMsg = ""; // message to show at the end
+ var timeout = null; // the timeout. if null, it wont be hidden
+
+ if (isNewVersionAvaible || newVersion || showMOTD) {
+ greetMsg =
+ "Moodle/Elearning/KMOOC segéd v. " +
+ info().script.version +
+ ". ";
+ }
+ if (isNewVersionAvaible) {
+ timeout = 5;
+ greetMsg += "Új verzió elérhető: " + lastestVersion;
+ timeout = undefined;
+ }
+ if (newVersion) {
+ // --------------------------------------------------------------------------------------------------------------
+ greetMsg +=
+ "Verzió frissítve " +
+ info().script.version +
+ "-re. Changelog:\n" +
+ texts.lastChangeLog;
+ setVal("lastVerson", info().script.version); // setting lastVersion
+ }
+ if (showMOTD) {
+ greetMsg += "\nMOTD:\n" + motd;
+ timeout = null;
+ }
+
+ ShowMessage(
+ {
+ m: greetMsg,
+ isSimple: true,
+ },
+ timeout
+ ); // showing message. If "m" is empty it wont show it, thats how showSplash works.
+ }
+
+ // : }}}
+
+ // : Answering stuffs {{{
+
+ function HandleQuiz() {
+ var q = QPM.GetQuestionFromTest();
+ var questions = q.q;
+ var imgNodes = q.imgnodes;
+ // ------------------------------------------------------------------------------------------------------
+ let promises = [];
+ questions.forEach(x => {
+ let question = SUtils.EmptyOrWhiteSpace(x)
+ ? ""
+ : SUtils.RemoveUnnecesarySpaces(x); // simplifying question
+ promises.push(
+ GetXHRQuestionAnswer({
+ q: question,
+ data: GetImageDataFromImgNodes(imgNodes),
+ subj: MPM.GetCurrentSubjectName(),
+ })
+ );
+ });
+
+ // FIXME: promise.all promise resolve order same as original?
+ Promise.all(promises).then(res => {
+ let answers = [];
+
+ res.forEach((result, j) => {
+ var r = PrepareAnswers(result, j);
+ if (r !== undefined) {
+ answers.push(r);
+ }
+ HighLightAnswer(result, j); // highlights the answer for the current result
+ });
+
+ ShowAnswers(answers, q.q);
+ });
+ }
+
+ function PrepareAnswers(result, j) {
+ assert(result);
+
+ if (result.length > 0) {
+ var allMessages = []; // preparing all messages
+ for (var k = 0; k < result.length; k++) {
+ var msg = ""; // the current message
+ if (
+ getVal("showQuestions") === undefined ||
+ getVal("showQuestions")
+ ) {
+ msg += result[k].q.Q + "\n"; // adding the question if yes
+ }
+ msg += result[k].q.A.replace(/, /g, "\n"); // adding answer
+ if (result[k].q.data.type === "image") {
+ msg +=
+ "\n\nKépek fenti válaszok sorrendjében: " +
+ result[k].q.data.images.join(", "); // if it has image part, adding that too
+ }
+ allMessages.push({
+ m: msg,
+ p: result[k].match,
+ });
+ }
+ return allMessages;
+ }
+ }
+
+ function ShowAnswers(answers, question) {
+ assert(answers);
+
+ if (answers.length > 0) {
+ // if there are more than 0 answer
+ ShowMessage(answers);
+ } else {
+ ShowMessage(
+ {
+ m: texts.noResult,
+ isSimple: true,
+ },
+ undefined,
+ function() {
+ OpenErrorPage({
+ message: "No result found",
+ stack: JSON.stringify(question),
+ });
+ }
+ );
+ }
+ }
+
+ // : }}}
+
+ // : Quiz saving {{{
+
+ function HandleResults(url) {
+ SaveQuiz(GetQuiz(), ShowSaveQuizDialog); // saves the quiz questions and answers
+ }
+
+ function ShowSaveQuizDialog(sendResult, sentData, newQuestions) {
+ // FIXME: normal string building with localisation :/
+ var msg = "";
+ if (sendResult) {
+ msg = "Kérdések elküldve, katt az elküldött adatokért.";
+ if (newQuestions > 0) {
+ msg += " " + newQuestions + " új kérdés";
+ } else {
+ msg += " Nincs új kérdés";
+ }
+ } else {
+ msg =
+ "Szerver nem elérhető, vagy egyéb hiba kérdések elküldésénél! (F12 -> Console)";
+ }
+ // showing a message wit the click event, and the generated page
+ ShowMessage(
+ {
+ m: msg,
+ isSimple: true,
+ },
+ null,
+ function() {
+ let towrite = "";
+ try {
+ towrite +=
+ "Elküldött adatok: " + JSON.stringify(sentData);
+ } catch (e) {
+ towrite += "Elküldött adatok: " + sentData;
+ }
+ document.write(towrite);
+ document.close();
+ }
+ );
+ }
+
+ // this should get the image url from a result page
+ // i is the index of the question
+ // FIXME: move this to RPM class ??? and refactor this
+ function GetImageFormResult(i) {
+ try {
+ var imgElements = RPM.GetResultImage(i); // trying to get image
+ var imgURL = []; // image urls
+ for (var j = 0; j < imgElements.length; j++) {
+ if (!imgElements[j].src.includes("brokenfile")) {
+ var filePart = imgElements[j].src.split("/"); // splits the link by "/"
+ filePart = filePart[filePart.length - 1]; // the last one is the image name
+ imgURL.push(decodeURI(SUtils.ShortenString(filePart, 30)));
+ }
+ }
+ if (imgURL.length > 0) {
+ return imgURL;
+ }
+ } catch (e) {
+ Log("Couldn't get images from result");
+ }
+ }
+
+ function GetDataFormResult(i) {
+ let data = { type: "simple" };
+
+ let img = GetImageFormResult(i);
+ let grabbox = RPM.GetAnswersFromGrabBox(i);
+ if (img) {
+ data = {
+ type: "image",
+ images: img,
+ };
+ }
+ if (grabbox) {
+ data = {
+ type: "grabbox",
+ images: img,
+ grabbox: grabbox,
+ };
+ }
+
+ return data;
+ }
+
+ // saves the current quiz. questionData contains the active subjects questions
+ function SaveQuiz(quiz, next) {
+ try {
+ let sentData = {};
+ if (quiz.length === 0) {
+ throw new Error("quiz length is zero!");
+ }
+ try {
+ try {
+ sentData.subj = MPM.GetCurrentSubjectName();
+ } catch (e) {
+ sentData.subj = "NOSUBJ";
+ Log("unable to get subject name :c");
+ }
+ sentData.version = info().script.version;
+ sentData.id = GetId();
+ sentData.quiz = quiz;
+ console.log("SENT DATA", sentData);
+ SendXHRMessage("isAdding", sentData).then(res => {
+ next(res.success, sentData, res.newQuestions);
+ });
+ } catch (e) {
+ Exception(e, "error at sending data to server.");
+ }
+ } catch (e) {
+ Exception(e, "script error at saving quiz");
+ }
+ }
+
+ // getting quiz from finish page
+ function GetQuiz() {
+ try {
+ var quiz = []; // final quiz stuff
+ var results = RPM.GetFormResult(); // getting results element
+ for (var i = 0; i < results.length - 2; i++) {
+ var question = {}; // the current question
+ // QUESTION --------------------------------------------------------------------------------------------------------------------
+ question.Q = RPM.GetQuestionFromResult(i);
+
+ // RIGHTANSWER ---------------------------------------------------------------------------------------------------------------------
+ question.A = RPM.GetRightAnswerFromResultv2(i);
+ if (question.A === undefined) {
+ question.A = RPM.GetRightAnswerFromResult(i);
+ }
+ // DATA ---------------------------------------------------------------------------------------------------------------------
+ question.data = GetDataFormResult(i);
+
+ if (question.A !== undefined) {
+ quiz.push(question); // adding current question to quiz
+ } else {
+ Log(
+ "error getting queston, no correct answer given, or its incorrect"
+ );
+ Log(question);
+ }
+ }
+ return quiz;
+ } catch (e) {
+ Exception(e, "script error at quiz parsing:");
+ }
+ }
+
+ // : }}}
+
+ // : Helpers {{{
+
+ function GetImageDataFromImgNodes(imgs) {
+ var questionImages = []; // the array for the image names in question
+ for (var i = 0; i < imgs.length; i++) {
+ if (!imgs[i].src.includes("brokenfile")) {
+ var filePart = imgs[i].src.split("/"); // splits the link by "/"
+ filePart = filePart[filePart.length - 1]; // the last one is the image name
+ questionImages.push(
+ decodeURI(
+ SUtils.RemoveUnnecesarySpaces(
+ SUtils.ShortenString(filePart, 30)
+ )
+ )
+ ); // decodes uri codes, and removes exess spaces, and shortening it
+ }
+ }
+ if (questionImages.length > 0) {
+ return {
+ type: "image",
+ images: questionImages,
+ };
+ } else {
+ return {
+ type: "simple",
+ };
+ }
+ }
+
+ // adds image names to image nodes
+ function AddImageNamesToImages(imgs) {
+ for (var i = 0; i < imgs.length; i++) {
+ if (!imgs[i].src.includes("brokenfile")) {
+ var filePart = imgs[i].src.split("/"); // splits the link by "/"
+ filePart = filePart[filePart.length - 1]; // the last one is the image name
+ var appedtTo = imgs[i].parentNode; // it will be appended here
+ var mainDiv = document.createElement("div");
+ var fileName = SUtils.ShortenString(decodeURI(filePart), 15); // shortening name, couse it can be long as fuck
+ var textNode = document.createTextNode("(" + fileName + ")");
+ mainDiv.appendChild(textNode);
+ appedtTo.appendChild(mainDiv);
+ }
+ }
+ }
+
+ // this function adds basic hotkeys for video controll.
+ function AddVideoHotkeys(url) {
+ var seekTime = 20;
+ document.addEventListener("keydown", function(e) {
+ try {
+ var video = MPM.GetVideo();
+ var keyCode = e.keyCode; // getting keycode
+ if (keyCode === 32) {
+ // if the keycode is 32 (space)
+ e.preventDefault(); // preventing default action (space scrolles down)
+ if (video.paused && video.buffered.length > 0) {
+ video.play();
+ } else {
+ video.pause();
+ }
+ }
+ if (keyCode === 39) {
+ // rigth : 39
+ video.currentTime += seekTime;
+ }
+ if (keyCode === 37) {
+ // left : 37
+ video.currentTime -= seekTime;
+ }
+ } catch (err) {
+ Log("Hotkey error.");
+ Log(err.message);
+ }
+ });
+ var toadd = MPM.GetVideoElement();
+ var node = CreateNodeWithText(toadd, texts.videoHelp);
+ node.style.margin = "5px 5px 5px 5px"; // fancy margin
+ }
+
+ // removes stuff like " a. q1" -> "q1"
+ function RemoveLetterMarking(inp) {
+ let dotIndex = inp.indexOf(".");
+ let doubledotIndex = inp.indexOf(":");
+ let maxInd = 4; // inp.length * 0.2;
+
+ if (dotIndex < maxInd) {
+ return SUtils.RemoveUnnecesarySpaces(
+ inp.substr(inp.indexOf(".") + 1, inp.length)
+ );
+ } else if (doubledotIndex < maxInd) {
+ return SUtils.RemoveUnnecesarySpaces(
+ inp.substr(inp.indexOf(":") + 1, inp.length)
+ );
+ } else {
+ return inp;
+ }
+ }
+
+ // highlights the possible solutions to the current question
+ function HighLightAnswer(results, currQuestionNumber) {
+ try {
+ if (results.length > 0) {
+ var answers = RPM.GetAllAnswer(currQuestionNumber); // getting all answers
+ var toColor = []; // the numberth in the array will be colored, and .length items will be colored
+ var type = ""; // type of the question. radio or ticbox or whatitscalled
+ for (let i = 0; i < answers.length; i++) {
+ // going thtough answers
+ if (
+ answers[i].tagName &&
+ answers[i].tagName.toLowerCase() === "div"
+ ) {
+ // if its not null and is "div"
+ var correct = results[0].q.A.toLowerCase(); // getting current correct answer from data
+ var answer = answers[i].innerText
+ .replace(/\n/g, "")
+ .toLowerCase(); // getting current answer
+
+ // removing stuff like "a."
+ answer = RemoveLetterMarking(answer);
+
+ if (
+ SUtils.EmptyOrWhiteSpace(correct) ||
+ SUtils.EmptyOrWhiteSpace(answer)
+ ) {
+ continue;
+ }
+
+ if (
+ SUtils.NormalizeSpaces(
+ SUtils.RemoveUnnecesarySpaces(correct)
+ ).includes(answer)
+ ) {
+ // if the correct answer includes the current answer
+ toColor.push(i); // adding the index
+ type = MPM.GetInputType(answers, i); // setting the type
+ }
+ }
+ }
+ if (results[0].match === 100) {
+ // if the result is 100% correct
+ if (type !== "radio" || toColor.length === 1) {
+ // FIXME why not radio
+ for (let i = 0; i < toColor.length; i++) {
+ // going through "toColor"
+ let highlight = createHoverOver(
+ answers[toColor[i]]
+ );
+ Object.assign(highlight.style, {
+ border: "7px solid rgba(100, 240, 100, 0.8)",
+ borderRadius: "10px",
+ margin: "-13px 0 0 -8px",
+ });
+ }
+ }
+ } // and coloring the correct index
+ }
+ } catch (e) {
+ // catching errors. Sometimes there are random errors, wich i did not test, but they are rare, and does not break the main script.
+ Log("script error at highlightin answer: " + e.message);
+ }
+ }
+
+ // : }}}
+
+ function Log(value) {
+ if (log) {
+ console.log(value);
+ }
+ }
+
+ function Exception(e, msg) {
+ Log("------------------------------------------");
+ Log(msg);
+ Log(e.message);
+ Log("------------------------------------------");
+ Log(e.stack);
+ Log("------------------------------------------");
+ }
+
+ // : }}}
+
+ // : Minor UI stuff {{{
+ function ClearAllMessages() {
+ overlay.querySelectorAll("#scriptMessage").forEach(x => x.remove());
+ }
+
+ // shows a message with "msg" text, "matchPercent" tip and transp, and "timeout" time
+ function ShowMessage(msgItem, timeout, funct) {
+ // msgItem help:
+ // [ [ {}{}{}{} ] [ {}{}{} ] ]
+ // msgItem[] <- a questions stuff
+ // msgItem[][] <- a questions relevant answers array
+ // msgItem[][].p <- a questions precent
+ // msgItem[][].m <- a questions message
+ try {
+ var defMargin = "0px 5px 0px 5px";
+ var isSimpleMessage = false;
+ var simpleMessageText = "";
+ if (msgItem.isSimple) {
+ // parsing msgItem for easier use
+ simpleMessageText = msgItem.m;
+ if (simpleMessageText === "") {
+ // if msg is empty
+ return;
+ }
+ msgItem = [
+ [
+ {
+ m: simpleMessageText,
+ },
+ ],
+ ];
+ isSimpleMessage = true;
+ }
+
+ var appedtTo = overlay; // will be appended here
+ var width = window.innerWidth - window.innerWidth / 6; // with of the box
+ var startFromTop = 25; // top distance
+
+ var mainDiv = document.createElement("div"); // the main divider, wich items will be attached to
+ mainDiv.setAttribute("id", "messageMainDiv");
+ if (funct) {
+ // if there is a function as parameter
+ addEventListener(mainDiv, "click", funct); // adding it as click
+ }
+ // lotsa crap style
+ SetStyle(mainDiv, {
+ position: "fixed",
+ zIndex: 999999,
+ textAlign: "center",
+ width: width + "px",
+ padding: "0px",
+ background: "#222d32",
+ color: "#ffffff",
+ borderColor: "#035a8f",
+ border: "none",
+ top: startFromTop + "px",
+ left: (window.innerWidth - width) / 2 + "px",
+ opacity: "0.9",
+ });
+ mainDiv.setAttribute("id", "scriptMessage");
+ var matchPercent = msgItem[0][0].p;
+ if (isSimpleMessage) {
+ var simpleMessageParagrapg = document.createElement("p"); // new paragraph
+ simpleMessageParagrapg.style.margin = defMargin; // fancy margin
+
+ var mesageNode = document.createElement("p"); // new paragraph
+ mesageNode.innerHTML = simpleMessageText.replace(
+ /\n/g,
+ ""
+ );
+ simpleMessageParagrapg.appendChild(mesageNode);
+ mesageNode.style.margin = defMargin; // fancy margin
+
+ mainDiv.appendChild(simpleMessageParagrapg); // adding text box to main div
+ } else {
+ // if its a fucking complicated message
+ // TABLE SETUP ------------------------------------------------------------------------------------------------------------
+ var table = document.createElement("table");
+ table.style.width = "100%";
+ // ROWS -----------------------------------------------------------------------------------------------------
+ var rowOne = table.insertRow(); // previous suggestion, question text, and prev question
+ var rowTwo = table.insertRow(); // next question button
+ var rowThree = table.insertRow(); // next suggetsion button
+ // CELLS -----------------------------------------------------------------------------------------------------
+ // row one
+ var numberTextCell = rowOne.insertCell();
+ var questionCell = rowOne.insertCell(); // QUESTION CELL
+ questionCell.setAttribute("id", "questionCell");
+ questionCell.rowSpan = 3;
+ questionCell.style.width = "90%";
+ var prevQuestionCell = rowOne.insertCell();
+ // row two
+ var percentTextCell = rowTwo.insertCell();
+ var nextQuestionCell = rowTwo.insertCell();
+ // row three
+ var prevSuggestionCell = rowThree.insertCell();
+ var nextSuggestionCell = rowThree.insertCell();
+ // adding finally
+ mainDiv.appendChild(table);
+ // PERCENT TEXT SETUP -----------------------------------------------------------------------------------------------------
+ var percentTextBox = CreateNodeWithText(percentTextCell, "");
+ percentTextBox.setAttribute("id", "percentTextBox");
+
+ if (matchPercent) {
+ // if match percent param is not null
+ percentTextBox.innerText = matchPercent + "%";
+ }
+ // NUMBER SETUP -----------------------------------------------------------------------------------------------------
+ var numberTextBox = CreateNodeWithText(numberTextCell, "1.");
+ numberTextBox.setAttribute("id", "numberTextBox");
+
+ // ANSWER NODE SETUP -------------------------------------------------------------------------------------------------------------
+ var questionTextElement = CreateNodeWithText(
+ questionCell,
+ "ur question goes here, mister OwO"
+ );
+ questionTextElement.setAttribute("id", "questionTextElement");
+
+ // BUTTON SETUP -----------------------------------------------------------------------------------------------------------
+ var currItem = 0;
+ var currRelevantQuestion = 0;
+
+ const GetRelevantQuestion = () => {
+ // returns the currItemth questions currRelevantQuestionth relevant question
+ return msgItem[currItem][currRelevantQuestion];
+ };
+
+ const ChangeCurrItemIndex = to => {
+ currItem += to;
+ if (currItem < 0) {
+ currItem = 0;
+ }
+ if (currItem > msgItem.length - 1) {
+ currItem = msgItem.length - 1;
+ }
+ currRelevantQuestion = 0;
+ };
+
+ const ChangeCurrRelevantQuestionIndex = to => {
+ currRelevantQuestion += to;
+ if (currRelevantQuestion < 0) {
+ currRelevantQuestion = 0;
+ }
+ if (currRelevantQuestion > msgItem[currItem].length - 1) {
+ currRelevantQuestion = msgItem[currItem].length - 1;
+ }
+ };
+
+ const SetQuestionText = () => {
+ var relevantQuestion = GetRelevantQuestion();
+ questionTextElement.innerText = relevantQuestion.m;
+ if (currItem === 0 && currRelevantQuestion === 0) {
+ numberTextBox.innerText =
+ currRelevantQuestion + 1 + ".";
+ } else {
+ numberTextBox.innerText =
+ currItem +
+ 1 +
+ "./" +
+ (currRelevantQuestion + 1) +
+ ".";
+ }
+ percentTextBox.innerText = relevantQuestion.p + "%";
+ };
+
+ var buttonMargin = "2px 2px 2px 2px"; // uniform button margin
+ if (msgItem[currItem].length > 1) {
+ // PREV SUGG BUTTON ------------------------------------------------------------------------------------------------------------
+ var prevSuggButton = CreateNodeWithText(
+ prevSuggestionCell,
+ "<",
+ "button"
+ );
+ prevSuggButton.style.margin = buttonMargin; // fancy margin
+
+ prevSuggButton.addEventListener("click", function() {
+ ChangeCurrRelevantQuestionIndex(-1);
+ SetQuestionText();
+ });
+ // NEXT SUGG BUTTON ------------------------------------------------------------------------------------------------------------
+ var nextSuggButton = CreateNodeWithText(
+ nextSuggestionCell,
+ ">",
+ "button"
+ );
+ nextSuggButton.style.margin = buttonMargin; // fancy margin
+
+ nextSuggButton.addEventListener("click", function() {
+ ChangeCurrRelevantQuestionIndex(1);
+ SetQuestionText();
+ });
+ }
+ // deciding if has multiple questions ------------------------------------------------------------------------------------------------
+ if (msgItem.length === 1) {
+ SetQuestionText();
+ } else {
+ // if there are multiple items to display
+ // PREV QUESTION BUTTON ------------------------------------------------------------------------------------------------------------
+ var prevButton = CreateNodeWithText(
+ prevQuestionCell,
+ "^",
+ "button"
+ );
+ prevButton.style.margin = buttonMargin; // fancy margin
+
+ // event listener
+ prevButton.addEventListener("click", function() {
+ ChangeCurrItemIndex(-1);
+ SetQuestionText();
+ });
+ // NEXT QUESTION BUTTON ------------------------------------------------------------------------------------------------------------
+ var nextButton = CreateNodeWithText(
+ nextQuestionCell,
+ "ˇ",
+ "button"
+ );
+ nextButton.style.margin = buttonMargin; // fancy margin
+
+ // event listener
+ nextButton.addEventListener("click", function() {
+ ChangeCurrItemIndex(1);
+ SetQuestionText();
+ });
+ SetQuestionText();
+ }
+ }
+ appedtTo.appendChild(mainDiv); // THE FINAL APPEND
+
+ // setting some events
+ // addEventListener(window, 'scroll', function () {
+ // mainDiv.style.top = (pageYOffset + startFromTop) + 'px';
// })
- // ERROR:
- // res.json({
- // message: `Invalid question :(`,
- // result: [],
- // recievedData: JSON.stringify(req.query),
- // success: false
- // })
- resolve(res.result)
- } catch (e) {
- reject(e)
- }
- },
- onerror: (e) => {
- Log('Errro paring JSON in GetXHRQuestionAnswer')
- Log(e)
- reject(e)
- reject(e)
+ addEventListener(window, "resize", function() {
+ mainDiv.style.left = (window.innerWidth - width) / 2 + "px";
+ });
+ var timeOut;
+ if (timeout && timeout > 0) {
+ // setting timeout if not zero or null
+ timeOut = setTimeout(function() {
+ mainDiv.parentNode.removeChild(mainDiv);
+ }, timeout * 1000);
+ }
+ // middle click close event listener
+ addEventListener(mainDiv, "mousedown", function(e) {
+ if (e.which === 2) {
+ mainDiv.parentNode.removeChild(mainDiv);
+ if (timeOut) {
+ clearTimeout(timeOut);
+ }
+ }
+ });
+ } catch (e) {
+ Exception(e, "script error at showing message:");
}
- })
- })
- }
-
- function SendXHRMessage (path, message) {
- // message = SUtils.RemoveSpecialChars(message) // TODO: check this
- if (typeof message === 'object') {
- message = JSON.stringify(message)
}
- const url = apiAdress + path
- return new Promise((resolve, reject) => {
- xmlhttpRequest({
- method: 'POST',
- url: url,
- crossDomain: true,
- xhrFields: { withCredentials: true },
- data: message,
- headers: {
- 'Content-Type': 'application/json'
- },
- onerror: function (e) {
- Log('Data send error', e)
- reject(e)
- },
- onload: (resp) => {
- try {
- const res = JSON.parse(resp.responseText)
- resolve(res)
- } catch (e) {
- Log('Error paring JSON in SendXHRMessage')
- Log(e)
- reject(e)
- }
+
+ // shows a fancy menu
+ function ShowMenu() {
+ try {
+ var appedtTo = overlay; // will be appended here
+
+ // mainDiv.style.left = (window.innerWidth - width) / 2 + 'px';
+
+ var menuButtonDiv = document.createElement("div");
+ menuButtonDiv.setAttribute("id", "menuButtonDiv");
+ SetStyle(menuButtonDiv, {
+ width: "600px",
+ // height: buttonHeight + 'px',
+ top: window.innerHeight - 120 + "px",
+ left: "10px",
+ zIndex: 999999,
+ position: "fixed",
+ textAlign: "center",
+ padding: "0px",
+ margin: "0px",
+ background: "#262626",
+ });
+
+ var tbl = document.createElement("table");
+ tbl.style.margin = "5px 5px 5px 5px";
+ tbl.style.textAlign = "left";
+ tbl.style.width = "98%";
+ menuButtonDiv.appendChild(tbl);
+
+ var buttonRow = tbl.insertRow();
+ var buttonCell = buttonRow.insertCell();
+ buttonCell.style.textAlign = "center";
+
+ let buttonStyle = {
+ position: "",
+ margin: "5px 5px 5px 5px",
+ border: "none",
+ backgroundColor: "#222d32",
+ color: "#ffffff",
+ cursor: "pointer",
+ };
+ // help button ----------------------------------------------------------------------------------------------------------------
+ let helpButton = CreateNodeWithText(
+ buttonCell,
+ texts.help,
+ "button"
+ );
+ SetStyle(helpButton, buttonStyle);
+
+ helpButton.addEventListener("click", function() {
+ ShowHelp();
+ }); // adding clicktextNode
+
+ // site link ----------------------------------------------------------------------------------------------------------------
+
+ let contributeLink = CreateNodeWithText(
+ buttonCell,
+ texts.contribute,
+ "button"
+ );
+ contributeLink.title = texts.contributeTitle;
+ SetStyle(contributeLink, buttonStyle);
+
+ contributeLink.addEventListener("click", function() {
+ openInTab(serverAdress + "contribute?scriptMenu", {
+ active: true,
+ });
+ });
+
+ // pw request ----------------------------------------------------------------------------------------------------------------
+
+ let pwRequest = CreateNodeWithText(
+ buttonCell,
+ texts.pwRequest,
+ "button"
+ );
+ pwRequest.title = texts.newPWTitle;
+ SetStyle(pwRequest, buttonStyle);
+
+ pwRequest.addEventListener("click", function() {
+ openInTab(serverAdress + "pwRequest", {
+ active: true,
+ });
+ });
+
+ // site link ----------------------------------------------------------------------------------------------------------------
+
+ let siteLink = CreateNodeWithText(
+ buttonCell,
+ texts.websiteBugreport,
+ "button"
+ );
+ SetStyle(siteLink, buttonStyle);
+
+ siteLink.addEventListener("click", function() {
+ openInTab(serverAdress + "menuClick", {
+ active: true,
+ });
+ });
+
+ // donate link ----------------------------------------------------------------------------------------------------------------
+ let donateLink = CreateNodeWithText(
+ buttonCell,
+ texts.donate,
+ "button"
+ );
+ SetStyle(donateLink, buttonStyle);
+
+ donateLink.addEventListener("click", function() {
+ openInTab(serverAdress + "donate?scriptMenu", {
+ active: true,
+ });
+ });
+
+ addEventListener(window, "resize", function() {
+ menuButtonDiv.style.top = window.innerHeight - 70 + "px";
+ });
+
+ // INFO TABEL --------------------------------------------------------------------
+ var itbl = document.createElement("table");
+ SetStyle(itbl, {
+ margin: "5px 5px 5px 5px",
+ textAlign: "left",
+ width: "98%",
+ });
+ menuButtonDiv.appendChild(itbl);
+ var ibuttonRow = tbl.insertRow();
+ var ibuttonCell = ibuttonRow.insertCell();
+ ibuttonCell.style.textAlign = "center";
+
+ // INFO DIV ---------------------------------------------------------------------------------
+ let infoDiv = CreateNodeWithText(
+ ibuttonCell,
+ texts.loading,
+ "span"
+ );
+ infoDiv.setAttribute("id", "infoMainDiv");
+ SetStyle(infoDiv, {
+ color: "#ffffff",
+ margin: "5px",
+ });
+
+ // login div ----------------------------------------------------------------------------------------------------------------
+ const loginDiv = document.createElement("div");
+ loginDiv.style.display = "none";
+ loginDiv.setAttribute("id", "loginDiv");
+ const loginButton = document.createElement("button");
+ loginButton.innerText = texts.login;
+ const loginInput = document.createElement("input");
+ loginInput.type = "text";
+ loginInput.style.width = "400px";
+ loginInput.style.textAlign = "center";
+ const clientId = getVal("clientId");
+ if (clientId && clientId.toString()[0] !== "0") {
+ loginInput.value = clientId || "";
+ loginButton.innerText = texts.requestPWInsteadOfLogin;
+ }
+ loginDiv.appendChild(loginInput);
+ loginDiv.appendChild(loginButton);
+
+ SetStyle(loginButton, buttonStyle);
+
+ loginInput.addEventListener("keyup", e => {
+ console.log(e.target.value);
+ if (e.target.value === clientId) {
+ loginButton.innerText = texts.requestPWInsteadOfLogin;
+ } else if (e.target.value !== "") {
+ loginButton.innerText = texts.login;
+ }
+ });
+
+ loginButton.addEventListener("click", function() {
+ if (loginInput.value === clientId.toString()) {
+ openInTab(serverAdress + "getVeteranPw?cid=" + clientId, {
+ active: true,
+ });
+ } else {
+ Auth(loginInput.value);
+ }
+ });
+
+ ibuttonCell.appendChild(loginDiv);
+
+ // irc button ----------------------------------------------------------------------------------------------------------------
+ let ircButton = CreateNodeWithText(
+ ibuttonCell,
+ texts.ircButton,
+ "button"
+ );
+ SetStyle(ircButton, buttonStyle);
+ ircButton.style.display = "none";
+ ircButton.setAttribute("id", "ircButton");
+
+ ircButton.addEventListener("click", function() {
+ openInTab(ircAddress, {
+ active: true,
+ });
+ });
+
+ // retry button ----------------------------------------------------------------------------------------------------------------
+ let retryButton = CreateNodeWithText(
+ ibuttonCell,
+ texts.retry,
+ "button"
+ );
+ SetStyle(retryButton, buttonStyle);
+ retryButton.style.display = "none";
+ retryButton.setAttribute("id", "retryButton");
+
+ retryButton.addEventListener("click", function() {
+ menuButtonDiv.style.background = "#262626";
+ infoDiv.innerText = texts.loading;
+ retryButton.style.display = "none";
+ ircButton.style.display = "none";
+ ConnectToServer(AfterLoad);
+ });
+
+ // window resize event listener ---------------------------------------
+ addEventListener(window, "resize", function() {
+ menuButtonDiv.style.top = window.innerHeight - 70 + "px";
+ });
+
+ // APPEND EVERYTHING
+ appedtTo.appendChild(menuButtonDiv);
+ } catch (e) {
+ Exception(e, "script error at showing menu:");
}
- })
- })
- }
-
- function OpenErrorPage (e) {
- let path = 'lred'
- try {
- if (e.message || e.stack) {
- path += '?'
- }
- if (e.message) {
- path += 'msg:' + SUtils.SimplifyQuery(e.message)
- }
- if (e.stack) {
- path += '___stack:' + SUtils.SimplifyStack(e.stack)
- }
- path += '___version:' + info().script.version
- path = SUtils.RemoveSpecialChars(path)
- } catch (e) {
- Exception(e, 'error at setting error stack/msg link')
}
- path = path.replace(/ /g, '_')
- openInTab(serverAdress + path, {
- active: true
- })
- }
- // : }}}
+ // : }}}
- // : Help {{{
+ // : Generic utils {{{
+ function GetId() {
+ let currId = getVal("clientId");
+ if (currId) {
+ return currId;
+ } else {
+ currId = new Date();
+ currId =
+ currId.getTime() + Math.floor(Math.random() * 1000000000000);
+ currId = currId.toString().split("");
+ currId.shift();
+ currId = "0" + currId.join("");
+ setVal("clientId", currId);
+ return currId;
+ }
+ }
- // shows some neat help
- function ShowHelp () {
- openInTab(serverAdress + 'manual?scriptMenu', {
- active: true
- })
- }
+ function SafeGetElementById(id, next) {
+ let element = overlay.querySelector("#" + id);
+ if (element) {
+ next(element);
+ } else {
+ Log(`Unable to safe get element by id: ${id}`);
+ }
+ }
- // : }}}
+ function SetStyle(target, style) {
+ Object.keys(style)
+ .sort()
+ .forEach(key => {
+ target.style[key] = style[key];
+ });
+ }
- // I am not too proud to cry that He and he
- // Will never never go out of my mind.
- // All his bones crying, and poor in all but pain,
+ function CreateNodeWithText(to, text, type) {
+ var paragraphElement = document.createElement(type || "p"); // new paragraph
+ var textNode = document.createTextNode(text);
+ paragraphElement.appendChild(textNode);
+ to.appendChild(paragraphElement);
+ return paragraphElement;
+ }
- // Being innocent, he dreaded that he died
- // Hating his God, but what he was was plain:
- // An old kind man brave in his burning pride.
+ function GetXHRInfos() {
+ const now = new Date().getTime();
+ const lastCheck = getVal("lastInfoCheckTime");
+ if (!lastCheck) {
+ setVal("lastInfoCheckTime", now);
+ }
- // The sticks of the house were his; his books he owned.
- // Even as a baby he had never cried;
- // Nor did he now, save to his secret wound.
+ let lastInfo = { result: "noLastInfo" };
+ try {
+ lastInfo = JSON.parse(getVal("lastInfo"));
+ } catch (e) {
+ console.info(e);
+ }
+ if (
+ lastInfo.result !== "success" ||
+ now > lastCheck + infoExpireTime * 1000
+ ) {
+ return new Promise((resolve, reject) => {
+ const url =
+ apiAdress +
+ "infos?version=true&motd=true&subjinfo=true&cversion=" +
+ info().script.version +
+ "&cid=" +
+ GetId();
- // Out of his eyes I saw the last light glide.
- // Here among the liught of the lording sky
- // An old man is with me where I go
+ xmlhttpRequest({
+ method: "GET",
+ url: url,
+ crossDomain: true,
+ xhrFields: { withCredentials: true },
+ headers: {
+ "Content-Type": "application/json",
+ },
+ onload: function(response) {
+ try {
+ setVal("lastInfoCheckTime", now);
+ const res = JSON.parse(response.responseText);
+ setVal("lastInfo", response.responseText);
+ resolve(res);
+ } catch (e) {
+ Log("Errro paring JSON in GetXHRInfos");
+ Log(response.responseText);
+ Log(e);
+ reject(e);
+ }
+ },
+ onerror: e => {
+ Log("Info get Error", e);
+ reject(e);
+ },
+ });
+ });
+ } else {
+ return new Promise((resolve, reject) => {
+ try {
+ resolve(lastInfo);
+ } catch (e) {
+ Log(
+ "Errro paring JSON in GetXHRInfos, when using old data!"
+ );
+ Log(e);
+ reject(e);
+ }
+ });
+ }
+ }
- // Walking in the meadows of his son's eye
- // Too proud to cry, too frail to check the tears,
- // And caught between two nights, blindness and death.
+ function GetXHRQuestionAnswer(question) {
+ return new Promise((resolve, reject) => {
+ let url = apiAdress + "ask?";
+ let params = [];
+ Object.keys(question).forEach(key => {
+ let val = question[key];
+ if (typeof val !== "string") {
+ val = JSON.stringify(val);
+ }
+ params.push(key + "=" + encodeURIComponent(val));
+ });
+ url +=
+ params.join("&") +
+ "&cversion=" +
+ info().script.version +
+ "&cid=" +
+ GetId();
- // O deepest wound of all that he should die
- // On that darkest day.
+ xmlhttpRequest({
+ method: "GET",
+ url: url,
+ onload: function(response) {
+ try {
+ let res = JSON.parse(response.responseText);
+ // FIXME: check if res is a valid answer array
+ // res.json({
+ // result: r,
+ // success: true
+ // })
+ // ERROR:
+ // res.json({
+ // message: `Invalid question :(`,
+ // result: [],
+ // recievedData: JSON.stringify(req.query),
+ // success: false
+ // })
+ resolve(res.result);
+ } catch (e) {
+ reject(e);
+ }
+ },
+ onerror: e => {
+ Log("Errro paring JSON in GetXHRQuestionAnswer");
+ Log(e);
+ reject(e);
+ reject(e);
+ },
+ });
+ });
+ }
+
+ function SendXHRMessage(path, message) {
+ // message = SUtils.RemoveSpecialChars(message) // TODO: check this
+ if (typeof message === "object") {
+ message = JSON.stringify(message);
+ }
+ const url = apiAdress + path;
+ return new Promise((resolve, reject) => {
+ xmlhttpRequest({
+ method: "POST",
+ url: url,
+ crossDomain: true,
+ xhrFields: { withCredentials: true },
+ data: message,
+ headers: {
+ "Content-Type": "application/json",
+ },
+ onerror: function(e) {
+ Log("Data send error", e);
+ reject(e);
+ },
+ onload: resp => {
+ try {
+ const res = JSON.parse(resp.responseText);
+ resolve(res);
+ } catch (e) {
+ Log("Error paring JSON in SendXHRMessage");
+ Log(resp.responseText);
+ Log(e);
+ reject(e);
+ }
+ },
+ });
+ });
+ }
+
+ function OpenErrorPage(e) {
+ let path = "lred";
+ try {
+ if (e.message || e.stack) {
+ path += "?";
+ }
+ if (e.message) {
+ path += "msg:" + SUtils.SimplifyQuery(e.message);
+ }
+ if (e.stack) {
+ path += "___stack:" + SUtils.SimplifyStack(e.stack);
+ }
+ path += "___version:" + info().script.version;
+ path = SUtils.RemoveSpecialChars(path);
+ } catch (e) {
+ Exception(e, "error at setting error stack/msg link");
+ }
+ path = path.replace(/ /g, "_");
+ openInTab(serverAdress + path, {
+ active: true,
+ });
+ }
+
+ // : }}}
+
+ // : Help {{{
+
+ // shows some neat help
+ function ShowHelp() {
+ openInTab(serverAdress + "manual?scriptMenu", {
+ active: true,
+ });
+ }
+
+ // : }}}
+
+ // I am not too proud to cry that He and he
+ // Will never never go out of my mind.
+ // All his bones crying, and poor in all but pain,
+
+ // Being innocent, he dreaded that he died
+ // Hating his God, but what he was was plain:
+ // An old kind man brave in his burning pride.
+
+ // The sticks of the house were his; his books he owned.
+ // Even as a baby he had never cried;
+ // Nor did he now, save to his secret wound.
+
+ // Out of his eyes I saw the last light glide.
+ // Here among the liught of the lording sky
+ // An old man is with me where I go
+
+ // Walking in the meadows of his son's eye
+ // Too proud to cry, too frail to check the tears,
+ // And caught between two nights, blindness and death.
+
+ // O deepest wound of all that he should die
+ // On that darkest day.
})(); // eslint-disable-line