// vim:foldmethod=marker /* ---------------------------------------------------------------------------- Online Moodle/Elearning/KMOOC test help Greasyfork: GitLab: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ------------------------------------------------------------------------- */ // TODO: // default is not active on new subjects -> TEST var data; // all data, which is in the resource txt var addEventListener; // add event listener function const lastChangeLog = '- Eredmények oldalon kérdésekre válasz szerzés mód váltás\n - Görgethető tárgyak, mert túl sok van már :p\nHa rosz választ szed ki a script pls küldj feedbacket! IRC is van.'; const serverAdress = "https://qmining.tk/"; // 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 = false; const motdShowCount = 3; var motd = ""; var lastestVersion = ""; // TODO: if undefined no new verion const minMatchAmmount = 49; //: Class descriptions {{{ class Question { constructor(q, a, i) { this.Q = q; this.A = a; this.I = i; } toString() { var r = "?" + this.Q + "\n!" + this.A; if (this.I) r += "\n>" + this.I; return r; } HasQuestion() { return this.Q != undefined; } HasAnswer() { return this.A != undefined; } HasImage() { return this.I != undefined; } IsComplete() { return this.HasQuestion() && this.HasAnswer(); } Compare(q2, i) { if (typeof q2 == 'string') { var qmatchpercent = Question.CompareString(this.Q, q2); if (i == undefined || i.length == 0) return qmatchpercent; else { if (this.HasImage()) { const imatchpercent = this.HasImage() ? Question.CompareString(this.I.join(" "), i.join(" ")) : 0; return (qmatchpercent + imatchpercent) / 2; } else { qmatchpercent -= 30; if (qmatchpercent < 0) return 0; else return qmatchpercent; } } } else { const qmatchpercent = Question.CompareString(this.Q, q2.Q); const amatchpercent = Question.CompareString(this.A, q2.A); if (this.I != undefined) { const imatchpercent = this.I == undefined ? Question.CompareString(this.I.join(" "), q2.I.join( " ")) : 0; return (qmatchpercent + amatchpercent + imatchpercent) / 3; } else { return (qmatchpercent + amatchpercent) / 2; } } } static CompareString(s1, s2) { //if (s1 == undefined || s2 == undefined) // return 0; s1 = SimplifyStringForComparison(s1).split(" "); s2 = SimplifyStringForComparison(s2).split(" "); var match = 0; for (var i = 0; i < s1.length; i++) if (s2.includes(s1[i])) match++; var percent = Math.round(((match / s1.length) * 100).toFixed(2)); // matched words percent var lengthDifference = Math.abs(s2.length - s1.length); percent -= lengthDifference * 3; if (percent < 0) percent = 0; return percent; } } class Subject { constructor(n) { this.Name = n; this.Questions = []; } get length() { return this.Questions.length; } AddQuestion(q) { this.Questions.push(q); } Search(q, img) { var r = []; for (var i = 0; i < this.length; i++) { let percent = this.Questions[i].Compare(q, img); if (percent > minMatchAmmount) r.push({ q: this.Questions[i], match: percent }); } for (var i = 0; i < r.length; i++) for (var j = i; j < r.length; j++) if (r[i].match < r[j].match) { var tmp = r[i]; r[i] = r[j]; r[j] = tmp; } return r; } toString() { var r = []; for (var i = 0; i < this.Questions.length; i++) r.push(this.Questions[i].toString()); return "+" + this.Name + "\n" + r.join("\n"); } } class QuestionDB { constructor() { this.Subjects = []; } get length() { return this.Subjects.length; } get activeIndexes() { var r = []; for (var i = 0; i < this.length; i++) { if (GM_getValue("Is" + i + "Active")) { r.push(i); } } return r; } GetIfActive(ind) { return GM_getValue("Is" + ind + "Active"); } ChangeActive(i, value) { GM_setValue("Is" + i + "Active", !!value); } AddQuestion(subj, q) { var i = 0; while (i < this.Subjects.length && this.Subjects[i].Name != subj) i++; if (i < this.Subjects.length) this.Subjects[i].AddQuestion(q); else { const n = new Subject(subj); n.AddQuestion(q); this.Subjects.push(n); } } Search(q, img) { var r = []; for (var i = 0; i < this.length; i++) if (this.GetIfActive(i)) r = r.concat(this.Subjects[i].Search(q, img)); for (var i = 0; i < r.length; i++) for (var j = i; j < r.length; j++) if (r[i].match < r[j].match) { var tmp = r[i]; r[i] = r[j]; r[j] = tmp; } return r; } AddSubject(subj) { var i = 0; while (i < this.length && subj.Name != this.Subjects[i].Name) i++; if (i < this.length) { this.Subjects.concat(subj.Questions); } else { this.Subjects.push(subj); } } toString() { var r = []; for (var i = 0; i < this.Subjects.length; i++) r.push(this.Subjects[i].toString()); return r.join("\n\n"); } } //: }}} //: Main function {{{ function Main() { 'use strict'; Init(function(count, subjCount) { var url = location.href; 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, count, subjCount); } } catch (e) { ShowMessage({ m: "Fatál error. Check console (f12). Kattints az üzenetre az összes kérdés/válaszért manuális kereséshez!", isSimple: true }, undefined, function() { GM_openInTab(serverAdress + 'legacy', { active: true }); }); Exception(e, "script error at main:"); } if (url.includes("eduplayer")) // if the current site is a video site AddVideoHotkeys(url); // adding video hotkeys Log( "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! Nagy esélyel a kérdéseket nem lehetett beolvasni." ); }); } //: }}} //: DOM getting stuff {{{ // all dom getting stuff are in this sections, so on // moodle dom change, stuff breaks here function GetAllQuestionsDropdown() { if (logElementGetting) Log("getting dropdown question"); return document.getElementById("responseform").getElementsByTagName("p")[0].innerText; } function GetAllQuestionsQtext() { if (logElementGetting) Log("getting all questions qtext"); return document.getElementById("responseform").getElementsByClassName("qtext"); // getting questions } function GetAllQuestionsP() { if (logElementGetting) Log("getting all questions by tag p"); return document.getElementById("responseform").getElementsByTagName("p"); } function GetFormulationClearfix() { if (logElementGetting) Log("getting formulation clearfix lol"); return document.getElementsByClassName("formulation clearfix"); } function GetAnswerOptions() { // TODO if (logElementGetting) Log("getting all answer options"); return GetFormulationClearfix()[0].childNodes[3].innerText; } function GetQuestionImages() { if (logElementGetting) Log("getting question images"); return GetFormulationClearfix()[0].getElementsByTagName("img"); } function GetCurrentSubjectName() { if (logElementGetting) Log("getting current subjects name"); return document.getElementById("page-header").innerText.split("\n")[0]; } function GetVideo() { if (logElementGetting) Log("getting video stuff"); return document.getElementsByTagName("video")[0]; } function GetVideoElement() { if (logElementGetting) Log("getting video element"); return document.getElementById("videoElement").parentNode; } function GetAllAnswer(index) { if (logElementGetting) Log("getting all answers, ind: " + index); return document.getElementsByClassName("answer")[index].childNodes; } function GetInputType(answers, i) { if (logElementGetting) Log("getting input type"); return answers[i].getElementsByTagName("input")[0].type; } function 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; } function GetQText(i) { if (logElementGetting) Log("getting qtext by index: " + i); var results = GetFormResult(); // getting results element return results[i].getElementsByClassName("qtext"); } function GetDropboxes(i) { if (logElementGetting) Log("getting dropboxes by index: " + i); var results = GetFormResult(); // getting results element return results[i].getElementsByTagName("select"); } function 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; } function GetCurrentAnswer(i) { if (logElementGetting) Log("getting curr answer by index: " + i); var results = GetFormResult(); // getting results element var t = results[i].getElementsByClassName("formulation clearfix")[0].getElementsByTagName("span"); if (t.length > 2) return t[1].innerHTML.split("
")[1]; } function GetSelectAnswer() { if (logElementGetting) Log("getting selected answer"); var t = document.getElementsByTagName("select"); if (t.length > 0) return t[0].options[document.getElementsByTagName("select")[ 0].selectedIndex].innerText; } function GetAnswerNode(i) { if (logElementGetting) Log("getting answer node"); var results = 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 = DetermineQuestionType(ret); return { nodes: ret, type: qtype }; } function 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; } function GetPossibleAnswers(i) { if (logElementGetting) Log("getting possible answers"); var results = GetFormResult(); // getting results element var items = GetFormResult()[i].getElementsByTagName("label"); var r = []; for (var j = 0; j < items.length; j++) { function 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; } function GetRightAnswerIfCorrectShown(i) { if (logElementGetting) Log("getting right answer if correct shown"); var results = GetFormResult(); // getting results element return results[i].getElementsByClassName("rightanswer"); } function GetWrongAnswerIfCorrectNotShown(i) { if (logElementGetting) Log("getting wrong answer if correct not shown"); var results = 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 ""; } function GetRightAnswerIfCorrectNotShown(i) { if (logElementGetting) Log("Getting right answer if correct not shown"); var results = 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; else return ""; } function GetFormCFOfResult(result) { if (logElementGetting) Log("getting formulation clearfix"); return result.getElementsByClassName("formulation clearfix")[0]; } function GetResultText(i) { if (logElementGetting) Log("getting result text"); var results = GetFormResult(); // getting results element return GetFormCFOfResult(results[i]).getElementsByTagName("p"); } function GetResultImage(i) { if (logElementGetting) Log("getting result image"); var results = GetFormResult(); // getting results element return GetFormCFOfResult(results[i]).getElementsByTagName("img"); } // this function should return the question, posible answers, and image names function GetQuestionFromTest() { var questions; // the important questions var allQuestions; // all questions try // trying to get tha current questions { allQuestions = GetAllQuestionsQtext(); // getting questions if (allQuestions.length == 0) // if there are no found questions { var ddq = GetAllQuestionsDropdown(); if (EmptyOrWhiteSpace(ddq)) { var questionData = ""; for (var j = 0; j < allQuestions.length; j++) { allQuestions = GetAllQuestionsQtext()[j].childNodes; for (var i = 0; i < allQuestions.length; i++) { if (allQuestions[i].data != undefined && !EmptyOrWhiteSpace(allQuestions[i].data)) // if the current element has some text data to add { questionData += allQuestions[i].data + " "; // adding text to question data } } } questions = [questionData]; } else questions = [ddq]; } else // if there is { questions = []; for (var 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 = 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"); } return { imgnodes: imgNodes, allQ: allQuestions, q: questions }; } // gets the question from the result page // i is the index of the question function GetQuestionFromResult(i) { var temp = GetQText(i); var currQuestion = ""; if (temp.length > 0) // if the qtext element is not 0 length { currQuestion = temp[0].innerText; // adding the question to curr question as .q } else { // this is black magic fuckery a bit if (GetDropboxes(i).length > 0) // if there is dropdown list in the current question { var allNodes = GetResultText(i); currQuestion = ""; for (var k = 0; k < allNodes.length; k++) { var allQuestions = GetResultText(i)[k].childNodes; for (var j = 0; j < allQuestions.length; j++) { if (allQuestions[j].data != undefined && !EmptyOrWhiteSpace(allQuestions[j].data)) { currQuestion += allQuestions[j].data + " "; } } } } else { try { currQuestion = GetCurrQuestion(i); } catch (e) { currQuestion = "REEEEEEEEEEEEEEEEEEEEE"; // this shouldnt really happen sry guys } } } return currQuestion; } // tries to get right answer from result page // i is the index of the question function GetRightAnswerFromResult(i) { var fun = []; // the basic type of getting answers fun.push(function TryGet0(i) { var temp = GetRightAnswerIfCorrectShown(i); // getting risht answer if (temp.length > 0) // if the rightanswer element is not 0 length return temp[0].innerText; // adding the answer to curr question as .a }); // if there is dropdown list in the current question fun.push(function TryGet1(i) { if (GetDropboxes(i).length > 0) return GetCurrentAnswer(i); }); // if the correct answers are not shown, and the selected answer // is correct fun.push(function TryGet2(i) { return GetRightAnswerIfCorrectNotShown(i); }); // if there is dropbox in the question fun.push(function TryGet3(i) { return GetSelectAnswer(); }); // if the correct answers are not shown, and the selected answer // is incorrect, and there are only 2 options fun.push(function TryGet4(i) { var possibleAnswers = GetPossibleAnswers(i); if (possibleAnswers.length == 2) { for (var k = 0; k < possibleAnswers.length; k++) if (possibleAnswers[k].iscorrect == undefined) return possibleAnswers[k].value; } }); fun.push(function TryGetFinal(i) { return undefined; }); var j = 0; var currAnswer; while (j < fun.length && EmptyOrWhiteSpace(currAnswer)) { currAnswer = fun[j](i); j++; } return currAnswer; } // version 2 of getting right answer from result page // i is the index of the question function GetRightAnswerFromResultv2(i) { try { var answerNodes = GetAnswerNode(i); let items = answerNodes.nodes; if (answerNodes.type == "checkbox") return GetRightAnswerFromResult(i); for (var j = 0; j < items.length; j++) { var cn = items[j].className; if (cn.includes("correct") && !cn.includes("incorrect")) return items[j].innerText; } if (items.length == 2) { for (var j = 0; j < items.length; j++) { var cn = items[j].className; if (!cn.includes("correct")) return items[j].innerText; } } } catch (e) { Log("error at new nodegetting, trying the oldschool way"); } } //: }}} //: Main logic stuff {{{ //: Loading {{{ function Init(cwith) { if (false) // reset, only for testing! { GM_setValue("version16", undefined); GM_setValue("version15", undefined); GM_setValue("firstRun", undefined); // GM_getValue("lastVerson") == undefined => firstrun GM_setValue("showQuestions", undefined); GM_setValue("showSplash", undefined); } var url = location.href; // window location var count = -1; // loaded question count. stays -1 if the load failed. // -------------------------------------------------------------------------------------- // 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(); count = Load(cwith); // loads resources if (!url.includes(".pdf")) ShowMenu(); return count; } function VersionActions() { // FOR TESTING ONLY // GM_setValue("version15", true); // GM_setValue("firstRun", true); // GM_setValue("version16", true); // GM_setValue("version161", true); // throw "asd"; let r = FreshStart(); if (r != true) GM_setValue("version161", false); Version15(); Version16(); Version161(); } //: Version action functions {{{ function FreshStart() { var firstRun = GM_getValue("firstRun"); // if the current run is the frst if (firstRun == undefined || firstRun == true) // if its undefined, or true { GM_setValue("firstRun", false); ShowHelp(); // showing help return true; } } function Version15() { var version15 = GM_getValue("version15"); // if the current run is the frst if (version15 == undefined || version15 == true) // if its undefined, or true { GM_setValue("useNetDB", "0"); GM_setValue("version15", false); document.write( '

