X-Git-Url: http://git.shiar.nl/sheet.git/blobdiff_plain/20332e82f5c6365a8d65c75192985d846a99a2dd..9b8d7e610cef31f15f12c1058dfd45efffac5fb0:/word/quiz.js diff --git a/word/quiz.js b/word/quiz.js index d32368b..f47fde1 100644 --- a/word/quiz.js +++ b/word/quiz.js @@ -6,61 +6,79 @@ Array.prototype.shuffle = function () { return this; }; +Set.prototype.filter = function (f) { + return new Set([...this].filter(f)); +}; + class WordQuiz { dataselect(json) { - this.data = json; - this.cats = {}; // category lookup - for (let i in json) { - let cat = json[i][3]; - if (this.cats[cat]) { - this.cats[cat].push(i); - } - else { - this.cats[cat] = [i]; - } - } - return this.datafilter(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 rows = Object.values(json); + let ids = new Set(Object.keys(json)); + const selection = {...json}; // clone + + for (let cat of selection[''][3]) { + if (selection[cat]) + selection[cat][1] = 0; // keep root categories + } if (this.preset.cat !== undefined) { - rows = []; - let children = this.cats[this.preset.cat]; + ids.clear(); + let children = this.preset.cat; for (let loop = 0; children.length && loop < 20; loop++) { - rows.push(...children); - children = children.map(cat => this.cats[cat]).filter(is => is).flat(); + for (let child of children) ids.add(child.toString()); + children = children.map(cat => json[cat][3]).filter(is => is).flat() } - rows = rows.map(row => json[row]).filter(row => row[2]); + } + if (this.preset.images) { + ids = ids.filter(id => json[id][2]); } if (this.preset.level !== undefined) { - rows = rows.filter(row => row[1] <= this.preset.level); + ids = ids.filter(id => json[id][1] <= this.preset.level); } - { - let cats = new Set(); - let subcats = rows.map(row => row[3]); // direct parents - for (let loop = 0; subcats.length && loop < 20; loop++) { - subcats.forEach(cat => cats.add(cat)); - subcats = subcats.map(row => json[row] && json[row][3]).filter(val => val); // recurse grandparents + // keep only wanted ids + for (let id in selection) { + if (id && !ids.has(id)) { + delete selection[id]; } - rows = rows.filter(row => !cats.has(row[2])); // remove referenced categories } - return rows.shuffle(); - } - load(dataurl) { - this.preset = {}; - let input; - if (input = window.location.hash.match(/\d+/)) { - this.preset.cat = input[0]; + // 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] : json[sub] ? subresolve(json[sub][3]) : [] + ); + }(selection[id][3]); } - if (window.location.hash.match(/a/)) { - this.preset.level = 3; + return selection; + } + + configure(params) { + const opts = new Map(params.map(arg => arg.split(/[:=](.*)/))); + for (let [query, val] of opts) { + if (query.match(/^\d+$/)) { + this.preset.cat = [parseInt(query)]; + } + else if (query === 'level') { + this.preset.level = parseInt(val); + } + else { + this.preset[query] = val; + } } + } + load(dataurl) { + this.configure(window.location.hash.split('#')); fetch(dataurl).then(res => res.json()).then(json => { this.words = this.dataselect(json) this.setup(); @@ -78,10 +96,14 @@ class WordQuiz { } constructor(dataurl) { + this.preset = {images: true}; this.load(dataurl); this.history = []; window.onbeforeunload = e => { this.stop('abort'); }; + window.onhashchange = e => { + this.load(dataurl); + }; } }