word/quiz: report table to save user actions
authorMischa POSLAWSKY <perl@shiar.org>
Tue, 11 Jan 2022 05:53:54 +0000 (06:53 +0100)
committerMischa POSLAWSKY <perl@shiar.org>
Mon, 7 Feb 2022 17:42:33 +0000 (18:42 +0100)
Setup basic logging system to gather usage events serverside for debugging
and hopefully difficulty analysis later on.  Initially always enabled while
in private testing.

word/memory.js
word/multichoice.js
word/quiz.js
word/report.plp [new file with mode: 0644]
word/wijzer.js

index a6b19061fee1e42dbbc6f9df3e7ffc94c80e1f8d..89fd853c3cb89210c2a1d3e02e1b9fdaaaec2b55 100644 (file)
@@ -5,6 +5,7 @@ class WordMemory extends WordQuiz {
                        // show an open card
                        this.turned.push(target);
                        put(target, '.turn');
+                       this.log('pick', target.id, target.index);
                }
                else if (this.turned.length < 2) {
                        return; // keep open
@@ -30,6 +31,7 @@ class WordMemory extends WordQuiz {
                        this.turned = [];
                        if (Array.from(this.form.children).every(card => card.classList.contains('good'))) {
                                put(this.form, '.good');
+                               this.stop('done');
                        }
                        return;
                }
@@ -70,11 +72,15 @@ class WordMemory extends WordQuiz {
                                .map(e => e.toString())
                }
 
-               cards.shuffle().forEach(word => {
+               cards.shuffle().forEach((word, seq) => {
                        let ref = Math.abs(word);
                        put(this.form,
-                               'figure>img[src=$]<', `/data/word/32/${ref}.jpg`,
-                               {onclick: e => this.turn(e), id: ref, className: word < 0 ? 'mirror' : ''}
+                               'figure>img[src=$]<', `/data/word/32/${ref}.jpg`, {
+                                       onclick: e => this.turn(e),
+                                       id: ref,
+                                       className: word < 0 ? 'mirror' : '',
+                                       index: seq,
+                               }
                        );
                });
        }
index ca6843af1e992be47e3e8777b006f8fda121c177..f0520f9d428cccbcc376a89eecb7e2f2c960d884 100644 (file)
@@ -9,9 +9,11 @@ class WordMultiChoice extends WordQuiz {
 
                let answers = [word[0], this.words[0][0], this.words[1][0], this.words[2][0]]
                        .shuffle()
+               this.log('ask', word[2], answers);
                answers.forEach(suggest => {
                        let label = suggest.replace(/\/.*/, '');
                        let option = put(form, 'li', label, {onclick: () => {
+                               this.log('pick', suggest, null, word[0]);
                                if (suggest != word[0]) {
                                        // incorrect
                                        put(option, '.wrong');
index 2385455ea0ff6e3d3a641b08ba0e8a87e1bf6401..bb12a832c73b170e496dc09e25e6fb88aa0c8849 100644 (file)
@@ -58,7 +58,21 @@ class WordQuiz {
                });
        }
 
+       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');
+               };
        }
 }
diff --git a/word/report.plp b/word/report.plp
new file mode 100644 (file)
index 0000000..56d6188
--- /dev/null
@@ -0,0 +1,12 @@
+<:
+my $db = eval {
+       require Shiar_Sheet::DB;
+       Shiar_Sheet::DB->connect;
+} or Abort('Database error', 501, $@);
+
+$db->insert(report => {
+       agent   => $ENV{HTTP_USER_AGENT},
+       page    => $ENV{HTTP_REFERER},
+       address => $ENV{REMOTE_ADDR},
+       history => $PLP::read->($ENV{CONTENT_LENGTH}),
+});
index 5f2a3bba9ad40ec5a4253ce6310dd8ec269caefb..7446cc990e1231c7881041892c79da5e4d6e0457 100644 (file)
@@ -6,6 +6,7 @@ class WordWijzer extends WordQuiz {
                        this.form.querySelectorAll('li[onclick]').forEach(answer => {
                                answer.removeAttribute('onclick');
                        });
+                       this.log('done');
                        return;
                }
 
@@ -22,6 +23,7 @@ class WordWijzer extends WordQuiz {
                console.log(this.question, answer);
                let match = this.question.dataset.id == answer.dataset.id;
                put(answer, match ? '.good' : '.wrong');
+               this.log('pick', answer.dataset.id, answer.index, this.question.dataset.id);
                this.next();
        }
 
@@ -32,10 +34,13 @@ class WordWijzer extends WordQuiz {
 
                let answers = put(this.form, 'ul');
                this.words
-                       .forEach(answer => {
+                       .forEach((answer, seq) => {
                                let label = answer[0].replace(/\/.*/, ''); // primary form
                                put(answers, 'li[data-id=$][onclick=""]',
-                                       answer[2], label, {onclick: e => this.verify(e)}
+                                       answer[2], label, {
+                                               onclick: e => this.verify(e),
+                                               index: seq,
+                                       }
                                )
                        });
                this.words.shuffle();