Moodle teszt userscript:

1.5.0 verzió: a script mostantól XMLHTTP kéréseket küld szerver fele! Erre a userscript futtató kiegészitő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.
' ); document.close(); throw "something, so this stuff stops"; } } function Version16() { var version16 = GM_getValue("version16"); // if the current run is the frst if (version16 == undefined || version16 == true) // if its undefined, or true { var i = 0; while (GM_getValue("Is" + i + "Active") != undefined) { GM_setValue("Is" + i + "Active", false); i++; } GM_setValue("version16", false); } } function Version161() { var version161 = GM_getValue("version161"); // if the current run is the frst if (version161 == undefined || version161 == true) // if its undefined, or true { GM_setValue("useNetDB", "0"); GM_setValue("version161", false); document.write( '

Moodle teszt userscript:

1.6.1.0 verzió: Új domain név: qmining.tk. Ha frissíted az oldalt, akkor tampremonkey rá fog kérdezni, hpgy engedélyezed-e a kérdések külését erre az új domain-re. A rendes működés érdekében kattints a "Allow always domain"-gombra

' ); document.close(); throw "something, so this stuff stops"; } } //: }}} function ReadFile(cwith) { var resource = ""; try { resource = GM_getResourceText("data"); // getting data from txt if (resource == null) { return; // TODO show some msg what happened } if (EmptyOrWhiteSpace(resource)) { throw { message: "data file empty" }; } } catch (e) { Exception(e, "script error at reading file:"); } NLoad(resource, cwith); } function ReadNetDB(cwith, useNetDB) { function NewXMLHttpRequest() { const url = serverAdress + "data.json"; GM_xmlhttpRequest({ method: "GET", synchronous: true, url: url, onload: function(response) { NLoad(response.responseText, cwith); }, onerror: function() { NLoad(undefined, cwith); // server down } }); } try { Log("Sending XMLHTTP Request..."); return NewXMLHttpRequest(); } catch (e) { Exception(e, "script error at reading online database:"); } } /* * Returns a question database from the given data. * Parameter should be raw read file in string with "\n"-s * TODO: ??? -s are not listed as errors, tho works correctly * */ function ParseRawData(data) { const d = data.split("\n"); const r = new QuestionDB(); var logs = []; var currSubj = ""; // the current subjects name var ExpectedIdentifier = ['+', '?']; let currQuestion = new Question(); var i = -1; while (i < d.length) { let currIdentifier; let skipped = 0; do { if (skipped >= 1) logs.push(i + ": " + d[i]); i++; if (i >= d.length) { if (currQuestion.IsComplete()) r.AddQuestion(currSubj, currQuestion); return { result: r, logs: logs }; } currIdentifier = d[i][0]; skipped++; } while (!ExpectedIdentifier.includes(currIdentifier) && i < d.length); let currData = d[i].substring(1).trim(); if (currIdentifier == '+') { if (currQuestion.IsComplete()) r.AddQuestion(currSubj, currQuestion); currQuestion = new Question(); currSubj = currData; ExpectedIdentifier = ['?']; continue; } if (currIdentifier == '?') { if (currQuestion.IsComplete()) { r.AddQuestion(currSubj, currQuestion); currQuestion = new Question(); } // overwriting is allowed here, bcus: // ?????!> currQuestion.Q = currData; ExpectedIdentifier = ['!', '?']; continue; } if (currIdentifier == '!') { // if dont have question continue if (!currQuestion.HasQuestion()) throw "No question! (A)"; // dont allow overwriting // ?!!!! if (!currQuestion.HasAnswer()) { currData = currData.replace("A helyes válaszok: ", ""); currData = currData.replace("A helyes válasz: ", ""); currQuestion.A = currData; } ExpectedIdentifier = ['?', '>', '+']; continue; } if (currIdentifier == '>') { // if dont have question or answer continue if (!currQuestion.HasQuestion()) throw "No question! (I)"; if (!currQuestion.HasAnswer()) throw "No asnwer! (I)"; // dont allow overwriting // ?!>>> if (!currQuestion.HasImage()) { try { currQuestion.I = JSON.parse(currData); } catch (e) { currQuestion.I = [currData]; } } ExpectedIdentifier = ['?', '+']; continue; } } return { result: r, logs: logs }; } function Load(cwith) { var useNetDB = GM_getValue("useNetDB"); if (useNetDB != undefined && useNetDB == 1) return ReadNetDB(cwith, useNetDB); else return ReadFile(cwith); } function LoadMOTD(resource) { try { motd = resource.motd; } catch (e) { Log("Error loading motd :c"); Log(e); } } function LoadVersion(resource) { try { lastestVersion = resource.version; } catch (e) { Log("Error loading version :c"); Log(e); } } // loading stuff function NLoad(resource, cwith) { var count = -1; var subjCount = 0; try { var d = {}; try { d = JSON.parse(resource); } catch (e) { Log("Old data, trying with old methods...."); d = ParseRawData(resource).result; } var r = new QuestionDB(); var rt = []; var allCount = -1; LoadMOTD(d); LoadVersion(d); for (var i = 0; i < d.Subjects.length; i++) { let s = new Subject(d.Subjects[i].Name); if (GM_getValue("Is" + i + "Active")) { var j = 0; for (j = 0; j < d.Subjects[i].Questions.length; j++) { var currQ = d.Subjects[i].Questions[j]; s.AddQuestion(new Question(currQ.Q, currQ.A, currQ.I)); } rt.push({ name: d.Subjects[i].Name, count: j }); allCount += j; subjCount++; } r.AddSubject(s); } data = r; count = allCount + 1; // couse starting with -1 to show errors var i = 0; while (i < data.length && !GM_getValue("Is" + i + "Active")) { i++; } if (i >= data.length) document.getElementById("HelperMenuButton").style.background = "yellow"; } catch (e) { Exception(e, "script error at loading:"); count = -1; // returns -1 if error } cwith(count, subjCount); } //: }}} //: UI handling {{{ function HandleUI(url, count, subjCount) { var newVersion = false; // if the script is newer than last start var loaded = count != -1; // if script could load stuff try // try, cus im suspicious { newVersion = GM_info.script.version !== GM_getValue("lastVerson"); } catch (e) {} var greetMsg = ""; // message to show at the end var timeout = null; // the timeout. if null, it wont be hidden // no new version, nothing loaded if (!newVersion && !loaded) // -------------------------------------------------------------------------------------------------------------- { greetMsg = "Hiba a @resource tagnál, vagy a fileval van gond! (Lehet át lett helyezve, vagy üres.) Ellenőrizd az elérési utat, vagy hogy a Tampermonkey bővítmény eléri-e a fájlokat. Ha netes forrást használsz, akkor nem elérhető a szerver! Segítségért kattints!"; } var showSplash = (GM_getValue("showSplash") == undefined) || GM_getValue("showSplash"); // getting value, if splash screen should be shown. Its true, if its undefined, or true // no new version, everything loaded, and show splash is enabled. otherwise something happened, so showing it if (!newVersion && loaded && showSplash) // ------------------------------------------------------------------------------------------------ { timeout = 5; greetMsg = "Moodle/Elearning/KMOOC segéd v. " + GM_info.script.version + ". "; if (lastestVersion != undefined && GM_info.script.version != lastestVersion) { greetMsg += "Új verzió elérhető: " + lastestVersion + " "; timeout = undefined; } greetMsg += count + " kérdés és " + subjCount + " tárgy betöltve. (click for help)."; if (data.length > 0) { var toAdd = []; for (var i = 0; i < data.length; i++) { if (data.GetIfActive(i)) { toAdd.push(data.Subjects[i].Name + " (" + data.Subjects[i].length + ")"); } } if (toAdd.length != 0) { greetMsg += "\nAktív tárgyak: " + toAdd.join(", ") + "."; } else { greetMsg += "\nNincs aktív tárgyad. Menüből válassz ki eggyet!"; timeout = undefined; } } else { greetMsg += " Az adatfájlban nem adtál meg nevet. Vagy nem elérhető a szerver. Katt a helpért!"; } } // new version, nothing loaded if (newVersion && !loaded) // -------------------------------------------------------------------------------------------------------------- { greetMsg = "Moodle/Elearning/KMOOC segéd v. " + GM_info.script.version + ". Új verzió!\n Írd át a @resouce tagnál az elírési utat! Kivéve ha üres a file, akkor töltsd fel :) Nincs kérdés betöltve! Segítséghez kattints. Changelog:\n" + lastChangeLog; // showing changelog too } // new version, everything loaded -> set lastVerson to current if (newVersion && loaded) // -------------------------------------------------------------------------------------------------------------- { greetMsg = "Moodle/Elearning/KMOOC segéd v. " + GM_info.script.version + ". " + count + " kérdés és " + subjCount + " tárgy betöltve. Verzió frissítve " + GM_info.script.version + "-re. Changelog:\n" + lastChangeLog; GM_setValue("lastVerson", GM_info.script.version); // setting lastVersion } if (!EmptyOrWhiteSpace(motd)) { var prevmotd = GM_getValue("motd"); if (prevmotd != motd) { greetMsg += "\nMOTD:\n" + motd; timeout = null; GM_setValue("motdcount", motdShowCount); GM_setValue("motd", motd); } else { var motdcount = GM_getValue("motdcount"); if (motdcount == undefined) { GM_setValue("motdcount", motdShowCount); motdcount = motdShowCount; } motdcount--; if (motdcount > 0) { greetMsg += "\nMOTD:\n" + motd; timeout = null; GM_setValue("motdcount", motdcount); } } } ShowMessage({ m: greetMsg, isSimple: true }, timeout, ShowHelp); // showing message. If "m" is empty it wont show it, thats how showSplash works. } //: }}} //: Answering stuffs {{{ function HandleQuiz() { var q = GetQuestionFromTest(); var questions = q.q; var allQuestions = q.allQ; var imgNodes = q.imgnodes; // ------------------------------------------------------------------------------------------------------ var answers = []; for (var j = 0; j < questions.length; j++) // going thru all answers { var question = RemoveUnnecesarySpaces(questions[j]); // simplifying question var result = data.Search(question, SimplifyImages(imgNodes)); var r = PrepareAnswers(result, j); if (r != undefined) answers.push(r); HighLightAnswer(result, j); // highlights the answer for the current result } console.log(GetAnswerOptions()); ShowAnswers(answers); } function PrepareAnswers(result, j) { if (result.length > 0) // if there are more than zero results { var allMessages = []; // preparing all messages for (var k = 0; k < result.length; k++) // going throuh all results { var msg = ""; // the current message if ((GM_getValue("showQuestions") == undefined) || GM_getValue("showQuestions")) // if the question should be shown { 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.HasImage()) // and adding image, if it exists { msg += "\n" + result[k].q.I; // if it has image part, adding that too } allMessages.push({ m: msg, p: result[k].match }); } return allMessages; } } function ShowAnswers(answers) { if (answers.length > 0) { // if there are more than 0 answer ShowMessage(answers); } else { ShowMessage({ m: "Nincs találat :( Kattints az üzenetre az összes kérdés/válaszért manuális kereséshez! Előfordulhat, hogy a tárgyat nem válsztottad ki a menüben.", isSimple: true }, undefined, function() { GM_openInTab(serverAdress + 'legacy', { active: true }); }); } } //: }}} //: Quiz saving {{{ function HandleResults(url) { var allResults = new QuestionDB(); SaveQuiz(GetQuiz(), data); // saves the quiz questions and answers } function ShowSaveQuizDialog(addedQ, allQ, allOutput, output, sendSuccess, sentData) { var msg = ""; if (addedQ > 0) // if there are more than 0 new question { msg = "Klikk ide a nyers adatokhoz. " + addedQ + " új kérdés! Ne felejtsd el bemásolni a fő txt-be!"; var useNetDB = GM_getValue("useNetDB"); if (useNetDB != undefined && useNetDB == 1) { if (!sendSuccess) msg += " Nem sikerült kérdéseket elküldeni szervernek. Ha gondolod utánanézhetsz."; else msg += "Az új kérdések elküldve."; } } else // if there is 0 or less new question { msg = "A kérdőívben nincsen új kérdés. Ha mégis le akarod menteni klikk ide."; if (!data) msg += " Lehet azért, mert nincs kérdés betöltve."; } // showing a message wit the click event, and the generated page ShowMessage({ m: msg, isSimple: true }, null, function() { var towrite = '

