From 72f7bde190e41b0f61d2bfce27626380f069dc4e Mon Sep 17 00:00:00 2001 From: MrFry Date: Mon, 14 Oct 2019 15:27:49 +0200 Subject: [PATCH] Removed main.js and fram.js, updated readme, sending version on lred --- README.md | 9 - frame.js | 47 -- main.js | 2162 ------------------------------------------------ stable.user.js | 5 +- 4 files changed, 3 insertions(+), 2220 deletions(-) delete mode 100644 frame.js delete mode 100644 main.js diff --git a/README.md b/README.md index 1943820..64df06d 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,6 @@ This userscript shows help during solving Moodle/Elearning/KMOOC tests online. Server repository link -If you want to install from here then: - Open a blank text file - Paste everything from frame.js - Paste main.js between '(function() {' and '})();' - Search for 'function Main', and type Main(); right before it - -You could also add '// (AT)require file:///main.js' to frame.js, and simply call 'Main();' -there. - diff --git a/frame.js b/frame.js deleted file mode 100644 index 8186c33..0000000 --- a/frame.js +++ /dev/null @@ -1,47 +0,0 @@ -/* ---------------------------------------------------------------------------- - - 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 . - - ------------------------------------------------------------------------- */ - -// ==UserScript== -// @name Moodle/Elearning/KMOOC test help -// @version 1.6.4.3 -// @description Online Moodle/Elearning/KMOOC test help -// @author MrFry -// @match https://elearning.uni-obuda.hu/main/* -// @match https://elearning.uni-obuda.hu/kmooc/* -// @match https://mooc.unideb.hu/* -// @grant GM_getResourceText -// @grant GM_info -// @grant GM_getValue -// @grant GM_setValue -// @grant GM_xmlhttpRequest -// @grant GM_openInTab -// @license GNU General Public License v3.0 or later -// @supportURL qmining.frylabs.net -// @contributionURL qmining.frylabs.net -// @namespace https://qmining.frylabs.net -// @updateURL https://qmining.frylabs.net/moodle-test-userscript/stable.user.js -// ==/UserScript== - -(function() { - - - -})(); diff --git a/main.js b/main.js deleted file mode 100644 index ee33c22..0000000 --- a/main.js +++ /dev/null @@ -1,2162 +0,0 @@ -// 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 . - - ------------------------------------------------------------------------- */ - -// ------------------------------------------------------------------------------ - -// 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 openInTab (address, options) { GM_openInTab(address, options) } -function xmlhttpRequest (opts) { GM_xmlhttpRequest(opts) } -function info () { return GM_info } -/* eslint-enable */ - -var data // all data, which is in the resource txt -var addEventListener // add event listener function -const lastChangeLog = 'Kérdés parsolás bugfixek, old school fálj beolvasás kiszedése, részletesebb hibajelentés és egyéb fixek' -const serverAdress = 'https://qmining.frylabs.net/' - -// 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 */ -var motd = '' -var lastestVersion = '' - -const minResultMatchPercent = 99 /* Minimum ammount to consider that two questions match during saving */ - -// : question-classes {{{ -const commonUselessAnswerParts = [ - 'A helyes válasz az ', - 'A helyes válasz a ', - 'A helyes válaszok: ', - 'A helyes válaszok:', - 'A helyes válasz: ', - 'A helyes válasz:', - 'The correct answer is:', - '\'' -] -const commonUselessStringParts = [',', '\\.', ':', '!'] -const lengthDiffMultiplier = 10 /* Percent minus for length difference */ -const minMatchAmmount = 60 /* Minimum ammount to consider that two questions match during answering */ - -const assert = (val) => { - if (!val) { throw new Error('Assertion failed') } -} - -class StringUtils { - RemoveStuff (value, removableStrings) { - removableStrings.forEach((x) => { - var regex = new RegExp(x, 'g') - value = value.replace(regex, '') - }) - return value - } - - 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() - } - - // simplifies a string for easier comparison - SimplifyStringForComparison (value) { - assert(value) - - value = this.RemoveUnnecesarySpaces(value).toLowerCase() - return this.RemoveStuff(value, commonUselessStringParts) - } - - RemoveSpecialChars (value) { - assert(value) - - return this.RemoveStuff(value, ['&']) - } - - // 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, ' ') - } - - CompareString (s1, s2) { - if (!s1 || !s2) { - return 0 - } - - s1 = this.SimplifyStringForComparison(s1).split(' ') - s2 = this.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 * lengthDiffMultiplier - if (percent < 0) { percent = 0 } - return percent - } - - AnswerPreProcessor (value) { - assert(value) - - return this.RemoveStuff( - value, commonUselessAnswerParts) - } - - // 'a. pécsi sör' -> 'pécsi sör' - RemoveAnswerLetters (value) { - assert(value) - - let s = value.split('. ') - if (s[0].length < 2 && s.length > 1) { - s.shift() - return s.join(' ') - } else { - return value - } - } - - SimplifyQA (value, mods) { - if (!value) { return } - - const reducer = (res, fn) => { - return fn(res) - } - - return mods.reduce(reducer, value) - } - - SimplifyAnswer (value) { - return this.SimplifyQA( - value, - [ - this.RemoveSpecialChars.bind(this), - this.RemoveUnnecesarySpaces.bind(this), - this.AnswerPreProcessor.bind(this), - this.RemoveAnswerLetters.bind(this) - ]) - } - - SimplifyQuestion (value) { - return this.SimplifyQA( - value, - [ - this.RemoveSpecialChars.bind(this), - this.RemoveUnnecesarySpaces.bind(this) - ]) - } - - SimplifyStack (stack) { - return this.SimplifyQuery(stack) - } -} - -const SUtils = new StringUtils() - -class Question { - constructor (q, a, i) { - this.Q = SUtils.SimplifyQuestion(q) - this.A = SUtils.SimplifyAnswer(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 && (typeof this.I === 'string' || Array.isArray(this.I)) - } - - IsComplete () { - return this.HasQuestion() && this.HasAnswer() - } - - Compare (q2, i) { - assert(q2) - - if (typeof q2 === 'string') { - var qmatchpercent = SUtils.CompareString(this.Q, q2) - - if (i === undefined || i.length === 0) { return qmatchpercent } else { - if (this.HasImage()) { - const imatchpercent = this.HasImage() ? SUtils.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 = SUtils.CompareString(this.Q, q2.Q) - const amatchpercent = SUtils.CompareString(this.A, q2.A) - if (this.I !== undefined) { - const imatchpercent = this.I === undefined ? SUtils.CompareString(this.I.join(' '), q2.I.join( - ' ')) : 0 - return (qmatchpercent + amatchpercent + imatchpercent) / 3 - } else { - return (qmatchpercent + amatchpercent) / 2 - } - } - } -} - -class Subject { - constructor (n) { - assert(n) - - this.Name = n - this.Questions = [] - this.active = false - } - - setIndex (i) { - this.index = i - } - - getIndex () { - return this.index || -1 - } - - get length () { - return this.Questions.length - } - - markActive () { - this.active = true - } - - getIfActive () { - return this.active - } - - AddQuestion (q) { - assert(q) - - this.Questions.push(q) - } - - getSubjNameWithoutYear () { - let t = this.Name.split(' - ') - if (t[0].match(/^[0-9]{4}\/[0-9]{2}\/[0-9]{1}$/i)) { - return t[1] || '' - } else { - return '' - } - } - - getYear () { - let t = this.Name.split(' - ')[0] - if (t.match(/^[0-9]{4}\/[0-9]{2}\/[0-9]{1}$/i)) { - return t - } else { - return '' - } - } - - Search (q, img) { - assert(q) - - var r = [] - for (let 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 (let 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 (getVal, setVal) { - this.Subjects = [] - this.getVal = getVal - this.setVal = setVal - } - - get length () { - return this.Subjects.length - } - - get activeIndexes () { - var r = [] - for (var i = 0; i < this.length; i++) { - if (this.getVal('Is' + i + 'Active')) { - r.push(i) - } - } - return r - } - - GetIfActive (ind) { - return this.getVal('Is' + ind + 'Active') - } - - ChangeActive (i, value) { - this.setVal('Is' + i + 'Active', !!value) - } - - AddQuestion (subj, q) { - assert(subj) - - 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) { - assert(q) - - var r = [] - for (let i = 0; i < this.length; i++) { - if (this.GetIfActive(i)) { r = r.concat(this.Subjects[i].Search(q, img)) } - } - - for (let 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) { - assert(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') - } -} - -// : }}} - -// : DOM getting stuff {{{ -// all dom getting stuff are in this sections, so on -// moodle dom change, stuff breaks here - -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') } - return document.getElementById('responseform').getElementsByClassName('qtext') // getting questions - } - - GetAllQuestionsP () { - if (logElementGetting) { Log('getting all questions by tag p') } - return document.getElementById('responseform').getElementsByTagName('p') - } - - 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++) { - // TODO: test dis - 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) { - 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 { - 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 () { - 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 - } - } - - 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 - } - - 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 = [] - - // the basic type of getting answers - fun.push(function TryGet0 (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(function TryGet1 (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(function TryGet2 (i) { - return RPM.GetRightAnswerIfCorrectNotShown(i) - }) - - // if there is dropbox in the question - fun.push(function TryGet3 (i) { - return RPM.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 = RPM.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 && SUtils.EmptyOrWhiteSpace(currAnswer)) { - try { - currAnswer = fun[j](i) - } catch (e) { - } - j++ - } - - return currAnswer - } - - // 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].innerText } - } - if (items.length === 2) { - for (let j = 0; j < items.length; j++) { - let cn = items[j].className - if (!cn.includes('correct')) { return items[j].innerText } - } - } - } 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 {{{ -function Main () { - 'use strict' - console.time('main') - - Init(function (count, subjCount) { - var url = location.href // eslint-disable-line - - let skipLoad = getVal('skipLoad') - if (count === -2 && subjCount === -2 && skipLoad) { - if (url.includes('/quiz/') && url.includes('attempt.php')) { - ShowMessage({ - m: 'Passzív mód bekapcsolva, válaszok megjelenítéséhez menü gomb alatt kapcsold ki, és frissíts!', - isSimple: true - }) - } - } else { - 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, () => { - OpenErrorPage(e) - }) - - Exception(e, 'script error at main:') - } - if (url.includes('eduplayer')) { 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.' - ) - } - }) - - console.log('Moodle Test Script run time:') - console.timeEnd('main') - - if (forceTestPage || forceResultPage || forceDefaultPage) { - if (document.getElementById('scriptMessage')) { document.getElementById('scriptMessage').style.background = 'green' } - } -} -// : }}} - -// : Main logic stuff {{{ - -// : Loading {{{ - -function Init (cwith) { - if (false) { // eslint-disable-line - setVal('version16', undefined) - setVal('version15', undefined) - setVal('firstRun', undefined) - setVal('showQuestions', undefined) - setVal('showSplash', undefined) - } - var url = location.href // eslint-disable-line - 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 - // setVal("version15", true); - // setVal("firstRun", true); - // setVal("version16", true); - // throw "asd"; - - FreshStart() - - Version15() - Version16() -} - -// : 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 - return true - } -} - -function Version15 () { - var version15 = getVal('version15') // if the current run is the frst - if (version15 === undefined || version15 === true) { - setVal('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 new Error('something, so this stuff stops') - } -} - -function Version16 () { - var version16 = getVal('version16') // if the current run is the frst - if (version16 === undefined || version16 === true) { - var i = 0 - while (getVal('Is' + i + 'Active') !== undefined) { - setVal('Is' + i + 'Active', false) - i++ - } - setVal('version16', false) - } -} - -// : }}} - -function ReadNetDB (cwith) { - function NewXMLHttpRequest () { - const url = serverAdress + 'data.json' - 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:') - } -} - -function Load (cwith) { - let skipLoad = getVal('skipLoad') - - if (skipLoad) { - cwith(-2, -2) - return -1 - } - - ReadNetDB(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) { - assert(resource) - - var count = -1 - var subjCount = 0 - try { - var d = {} - try { - d = JSON.parse(resource) - } catch (e) { - Log('Old data, trying with old methods....') - Log('Couldt parse data!') - Log(e) - ShowMessage({ - m: 'Nem sikerült betölteni az adatokat! Kattints a manualért', - isSimple: true - }, undefined, ShowHelp) - } - var r = new QuestionDB(getVal, setVal) - var rt = [] - var allCount = -1 - LoadMOTD(d) - LoadVersion(d) - - for (let i = 0; i < d.Subjects.length; i++) { - let s = new Subject(d.Subjects[i].Name) - s.setIndex(i) - if (getVal('Is' + i + 'Active')) { - s.markActive() - 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 - - let i = 0 - while (i < data.length && !getVal('Is' + i + 'Active')) { - i++ - } - } catch (e) { - Exception(e, 'script error at loading:') - count = -1 // returns -1 if error - } - cwith(count, subjCount) -} - -function AlertOnNoQuestion () { - try { - document.getElementById('HelperMenuButton').style.background = 'yellow' - } catch (e) { - Log('Unable to get helper menu button') - } -} - -// : }}} - -// : 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 { - newVersion = info().script.version !== getVal('lastVerson') - } catch (e) { - Log('Some weird error trying to set new verison') - } - 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, vagy nincs tárgy kiválasztva) Vagy válaszd a netes adatok használatát menüben. 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 = (getVal('showSplash') === undefined) || getVal('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. ' + info().script.version + '. ' - - if (lastestVersion !== undefined && info().script.version !== lastestVersion) { - greetMsg += 'Új verzió elérhető: ' + lastestVersion + '\n' - 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 { - AlertOnNoQuestion() - 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. ' + 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. ' + info().script.version + '. ' + count + ' kérdés és ' + subjCount + ' tárgy betöltve. Verzió frissítve ' + info().script.version + '-re. Changelog:\n' + lastChangeLog - setVal('lastVerson', info().script.version) // setting lastVersion - } - if (!SUtils.EmptyOrWhiteSpace(motd)) { - var prevmotd = getVal('motd') - if (prevmotd !== motd) { - greetMsg += '\nMOTD:\n' + motd - timeout = null - setVal('motdcount', motdShowCount) - setVal('motd', motd) - } else { - var motdcount = getVal('motdcount') - if (motdcount === undefined) { - setVal('motdcount', motdShowCount) - motdcount = motdShowCount - } - - motdcount-- - if (motdcount > 0) { - greetMsg += '\nMOTD:\n' + motd - timeout = null - setVal('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 = QPM.GetQuestionFromTest() - var questions = q.q - var imgNodes = q.imgnodes - // ------------------------------------------------------------------------------------------------------ - var answers = [] - for (var j = 0; j < questions.length; j++) { - var question = SUtils.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 - } - 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.HasImage()) { - 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, question) { - assert(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 () { - OpenErrorPage({ - message: 'No result found', - stack: JSON.stringify(question) - }) - }) - } -} - -// : }}} - -// : Quiz saving {{{ - -function HandleResults (url) { - var d = SaveQuiz(GetQuiz(), data) // saves the quiz questions and answers - - if (d) { ShowSaveQuizDialog(d.addedQ, d.allQ, d.allOutput, d.output, d.sendSuccess, d.sentData) } -} - -function ShowSaveQuizDialog (addedQ, allQ, allOutput, output, sendSuccess, sentData) { - var msg = '' - if (addedQ > 0) { - msg = 'Klikk ide a nyers adatokhoz. ' + addedQ + ' új kérdés!' - - 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 { - 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 = '

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


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

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

