X-Git-Url: http://git.shiar.nl/sheet.git/blobdiff_plain/557e9a9b737294f5e170f8f5474ff750ab72cb4a..c7530c743eb2d8f45167ae0a9ed641559a4d550e:/word/quiz.js diff --git a/word/quiz.js b/word/quiz.js index 70f8500..1aaab61 100644 --- a/word/quiz.js +++ b/word/quiz.js @@ -1,21 +1,93 @@ Array.prototype.shuffle = function () { - return this.sort(() => {return .5 - Math.random()}); + for (let i = this.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); // random index 0..i + [this[i], this[j]] = [this[j], this[i]]; // swap elements + } + return this; +}; + +Set.prototype.filter = function (f) { + return new Set([...this].filter(f)); }; class WordQuiz { dataselect(json) { - let rows = Object.values(json); + this.data = this.datafilter(json); + let rows = Object.values(this.data); + rows = rows.filter(row => !row[3].length); // remove referenced categories return rows.shuffle(); } + datafilter(json) { + // find viable rows from json data + let ids = new Set(Object.keys(json)); + const selection = {...json}; // clone + + if (this.preset.cat !== undefined) { + ids.clear(); + let children = [this.preset.cat]; + for (let loop = 0; children.length && loop < 20; loop++) { + for (let child of children) ids.add(child.toString()); + children = children.map(cat => json[cat][3]).filter(is => is).flat() + } + } + if (this.preset.image) { + ids = ids.filter(id => json[id][2]); + } + if (this.preset.level !== undefined) { + ids = ids.filter(id => json[id][1] <= this.preset.level); + } + + // keep only wanted ids + for (let id in selection) { + if (id && !ids.has(id)) { + delete selection[id]; + } + } + + // retain orphaned references in grandparent categories + for (let id in selection) { + selection[id][3] = function subresolve(subs) { + //console.log(subs); + return (subs || []).flatMap(sub => + sub in selection ? [sub] : subresolve(json[sub][3]) + ); + }(selection[id][3]); + } + return selection; + } + load(dataurl) { + this.preset = {}; + let input; + if (input = window.location.hash.match(/\d+/)) { + this.preset.cat = parseInt(input[0]); + } + if (window.location.hash.match(/a/)) { + this.preset.level = 3; + } + fetch(dataurl).then(res => res.json()).then(json => { this.words = this.dataselect(json) this.setup(); }); } + log(...args) { + this.history.push([new Date().toISOString(), ...args]); + } + + stop(...args) { + this.log(...args); + window.onbeforeunload = null; + fetch('/word/report', {method: 'POST', body: JSON.stringify(this.history)}); + } + constructor(dataurl) { this.load(dataurl); + this.history = []; + window.onbeforeunload = e => { + this.stop('abort'); + }; } }