TXT-ben nem szereplő kérdések: ' + addedQ + '/' + allQ + '


' + output.replace(/\n/g, '
') + '

Összes kérdés/válasz:

' + allOutput.replace( /\n/g, '
'); var useNetDB = GM_getValue("useNetDB"); if (useNetDB != undefined && useNetDB == 1) towrite += "

Elküldött adatok:

" + sentData; document.write(towrite); document.close(); }); } function SearchSameQuestion(questionData, quiz, i) { var r = questionData.Search(quiz[i].Q); return r.length == 0 ? -1 : r.length; } // this should get the image url from a result page // i is the index of the question function GetImageFormResult(i) { var temp = null; try { var imgElements = GetResultImage(i); // trying to get image var imgURL = []; // image urls for (var j = 0; j < imgElements.length; j++) { if (!imgElements[j].src.includes("brokenfile")) // idk why brokenfile is in some urls, which are broken, so why tf are they there damn moodle { 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(ShortenString(filePart, 30))); } } if (imgURL.length > 0) { temp = JSON.stringify(imgURL); return temp; } } catch (e) {} } // saves the current quiz. questionData contains the active subjects questions function SaveQuiz(quiz, questionData) { try { if (quiz.length == 0) throw { message: "quiz length is zero!", stack: "no stack." }; var output = ""; // thefinal output var allOutput = ""; // thefinal output with all questions var allQ = 0; var addedQ = 0; var newQuestions = []; for (var i = 0; i < quiz.length; i++) // going though quiz { // searching for same questions in questionData var toAdd = ""; // this will be added to some variable depending on if its already in the database toAdd += "?" + RemoveUnnecesarySpaces(quiz[i].Q) + "\n"; // adding quiz question toAdd += "!" + RemoveUnnecesarySpaces(quiz[i].A) + "\n"; // adding quiz answer if (quiz[i].HasImage()) { toAdd += ">" + RemoveUnnecesarySpaces(quiz[i].I) + "\n"; // adding quiz image if there is any } if (SearchSameQuestion(questionData, quiz, i) == -1) // if there is no such item in the database (w/ same q and a) { output += toAdd; // adding to output newQuestions.push(quiz[i]); addedQ++; } allOutput += toAdd; // adding to all allQ++; } var sendSuccess = false; var sentData = {}; try { try { sentData.subj = GetCurrentSubjectName(); } catch (e) { sentData.subj = "NOSUBJ"; Log("unable to get subject name :c"); } var useNetDB = GM_getValue("useNetDB"); if (useNetDB != undefined && useNetDB == 1) { sentData.allData = quiz; sentData.data = newQuestions; sentData.version = GM_info.script.version; SendXHRMessage("datatoadd=" + JSON.stringify(sentData)); sendSuccess = true; } } catch (e) { Exception(e, "error at sending data to server."); } ShowSaveQuizDialog(addedQ, allQ, allOutput, output, sendSuccess, sentData); } catch (e) { Exception(e, "script error at saving quiz"); } } // getting quiz from finish page function GetQuiz() { try { var quiz = []; // final quiz stuff var results = GetFormResult(); // getting results element for (var i = 0; i < results.length - 2; i++) // going through results, except last two, idk why, dont remember, go check it man { var question = {}; // the current question // QUESTION -------------------------------------------------------------------------------------------------------------------- var q = GetQuestionFromResult(i); if (q != undefined) question.q = SimplifyQuery(q); // RIGHTANSWER --------------------------------------------------------------------------------------------------------------------- var a = GetRightAnswerFromResultv2(i); if (a == undefined) a = GetRightAnswerFromResult(i); if (a != undefined) question.a = SimplifyQuery(a); // IMG --------------------------------------------------------------------------------------------------------------------- var img = GetImageFormResult(i); question.i = img; if (question.a != undefined) // adding only if has question { quiz.push(new Question(question.q, question.a, question.i)); // adding current question to quiz } else { Log("error getting queston, or its incorrect"); Log(question); } } return quiz; } catch (e) { Exception(e, "script error at quiz parsing:"); } } //: }}} //: Helpers {{{ function SimplifyImages(imgs) { var questionImages = []; // the array for the image names in question for (var i = 0; i < imgs.length; i++) // going through all image { if (!imgs[i].src.includes("brokenfile")) // if its includes borken file its broken. Its another moodle crap. So i just wont check those { 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(RemoveUnnecesarySpaces(ShortenString(filePart, 30)))); // decodes uri codes, and removes exess spaces, and shortening it } } return questionImages; } // adds image names to image nodes function AddImageNamesToImages(imgs) { for (var i = 0; i < imgs.length; i++) // going through all image { if (!imgs[i].src.includes("brokenfile")) // if its includes borken file its broken. Its another moodle crap. So i just wont check those { 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 = 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) // keydown event listener { try { var video = 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 = GetVideoElement(); var node = CreateNodeWithText(toadd, "Miután elindítottad: Play/pause: space. Seek: Bal/jobb nyíl."); node.style.margin = "5px 5px 5px 5px"; // fancy margin } function GetMatchPercent(currData, questionParts) { var currQuestion = SimplifyQuery(currData.q); // current question simplified var match = 0; // how many times the current question matches the current question in the database for (var i = 0; i < questionParts.length; i++) // going through the question parts { if (currQuestion.includes(questionParts[i])) // if the current question from questionData includes one of the question parts { match++; } } var percent = Math.round(((match / questionParts.length) * 100).toFixed(2)); // matched words percent var lengthDifference = RemoveMultipleItems(SimplifyQuery(currQuestion).split(" ")).length - questionParts.length; percent -= Math.abs(lengthDifference) * 2; return percent; } // simple sort. function SortByPercent(results) { for (var i = 0; i < results.length; i++) { for (var j = results.length - 1; j > i; j--) { if (results[i].p < results[j].p) { var temp = results[i]; results[i] = results[j]; results[j] = temp; } } } return results; } // removes stuff like " a. q1" -> "q1" function RemoveLetterMarking(inp) { return RemoveUnnecesarySpaces(inp.substr(inp.indexOf(".") + 1, inp.length)); } // highlights the possible solutions to the current question function HighLightAnswer(results, currQuestionNumber) { try { if (results.length > 0) // if there are items in the result { var answers = 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 (var 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 (NormalizeSpaces(RemoveUnnecesarySpaces(correct)).includes(answer)) // if the correct answer includes the current answer { toColor.push(i); // adding the index type = GetInputType(answers, i); // setting the type } } } if (results[0].match == 100) // if the result is 100% correct if (type !== "radio" || toColor.length == 1) // if the type is not radio or there is exactly one correct solution for (var i = 0; i < toColor.length; i++) // going through "toColor" answers[toColor[i]].style.backgroundColor = "#8cff66"; // 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 {{{ // 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 == "") { return; } msgItem = [ [{ m: simpleMessageText }] ]; isSimpleMessage = true; } var appedtTo = document.body; // will be appended here var width = window.innerWidth - window.innerWidth / 6; // with of the box var startFromLeft = window.innerWidth / 2 - width / 2; // dont change this 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 mainDiv.style.position = "fixed"; mainDiv.style.zIndex = 999999; mainDiv.style.textAlign = "center"; mainDiv.style.width = width + 'px'; //mainDiv.style.height = height + 'px'; mainDiv.style.padding = "0px"; mainDiv.style.background = "#222d32"; // background color mainDiv.style.color = "#ffffff"; // text color mainDiv.style.borderColor = "#035a8f"; // border color mainDiv.style.border = "solid"; mainDiv.style.top = (startFromTop) + 'px'; mainDiv.style.left = (window.innerWidth - width) / 2 + 'px'; mainDiv.style.opacity = "0.9"; // setting starting opacity var matchPercent = msgItem[0][0].p; if (isSimpleMessage) { var simpleMessageParagrapg = document.createElement("p"); // new paragraph simpleMessageParagrapg.style.margin = defMargin; // fancy margin var splitText = simpleMessageText.split("\n"); for (var i = 0; i < splitText.length; i++) { var mesageNode = CreateNodeWithText(simpleMessageParagrapg, splitText[i]); 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; function GetRelevantQuestion() // returns the currItemth questions currRelevantQuestionth relevant question { return msgItem[currItem][currRelevantQuestion]; } function ChangeCurrItemIndex(to) { currItem += to; if (currItem < 0) { currItem = 0; } if (currItem > msgItem.length - 1) { currItem = msgItem.length - 1; } currRelevantQuestion = 0; } function ChangeCurrRelevantQuestionIndex(to) { currRelevantQuestion += to; if (currRelevantQuestion < 0) { currRelevantQuestion = 0; } if (currRelevantQuestion > msgItem[currItem].length - 1) { currRelevantQuestion = msgItem[currItem].length - 1; } } function 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 buttonWidth = 75; // button size ;) var buttonHeight = 55; var appedtTo = document.body; // will be appended here // mainDiv.style.left = (window.innerWidth - width) / 2 + 'px'; var menuButtonDiv = document.createElement("div"); menuButtonDiv.setAttribute("id", "HelperMenuButton"); menuButtonDiv.style.width = buttonWidth + 'px'; menuButtonDiv.style.height = buttonHeight + 'px'; menuButtonDiv.style.top = (window.innerHeight - buttonHeight * 1.5) + 'px'; menuButtonDiv.style.left = window.innerWidth - buttonWidth * 1.5 + 'px'; menuButtonDiv.style.zIndex = 999999; // TO THE MAX menuButtonDiv.style.position = "fixed"; // design menuButtonDiv.style.textAlign = "center"; menuButtonDiv.style.padding = "0px"; menuButtonDiv.style.background = "#222d32"; // background color menuButtonDiv.style.color = "#ffffff"; // text color menuButtonDiv.style.borderColor = "#035a8f"; // border color menuButtonDiv.style.border = "solid"; menuButtonDiv.style.opacity = "0.9"; // setting starting opacity // menu text var menuTextBox = CreateNodeWithText(menuButtonDiv, "Kérdések\nMenü"); menuButtonDiv.addEventListener("click", function() { if (document.getElementById("HelperMenu") == null) { ShowMenuList(); } else { document.getElementById("HelperMenu").parentNode.removeChild(document.getElementById( "HelperMenu")); } }); // adding click //addEventListener(window, 'scroll', function () { // menuButtonDiv.style.top = (pageYOffset + window.innerHeight - buttonHeight * 2) + 'px'; //}) addEventListener(window, 'resize', function() { menuButtonDiv.style.left = window.innerWidth - buttonWidth * 2 + 'px'; }); appedtTo.appendChild(menuButtonDiv); } catch (e) { Exception(e, "script error at showing menu:"); } } // shows a fancy menu list with the subjects function ShowMenuList() { try { var appedtTo = document.body; // will be appended here var menuDiv = document.createElement("div"); menuDiv.setAttribute("id", "HelperMenu"); menuDiv.style.width = (window.innerWidth / 2) + 'px'; menuDiv.style.top = (window.innerHeight / 10) + 'px'; menuDiv.style.left = window.innerWidth / 2 - (window.innerWidth / 2) / 2 + 'px'; menuDiv.style.zIndex = 999999; menuDiv.style.position = "fixed"; //design menuDiv.style.textAlign = "center"; menuDiv.style.padding = "0px"; menuDiv.style.background = "#222d32"; // background color menuDiv.style.color = "#ffffff"; // text color menuDiv.style.borderColor = "#035a8f"; // border color menuDiv.style.border = "solid"; menuDiv.style.opacity = "1"; // setting starting opacity var fiveMargin = "5px 5px 5px 5px"; var tbl = document.createElement('table'); tbl.style.margin = fiveMargin; tbl.style.textAlign = "left"; tbl.style.width = "98%"; // adding headers --------------------------------------------------------------------------------------------------------------- var subjTable = document.createElement('table'); subjTable.style.margin = fiveMargin; subjTable.style.textAlign = "left"; subjTable.style.width = "98%"; var tr = subjTable.insertRow(); var header1 = tr.insertCell(); var headerSubjInfoParagraph = CreateNodeWithText(header1, "Tárgynév [darab kérdés]", "center"); headerSubjInfoParagraph.style.margin = fiveMargin; // fancy margin var header2 = tr.insertCell(); var headerSubjInfoParagraph = CreateNodeWithText(header2, "Aktív"); headerSubjInfoParagraph.style.margin = fiveMargin; // fancy margin if (data && data.length > 0) { for (let i = 0; i < data.length; i++) { var subjRow = subjTable.insertRow(); subjRow.style.border = "1px solid #131319"; var td = subjRow.insertCell(); var text = data.Subjects[i].Name; if (data.Subjects[i].length != 0) text += " [ " + data.Subjects[i].length + "db ]"; var textBox = CreateNodeWithText(td, text); textBox.style.margin = fiveMargin; // fancy margin td = subjRow.insertCell(); var checkbox = document.createElement("input"); // new paragraph checkbox.type = "checkbox"; checkbox.style.background = "white"; checkbox.style.margin = "5px 5px 5px 5px"; // fancy margin td.appendChild(checkbox); // adding text box to main td var active = data.GetIfActive(i); checkbox.checked = active; checkbox.setAttribute("id", "HelperTextNode" + i); checkbox.addEventListener("click", function() { var checked = document.getElementById("HelperTextNode" + i).checked; data.ChangeActive(i, checked); }); // adding click } var scrollDiv = document.createElement("div"); scrollDiv.style.width = window.innerWidth / 2 + 'px'; scrollDiv.style.height = window.innerHeight - (window.innerHeight * 0.4) + "px"; scrollDiv.style.overflow = "auto"; scrollDiv.appendChild(subjTable); var subjtblrow = tbl.insertRow(); var subjtbltd = subjtblrow.insertCell(); subjtbltd.appendChild(scrollDiv); } else // if no data { var noDataRow = tbl.insertRow(); var noDataRowCell = noDataRow.insertCell(); var textBox = CreateNodeWithText(noDataRowCell, "A kérdéseket nem lehetett beolvasni. Vagy nem elérhető a szerver, vagy ha offline módot használsz, akkor hibás a fájl elérési útja, vagy a fájl maga. Olvasd el a manualt!" ); textBox.style.margin = fiveMargin; // fancy margin } // show splash tickbox ----------------------------------------------------------------------------------------------------------------------------- var splasTickboxRow = tbl.insertRow(); var splashTickboxCell = splasTickboxRow.insertCell(); var splashTickBox = document.createElement("input"); splashTickBox.type = "checkbox"; splashTickBox.checked = GM_getValue("showSplash") || false; splashTickBox.style.position = ""; //splashTickBox.style.background = "white"; splashTickBox.style.left = 10 + 'px'; splashTickBox.style.margin = "5px 5px 5px 5px"; // fancy margin splashTickBox.style.top = menuDiv.offsetHeight + 'px'; splashTickboxCell.appendChild(splashTickBox); // adding to main div splashTickBox.addEventListener("click", function() { GM_setValue("showSplash", splashTickBox.checked); }); // adding clicktextNode var splashTickBoxTextSpan = CreateNodeWithText(splashTickboxCell, "Üdvözlő üzenet mutatása minden oldalon", "span"); // show questons tickbox ----------------------------------------------------------------------------------------------------------------------------- var questionTickboxRow = tbl.insertRow(); var questionTickboxCell = questionTickboxRow.insertCell(); var questionsTickBox = document.createElement("input"); questionsTickBox.type = "checkbox"; questionsTickBox.checked = GM_getValue("showQuestions"); questionsTickBox.style.position = ""; //questionsTickBox.style.background = "white"; questionsTickBox.style.left = 10 + 'px'; questionsTickBox.style.margin = "5px 5px 5px 5px"; // fancy margin questionsTickBox.style.top = menuDiv.offsetHeight + 'px'; questionTickboxCell.appendChild(questionsTickBox); // adding to main div questionsTickBox.addEventListener("click", function() { GM_setValue("showQuestions", questionsTickBox.checked); if (!questionsTickBox.checked) { ShowMessage({ m: "Szinte mindég jó az talált válasz a kérdésre, de attól még könnyen előfordulhat, hogy rosz kérdésre írja ki a választ! Ez a opció nélkül ezt az ellenőrzési lehetőséget nem tudod kihasználni", isSimple: true }, 7); } }); // adding clicktextNode var questionsTickBoxTextSpan = CreateNodeWithText(questionTickboxCell, "Kérdések mutatása válaszhoz", "span"); // database mode listbox ----------------------------------------------------------------------------------------------------------------------------- var databasemodeListboxRow = tbl.insertRow(); var databasemodeListboxCell = databasemodeListboxRow.insertCell(); var databasemodeListbox = document.createElement("select"); databasemodeListbox.type = "checkbox"; //databasemodeListbox.checked = GM_getValue("showSplash") || false; databasemodeListbox.style.position = ""; //databasemodeListbox.style.background = "white"; databasemodeListbox.style.left = 10 + 'px'; databasemodeListbox.style.margin = "5px 5px 5px 5px"; // fancy margin databasemodeListbox.style.top = menuDiv.offsetHeight + 'px'; var databasemodeListboxText = CreateNodeWithText(questionTickboxCell, "Kérdések beszerzése:", "span"); databasemodeListboxCell.appendChild(databasemodeListboxText); databasemodeListboxCell.appendChild(databasemodeListbox); // adding to main div databasemodeListbox.addEventListener("change", function(e) { // sorry for using selectedindex :c GM_setValue("useNetDB", databasemodeListbox.selectedIndex); }); var uselocal = document.createElement('option'); uselocal.text = "Helyi fájlból (old school)"; uselocal.value = 2; databasemodeListbox.add(uselocal, 0); var usenetsafe = document.createElement('option'); usenetsafe.text = "Netről"; usenetsafe.value = 0; databasemodeListbox.add(usenetsafe, 1); var selected = GM_getValue("useNetDB"); if (selected != undefined) databasemodeListbox.selectedIndex = selected; var databasemodeListboxElement = document.createElement("span"); // new paragraph databasemodeListboxCell.appendChild(databasemodeListboxElement); // setting up buttons var buttonRow = tbl.insertRow(); var buttonCell = buttonRow.insertCell(); buttonCell.style.textAlign = 'center'; // x button ------------------------------------------------------------------------------------------------------------------------------ var xButton = CreateNodeWithText(buttonCell, "Bezárás", "button"); xButton.style.position = ""; xButton.style.background = "white"; xButton.style.left = 10 + 'px'; xButton.style.margin = "5px 5px 5px 5px"; // fancy margin xButton.style.top = menuDiv.offsetHeight + 'px'; xButton.addEventListener("click", function() { document.getElementById("HelperMenu").parentNode.removeChild(document.getElementById( "HelperMenu")); }); // adding clicktextNode // help button ---------------------------------------------------------------------------------------------------------------- var helpButton = CreateNodeWithText(buttonCell, "Help", "button"); helpButton.style.position = ""; helpButton.style.background = "white"; helpButton.style.left = 10 + 'px'; helpButton.style.margin = "5px 5px 5px 5px"; // fancy margin helpButton.style.top = menuDiv.offsetHeight + 'px'; helpButton.addEventListener("click", function() { ShowHelp(); }); // adding clicktextNode // site link ---------------------------------------------------------------------------------------------------------------- var siteLink = CreateNodeWithText(buttonCell, "Help", "button"); siteLink.innerText = "Weboldal"; siteLink.addEventListener("click", function() { location.href = serverAdress + "menuClick"; }); //addEventListener(window, 'scroll', function () { // menuDiv.style.top = (pageYOffset + window.innerHeight / 3) + 'px'; //}) addEventListener(window, 'resize', function() { menuDiv.style.left = window.innerWidth / 2 + 'px'; }); menuDiv.appendChild(tbl); appedtTo.appendChild(menuDiv); } catch (e) { Exception(e, "script error at showing menu list:"); } } //: }}} //: Generic utils {{{ function RemoveMultipleItems(array) { var newArray = []; for (var i = 0; i < array.length; i++) { var j = 0; while (j < newArray.length && newArray[j] !== array[i]) { j++; } if (j >= newArray.length) { newArray.push(array[i]); } } return newArray; } // removes some crap from "q" function SimplifyQuery(q) { var result = q.replace(/\n/g, "").replace(/\s/g, ' '); // WHY TF ARE THERE TWO KINDA SPACES??? (charcode 160 n 32) return RemoveUnnecesarySpaces(result); } function ShortenString(toShorten, ammount) { var result = ""; var i = 0; while (i < toShorten.length && i < ammount) { result += toShorten[i]; i++; } return result; } 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; } // removes whitespace from begining and and, and replaces multiple spaces with one space function RemoveUnnecesarySpaces(toremove) { toremove = NormalizeSpaces(toremove); while (toremove.includes(" ")) // while the text includes double spaces replaces all of them with a single one { toremove = toremove.replace(/ /g, " "); } return toremove.trim(); } // simplifies a string for easier comparison function SimplifyStringForComparison(value) { value = RemoveUnnecesarySpaces(value).toLowerCase(); var removableChars = [",", ".", ":", "!"]; for (var i = 0; i < removableChars.length; i++) { var regex = new RegExp(removableChars[i], "g"); value.replace(regex, ""); } return value; } // if the value is empty, or whitespace function 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 function NormalizeSpaces(input) { return input.replace(/\s/g, ' '); } function SendXHRMessage(message) { var url = serverAdress + "isAdding"; GM_xmlhttpRequest({ method: "POST", url: url, data: message, headers: { "Content-Type": "application/x-www-form-urlencoded" }, onerror: function(response) { Log("XMLHTTP request POST error"); } }); } //: }}} //: Help {{{ // shows some neat help function ShowHelp() { GM_openInTab(serverAdress + 'manual', { 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.