' + allOutput.replace( - /\n/g, '
') - - try { - towrite += '

Elküldött adatok:

' + JSON.stringify(sentData) - } catch (e) { - towrite += '

Elküldött adatok:

' + sentData - } - document.write(towrite) - document.close() - }) -} - -function SearchSameQuestion (questionData, quiz, i) { - var r = questionData.Search(quiz[i]) - - let count = 0 - r.forEach((item) => { - if (item.match > minResultMatchPercent) { count++ } - }) - - return count === 0 ? -1 : count -} - -// 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 = 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) { - temp = JSON.stringify(imgURL) - return temp - } - } catch (e) { - Log("Couldn't get images from result") - } -} - -// saves the current quiz. questionData contains the active subjects questions -function SaveQuiz (quiz, questionData) { - try { - if (quiz.length === 0) { - throw new Error('quiz length is zero!') - } - 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++) { - // searching for same questions in questionData - var toAdd = '' // this will be added to some variable depending on if its already in the database - toAdd += '?' + SUtils.RemoveUnnecesarySpaces(quiz[i].Q) + '\n' // adding quiz question - toAdd += '!' + SUtils.RemoveUnnecesarySpaces(quiz[i].A) + '\n' // adding quiz answer - if (quiz[i].HasImage()) { - toAdd += '>' + SUtils.RemoveUnnecesarySpaces(quiz[i].I) + '\n' // adding quiz image if there is any - } - if (SearchSameQuestion(questionData, quiz, i) === -1) { - 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 = MPM.GetCurrentSubjectName() - } catch (e) { - sentData.subj = 'NOSUBJ' - Log('unable to get subject name :c') - } - sentData.allData = quiz - sentData.data = newQuestions - sentData.version = info().script.version - SendXHRMessage('datatoadd=' + JSON.stringify(sentData)) - sendSuccess = true - } catch (e) { - Exception(e, 'error at sending data to server.') - } - return { - addedQ: addedQ, - allQ: allQ, - allOutput: allOutput, - output: output, - sendSuccess: sendSuccess, - sentData: 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 = RPM.GetFormResult() // getting results element - for (var i = 0; i < results.length - 2; i++) { - var question = {} // the current question - // QUESTION -------------------------------------------------------------------------------------------------------------------- - var q = RPM.GetQuestionFromResult(i) - if (q !== undefined) { question.q = SUtils.SimplifyQuery(q) } - - // RIGHTANSWER --------------------------------------------------------------------------------------------------------------------- - var a = RPM.GetRightAnswerFromResultv2(i) - if (a === undefined) { a = RPM.GetRightAnswerFromResult(i) } - if (a !== undefined) { question.a = SUtils.SimplifyQuery(a) } - // IMG --------------------------------------------------------------------------------------------------------------------- - var img = GetImageFormResult(i) - question.i = img - - if (question.a !== undefined) { - quiz.push(new Question(question.q, question.a, question.i)) // 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 SimplifyImages (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 - } - } - return questionImages -} - -// 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, - 'Miután elindítottad: Play/pause: space. Seek: Bal/jobb nyíl.') - 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) { // TODO why not radio - for (let 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 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 = 'none' - mainDiv.style.top = (startFromTop) + 'px' - mainDiv.style.left = (window.innerWidth - width) / 2 + 'px' - mainDiv.style.opacity = '0.9' // setting starting opacity - 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 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 - - 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'; - // }) - 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 = 100 // button size ;) - var buttonHeight = 85 - var appedtTo = document.body // will be appended here - - // mainDiv.style.left = (window.innerWidth - width) / 2 + 'px'; - - var menuButtonDiv = document.createElement('div') - 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' - // menuButtonDiv.style.borderStyle = "solid"; - // menuButtonDiv.style.borderWidth = "1px"; - - // design - menuButtonDiv.style.textAlign = 'center' - menuButtonDiv.style.padding = '0px' - menuButtonDiv.style.margin = '0px' - menuButtonDiv.style.background = 'transparent' // background color - - // menu text - // var menuTextBox = CreateNodeWithText(menuButtonDiv, "Kérdések\nMenü"); - - var menuButton = CreateNodeWithText(menuButtonDiv, 'Kérdések Menu', 'button') - menuButton.style.width = buttonWidth + 'px' - menuButton.style.border = 'none' - menuButton.style.height = buttonHeight - 20 + 'px' - menuButton.style.background = '#222d32' // background color - menuButton.style.color = '#ffffff' // background color - menuButton.setAttribute('id', 'HelperMenuButton') - - menuButton.addEventListener('click', function () { - if (document.getElementById('HelperMenu') == null) { - ShowMenuList() - } else { - CloseMenu() - } - }) // adding click - - // passive mode stuff - var questionsTickBox = document.createElement('input') - questionsTickBox.type = 'checkbox' - questionsTickBox.checked = getVal('skipLoad') - questionsTickBox.style.position = '' - questionsTickBox.style.left = 10 + 'px' - questionsTickBox.style.margin = '5px 5px 5px 5px' // fancy margin - questionsTickBox.style.top = 0 + 'px' - - menuButtonDiv.appendChild(questionsTickBox) // adding to main div - - questionsTickBox.addEventListener('click', function () { - setVal('skipLoad', questionsTickBox.checked) - var msg = '' - if (getVal('skipLoad')) { msg = 'Passzív mód bekapcsolva, mostantól kérdések nem lesznek betöltve/lekérve.' } else { msg = 'Passzív mód kikapcsolva, frissíts az érvénybe lépéshez!' } - - ShowMessage({ - m: msg, - isSimple: true - }, 6) - }) - var loadDataCheckBoxText = CreateNodeWithText(questionsTickBox, - 'Passzív mód', 'span') - loadDataCheckBoxText.style.fontSize = '12px' - - menuButtonDiv.appendChild(loadDataCheckBoxText) - - 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 = 'none' - 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('div') - 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 headerSubjInfoParagraph2 = CreateNodeWithText(header2, 'Aktív') - // headerSubjInfoParagraph2.style.margin = fiveMargin // fancy margin - - if (data && data.length > 0) { - let grouped = data.Subjects.reduce((res, s) => { - let sName = s.getSubjNameWithoutYear() - if (sName) { - if (!res[sName]) { - res[sName] = [] - } - res[sName].push(s) - } else { - res.others.push(s) - } - return res - }, { - others: [] - }) - - let collapsibles = [] - - Object.entries(grouped).forEach(([subjName, subjGroup]) => { - let b = CreateNodeWithText(subjTable, subjName, 'button') - b.style.backgroundColor = '#222d32' - b.style.color = '#ffffff' - b.style.cursor = 'pointer' - b.style.padding = '5px' - b.style.width = '100%' - b.style.border = 'none' - b.style.textAlign = 'left' - b.style.outline = 'none' - collapsibles.push(b) - - let content = document.createElement('div') - content.style.padding = '0 18px' - content.style.overflow = 'hidden' - content.style.backgroundColor = '#222d32' - content.style.borderColor = '#212127' - content.style.borderStyle = 'solid' - content.style.borderWidth = '5px' - let ifGroupActive = subjGroup.some((x) => { - return x.getIfActive() - }) - content.style.display = ifGroupActive ? 'block' : 'none' - - subjTable.appendChild(content) - - subjGroup.forEach((subj) => { - let tbl = document.createElement('table') - content.appendChild(tbl) - - var row = tbl.insertRow() - let td = row.insertCell() - let text = subj.getYear() || subj.Name - if (subj.length !== 0) { text += ' [ ' + subj.length + 'db ]' } - CreateNodeWithText(td, text) - - td = row.insertCell() - let 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 - - checkbox.checked = subj.active - let i = subj.getIndex() - checkbox.setAttribute('id', 'HelperTextNode' + i) - checkbox.addEventListener('click', function () { - var checked = document.getElementById('HelperTextNode' + i).checked - data.ChangeActive(i, checked) - }) // adding click - }) - }) - - collapsibles.forEach((x) => { - x.addEventListener('click', function () { - this.classList.toggle('active') - var content = this.nextElementSibling - if (content.style.display === 'block') { - content.style.display = 'none' - } else { - content.style.display = 'block' - } - }) - }) - - var scrollDiv = document.createElement('div') - scrollDiv.style.width = '100%' - 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() - let textBox - - if (getVal('skipLoad')) { - textBox = CreateNodeWithText(noDataRowCell, - 'Passszív mód bekapcsolva. Kapcsold ki a kérdések betöltéséhez!' - ) - } else { - 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 = getVal('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 () { - setVal('showSplash', splashTickBox.checked) - }) // adding clicktextNode - - 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 = getVal('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 () { - setVal('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 - - CreateNodeWithText(questionTickboxCell, 'Kérdések mutatása válaszhoz', 'span') - - // 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.left = 10 + 'px' - xButton.style.margin = '5px 5px 5px 5px' // fancy margin - xButton.style.top = menuDiv.offsetHeight + 'px' - - xButton.addEventListener('click', function () { - CloseMenu() - }) // adding clicktextNode - // help button ---------------------------------------------------------------------------------------------------------------- - var helpButton = CreateNodeWithText(buttonCell, 'Help', 'button') - - helpButton.style.position = '' - 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' // eslint-disable-line - }) - - // 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:') - } - - document.addEventListener('keydown', EscClose) -} - -function EscClose (e) { - if (e.keyCode === 27) { CloseMenu() } -} - -function CloseMenu () { - document.getElementById('HelperMenu').parentNode.removeChild(document.getElementById( - 'HelperMenu')) - - document.removeEventListener('keydown', EscClose) -} - -// : }}} - -// : Generic utils {{{ - -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 SendXHRMessage (message) { - var url = serverAdress + 'isAdding' - xmlhttpRequest({ - method: 'POST', - url: url, - data: message, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - onerror: function (response) { - Log('XMLHTTP request POST error') - } - }) -} - -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 = 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', { - 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. diff --git a/stable.user.js b/stable.user.js index 20fa7c1..e76bbd9 100644 --- a/stable.user.js +++ b/stable.user.js @@ -40,7 +40,7 @@ // @updateURL https://qmining.frylabs.net/moodle-test-userscript/stable.user.js // ==/UserScript== -(function() { +(function() { // eslint-disable-line // GM functions, only to disable ESLINT errors /* eslint-disable */ const a = Main @@ -2135,6 +2135,7 @@ 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') @@ -2180,4 +2181,4 @@ // O deepest wound of all that he should die // On that darkest day. -})(); +})(); // eslint-disable-line