File: webquiz-javascript-min

package info (click to toggle)
texlive-extra 2025.20250927-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,544,552 kB
  • sloc: perl: 401,877; xml: 41,384; python: 38,587; cs: 25,850; sh: 18,855; makefile: 17,325; ansic: 13,023; java: 12,811; javascript: 9,898; lisp: 1,876; csh: 1,347; ruby: 618; awk: 183; tcl: 142; pascal: 138; cpp: 124; sed: 92; haskell: 5
file content (436 lines) | stat: -rw-r--r-- 22,013 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
---
 texmf-dist/doc/latex/webquiz/www/js/webquiz.js |  428 ++++++++++++++++++++++++-
 1 file changed, 427 insertions(+), 1 deletion(-)

--- texlive-extra-2019.20190506.orig/texmf-dist/doc/latex/webquiz/www/js/webquiz.js
+++ texlive-extra-2019.20190506/texmf-dist/doc/latex/webquiz/www/js/webquiz.js
@@ -1 +1,427 @@
-var currentB,currentQ,dTotal,quizindex_menu,qTotal,side_closed,side_menu,side_open,correct=[],buttonOrder=[],questionOrder=[],wrongAnswers=[],currentFeedback=null,QuizSpecifications=[],Discussion=[],onePage=!1,QuizTitles=[],blank={content:"",name:"blank"},cross={content:"✘",name:"cross"},star={content:"✭",name:"star"},tick={content:"✔",name:"tick"};function markAnswer(){"undefined"!=typeof Storage&&(sessionStorage.correct=JSON.stringify(correct),sessionStorage.wrongAnswers=JSON.stringify(wrongAnswers))}var quizindex_menu_not_created=!0;function create_quizindex_menu(){if(quizindex_menu_not_created){document.getElementById("quizzes-menu-icon").innerHTML=" &#9776;";var q,quiz_link,max=0,menu=document.createDocumentFragment();for(q=0;q<QuizTitles.length;q++)(quiz_link=document.createElement("li")).innerHTML='<a href="'+QuizTitles[q][1]+'">'+QuizTitles[q][0]+"</a>",menu.appendChild(quiz_link),max=Math.max(max,QuizTitles[q][0].length);quizindex_menu.style.width=Math.round(max)+"ex",quizindex_menu.appendChild(menu),quizindex_menu_not_created=!1}}function MenuEventListener(evnt){var menu_icon=document.getElementById("quzzes-menu-icon");quizindex_menu.contains(evnt.target)||("block"===quizindex_menu.style.display||menu_icon.contains(evnt.target))&&(evnt.stopPropagation(),toggle_quizindex_menu())}function toggle_quizindex_menu(){"block"===quizindex_menu.style.display?quizindex_menu.style.display="none":(quizindex_menu.style.display="block",window.addEventListener("click",MenuEventListener,!0))}function toggle_side_menu(){"block"===side_menu.style.display||""===side_menu.style.display?(side_menu.style.display="none",side_open.style.display="none",side_closed.style.display="block"):(side_menu.style.display="block",side_open.style.display="block",side_closed.style.display="none")}function showQuestion(newB,newQ){onePage||(newQ!=currentQ&&0!=currentQ&&(hideFeedback(),document.getElementById("question"+currentQ).style.display="none",currentB.classList.remove("button-selected")),document.getElementById("question"+newQ).style.display="table",document.getElementById("question-number").innerHTML=0<newQ?(document.getElementById("question-label").style.display="contents",String(newB)):(document.getElementById("question-label").style.display="none",Discussion[-newQ]),(currentB=document.getElementById("button"+newB)).classList.add("button-selected")),currentQ=newQ}function hideFeedback(){currentFeedback&&(currentFeedback.style.display="none")}function showFeedback(tag){hideFeedback(),(currentFeedback=document.getElementById(tag)).style.display="block"}function nextQuestion(increment){if(currentQ<0)gotoQuestion(1===increment?1:qTotal);else{for(var q,b=buttonOrder[currentQ];0===(b+=increment)?b=qTotal:qTotal<b&&(b=1),(q=questionOrder[b])!==currentQ&&correct[q];);b===currentB?alert("There are no more unanswered questions"):gotoQuestion(b)}}var buttons=["blank","cross","star","tick"];function updateQuestionMarker(bnum,qnum){if(0<qnum){var marker,button=document.getElementById("button"+bnum);marker=correct[qnum]?0===wrongAnswers[qnum]?star:tick:0<wrongAnswers[qnum]?cross:blank;for(var b=0;b<buttons.length;b++)button.classList.remove(buttons[b]);button.classList.add(marker.name),button.setAttribute("content",marker.content)}}function gotoQuestion(bnum){var qnum=0<bnum?questionOrder[bnum]:bnum;gotoQuestionHelper(qnum),history.pushState(qnum,null,null)}function gotoQuestionHelper(qnum){var bnum=0<qnum?buttonOrder[qnum]:qnum;updateQuestionMarker(bnum,qnum),showQuestion(bnum,qnum)}var compare={complex:function(ans,val){var a=math.complex(ans),b=math.complex(val);return a.re==b.re&&a.im==b.im},integer:function(ans,val){return parseInt(val)==parseInt(ans)},lowercase:function(ans,val){return val==String(ans).toLowerCase()},number:function(ans,val){return math.eval(val)==math.eval(ans)},string:function(ans,val){return val==String(ans)}};function checkAnswer(qnum){var i,question=QuizSpecifications[qnum],studentAnswer=document.forms["Q"+qnum+"Form"];if("input"==question.type){var answer=studentAnswer.elements[0].value;if(""==answer)return void alert("Please answer the question first!");try{correct[qnum]=compare[question.comparison](answer,question.value)}catch(err){correct[qnum]=False}correct[qnum]?showFeedback("q"+qnum+"true"):showFeedback("q"+qnum+"false")}else if("single"==question.type){var checkedAnswer=0;for(i=0;i<question.length;i++)if(studentAnswer.elements[i].checked){correct[qnum]=question[i],checkedAnswer=i+1;break}showFeedback("q"+qnum+"feedback"+checkedAnswer)}else{var badAnswers=[];for(i=0;i<question.length;i++)if(studentAnswer.elements[i].checked!==question[i]){badAnswers.push(i+1);break}0===badAnswers.length?(correct[qnum]=!0,showFeedback("q"+qnum+"feedback0")):(correct[qnum]=!1,showFeedback("q"+qnum+"feedback"+badAnswers[Math.floor(Math.random()*badAnswers.length)]))}correct[qnum]||(wrongAnswers[qnum]+=1),updateQuestionMarker(buttonOrder[qnum],qnum),markAnswer()}function shuffleQuestions(){var i,j,qi;for(i=questionOrder.length-1;0<i;i--)j=1+Math.floor(Math.random()*i),qi=questionOrder[i],questionOrder[i]=questionOrder[j],questionOrder[j]=qi;for(i=buttonOrder.length-1;0<i;i--)buttonOrder[questionOrder[i]]=i}function initSession(){for("undefined"!=typeof Storage&&(sessionStorage.correct&&(correct=JSON.parse(sessionStorage.correct)),sessionStorage.wrongAnswers&&(wrongAnswers=JSON.parse(sessionStorage.wrongAnswers))),i=0;i<qTotal+1;i++)updateQuestionMarker(buttonOrder[i],i);qnum=0<dTotal?-1:questionOrder[1],history.replaceState(qnum,null,null)}function WebQuizInit(questions,discussions,quizfile){window.addEventListener("popstate",function(e){gotoQuestionHelper(e.state)}),dTotal=discussions,0==(qTotal=questions)&&(document.getElementsByClassName("arrows")[0].style.display="none");var i;currentQ=currentB=0;for(i=0;i<qTotal+1;i++)wrongAnswers[i]=0,correct[i]=!1,questionOrder[i]=i,buttonOrder[i]=i;var script=document.createElement("script");script.src=quizfile+"/wq-"+quizfile+".js",script.type="text/javascript",document.head.appendChild(script),side_menu=document.getElementById("sidemenu"),side_open=document.getElementById("sidelabelopen"),side_closed=document.getElementById("sidelabelclosed"),quizindex_menu=document.getElementById("quizindex-menu"),0<QuizTitles.length&&quizindex_menu&&create_quizindex_menu()}
\ No newline at end of file
+/* -----------------------------------------------------------------------
+ *   webquiz.js | javascript for controlling webquiz web pages
+ * -----------------------------------------------------------------------
+ *
+ *   Copyright (C) Andrew Mathas and Donald Taylor, University of Sydney
+ *
+ *   Distributed under the terms of the GNU General Public License (GPL)
+ *               http://www.gnu.org/licenses/
+ *
+ *   This file is part of the WebQuiz system.
+ *
+ *   <Andrew.Mathas@sydney.edu.au>
+ *   <Donald.Taylor@sydney.edu.au>
+ * ----------------------------------------------------------------------
+ */
+
+// Global variables
+var correct = [];           // questions answered correctly
+var buttonOrder = [];       // map from button number to question number
+var questionOrder = [];     // map from question number to button number
+var wrongAnswers = [];      // questions answered incorrectly
+
+
+var currentB;               // current button number
+var currentFeedback = null; // feedback currently being displayed
+var currentQ;               // current question number
+var dTotal;                 // number of discussion items
+var quizindex_menu;         // handler for the drop-down menu, if it exists
+var qTotal;                 // number of quiz questions
+var side_closed;            // handler for displaying sidelabelclosed
+var side_menu;              // handler to open and close side
+var side_open;              // handler for displaying sidelabelopen
+//var theme_menu              // handler for the theme_menu
+
+// The following variables are redefined in the specifications file
+var QuizSpecifications = [];
+var Discussion = [];        // Headings of discussion environments
+var onePage = false;
+
+// Defined and read from in quizindex.js if it exists
+var QuizTitles = [];        // Quiz titles from a quizindex environment
+
+// Specification for the question buttons for use in updateQuestionMarker
+var blank = {
+    "content": "",
+    "name": "blank"
+};
+var cross = {
+    "content": "\u2718",
+    "name": "cross"
+};
+var star = {
+    "content": "\u272D",
+    "name": "star"
+};
+var tick = {
+    "content": "\u2714",
+    "name": "tick"
+};
+
+function markAnswer() {
+  if (typeof(Storage) !== "undefined") {
+    sessionStorage.correct = JSON.stringify(correct);
+    sessionStorage.wrongAnswers = JSON.stringify(wrongAnswers);
+  }
+}
+
+// stop the dropdown menu from being created twice
+var quizindex_menu_not_created = true;
+
+// create the drop down menu dynamically using the QuizTitles array
+function create_quizindex_menu() {
+    if (quizindex_menu_not_created) {
+      // add the menu icon for the quizzes menu - only called if there is at least one quiz
+      document.getElementById("quizzes-menu-icon").innerHTML = " &#9776;";
+
+      var max = 0, q, quiz_link, menu = document.createDocumentFragment();
+      for (q = 0; q < QuizTitles.length; q++) {
+          quiz_link = document.createElement("li");
+          quiz_link.innerHTML = '<a href="' + QuizTitles[q][1] + '">' + QuizTitles[q][0] + '</a>';
+          menu.appendChild(quiz_link);
+          max = Math.max(max, QuizTitles[q][0].length);
+      }
+      quizindex_menu.style.width = Math.round(max) + "ex";
+      quizindex_menu.appendChild(menu);
+      quizindex_menu_not_created = false;
+    }
+}
+
+// create an event listener so that we can close the drop-down menu
+// whenever some one clicks outside of it
+function MenuEventListener(evnt) {
+    var menu_icon = document.getElementById('quzzes-menu-icon');
+    if (quizindex_menu.contains(evnt.target)) {
+      return; // inside the menu so just return
+    } else {   // outside the menu so check the number of menu_clicks
+      if (quizindex_menu.style.display === 'block' || menu_icon.contains(evnt.target)) {
+        evnt.stopPropagation();
+        toggle_quizindex_menu();
+      }
+      //if (theme_menu.style.display === 'block' || menu_icon.contains(evnt.target)) {
+      //  evnt.stopPropagation();
+      //  toggle_quizindex_menu();
+      //}
+    }
+}
+
+function toggle_quizindex_menu() {
+    if (quizindex_menu.style.display === 'block') {
+      quizindex_menu.style.display = 'none';
+    } else {
+      quizindex_menu.style.display = 'block';
+      window.addEventListener('click', MenuEventListener, true);
+    }
+}
+
+// function toggle_theme_menu() {// unused
+//     if (theme_menu.style.display === 'block') {
+//       theme_menu.style.display = 'none';
+//     } else {
+//       theme_menu.style.display = 'block';
+//       window.addEventListener('click', MenuEventListener, true);
+//     }
+// }
+
+// toggle the display of the side menu and its many associated labels
+function toggle_side_menu() {
+    if (side_menu.style.display === "block" || side_menu.style.display === "") {
+        side_menu.style.display = "none";
+        side_open.style.display = "none";
+        side_closed.style.display = "block";
+    } else {
+        side_menu.style.display = "block";
+        side_open.style.display = "block";
+        side_closed.style.display = "none";
+    }
+}
+
+// Code to hide/show questions
+function showQuestion(newB, newQ) { // newQ is an integer which is always in the correct range
+    // alert('showing newB='+newB+', newQ='+newQ+', currentQ='+currentQ+'.');
+    if (!onePage) {
+      // hide the current question and feedback
+      if (newQ!=currentQ && currentQ!=0) {
+            hideFeedback();
+            document.getElementById("question" + currentQ).style.display = "none";
+            // "de-select" the current button
+            currentB.classList.remove("button-selected");
+      }
+      // display the new question
+      document.getElementById("question" + newQ).style.display = "table";
+
+      // update the question/discussion header and select question button
+      if (newQ > 0) {
+          document.getElementById("question-label").style.display = 'contents';
+          document.getElementById("question-number").innerHTML = String(newB);
+      } else {
+          document.getElementById("question-label").style.display = 'none';
+          document.getElementById("question-number").innerHTML = Discussion[-newQ];
+      }
+      // set currentB = the current button and "select" the current button
+      currentB = document.getElementById("button" + newB);
+      currentB.classList.add("button-selected");
+    }
+
+    // finally set currentQ = current question
+    currentQ = newQ;
+}
+
+// Code to hide/show feedback
+
+function hideFeedback() {
+    if (currentFeedback) {
+        currentFeedback.style.display = "none";
+    }
+}
+
+function showFeedback(tag) {
+    // alert('Showing feedback for '+tag+'.');
+    hideFeedback(); // hide current feedback
+    currentFeedback = document.getElementById(tag);
+    currentFeedback.style.display = "block";
+}
+
+// if increment==1 we find the next questions which has not
+// been answered incorrectly and if increment==-1 we find the last
+// such question
+function nextQuestion(increment) {
+    if (currentQ < 0) { // a discussion item => go to either first or last question
+        if (increment === 1) {
+            gotoQuestion(1);
+        } else {
+            gotoQuestion(qTotal);
+        }
+    } else {
+        var b = buttonOrder[currentQ], q;
+        do {
+            b += increment;
+            if (b === 0) {
+                b = qTotal;
+            } else if (b > qTotal) {
+                b = 1;
+            }
+            q = questionOrder[b];
+        } while (q !== currentQ && correct[q]);
+        if (b === currentB) {
+            alert("There are no more unanswered questions");
+        } else {
+            gotoQuestion(b);
+        }
+    }
+}
+
+
+var buttons = ['blank', 'cross', 'star', 'tick'];
+function updateQuestionMarker(bnum, qnum) {
+    // alert('updating bnum='+bnum+', qnum='+qnum+', currentQ='+currentQ+'.');
+    // here qnum is assumed to be the question number in the web form
+    if (qnum > 0) {
+        var marker;
+        var button = document.getElementById('button'+bnum);
+        if (correct[qnum]) {
+            if (wrongAnswers[qnum] === 0) {
+                marker = star;
+            } else {
+                marker = tick;
+            }
+        } else {
+            if (wrongAnswers[qnum] > 0) {
+                marker = cross;
+            } else {
+                marker = blank;
+            }
+        }
+        for (var b = 0; b < buttons.length; b++) {
+           button.classList.remove(buttons[b]);
+        }
+        button.classList.add(marker.name);
+        button.setAttribute("content", marker.content);
+    }
+}
+
+// jumps to a chosen question and pushes the number of this question to the browser history
+function gotoQuestion(bnum) {
+    // bnum is a button number so we need to convert to a question number
+
+    var qnum = (bnum>0) ? questionOrder[bnum] : bnum;
+    gotoQuestionHelper(qnum);
+    history.pushState(qnum, null, null);
+}
+
+// jumps to the specified question (without pushing it to the browser history)
+function gotoQuestionHelper(qnum) {
+    var bnum = (qnum>0) ? buttonOrder[qnum] : qnum;
+    updateQuestionMarker(bnum, qnum);
+    showQuestion(bnum, qnum);
+}
+
+// dictionary of comparison methods for when question.type=='input'
+// each function in the dictionary returns true or false
+var compare = {
+  'complex': function(ans, val) {// check real and imaginary parts
+               var a = math.complex(ans);
+               var b = math.complex(val);
+               return a.re==b.re && a.im==b.im;
+             },
+  'integer': function(ans, val) {// compare as integers
+               return parseInt(val)==parseInt(ans);
+             },
+  'lowercase':  function(ans, val) {//convert to lowercase string and compare
+               return val==String(ans).toLowerCase();
+             },
+  'number':  function(ans, val) {// compare as numbers
+               return math.eval(val)==math.eval(ans);
+             },
+  'string':  function(ans, val) {// compare as strings
+               return val==String(ans);
+             }
+};
+
+// check to see whether the answer is correct and update the markers accordingly
+function checkAnswer(qnum) {
+    // alert('checking qnum='+qnum+'.');
+    var question = QuizSpecifications[qnum];
+    var studentAnswer = document.forms["Q" + qnum + "Form"];
+    var i;
+    if (question.type == "input") {
+        var answer = studentAnswer.elements[0].value;
+        if (answer=='') { //must have hit checkAnswer without answering, so ignore
+          alert('Please answer the question first!');
+          return;
+        }
+        try {
+          correct[qnum] = compare[question.comparison](answer, question.value);
+        } catch(err) {
+          correct[qnum] = False;
+        }
+
+        if (correct[qnum]) {
+            showFeedback("q" + qnum + "true");
+        } else {
+            showFeedback("q" + qnum + "false");
+        }
+    } else if (question.type == "single") {
+        var checkedAnswer = 0;
+        for (i = 0; i < question.length; i++) {
+            if (studentAnswer.elements[i].checked) {
+                correct[qnum] = question[i];
+                checkedAnswer = i + 1;
+                break;
+            }
+        }
+        showFeedback("q" + qnum + "feedback" + checkedAnswer);
+    } else { // type is "multiple"
+        var badAnswers = [];
+        for (i = 0; i < question.length; i++) {
+            if (studentAnswer.elements[i].checked !== question[i]) {
+                badAnswers.push(i + 1);
+                break;
+            }
+        }
+        // fully correct only if badAnswers == []
+        if (badAnswers.length === 0) {
+            correct[qnum] = true;
+            showFeedback("q" + qnum + "feedback0");
+        } else {
+            // randomly display a feedback for one of incorrect choices
+            correct[qnum] = false;
+            showFeedback("q" + qnum + "feedback" + badAnswers[Math.floor(Math.random() * badAnswers.length)]);
+        }
+    }
+    //
+    if (!correct[qnum]) {
+        wrongAnswers[qnum] += 1;
+    }
+    updateQuestionMarker(buttonOrder[qnum], qnum);
+    markAnswer();
+}
+
+/**
+ * Shuffle the questionOrder array and make buttonOrder its inverse
+ * Based on https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array
+ */
+function shuffleQuestions() {
+    var i, j, qi;
+    for (i = questionOrder.length-1; i > 0; i--) {
+        j = 1+Math.floor(Math.random() * i);
+        qi = questionOrder[i];
+        questionOrder[i]=questionOrder[j];
+        questionOrder[j]=qi;
+    }
+    // ...and compute the inverse map
+    for (i = buttonOrder.length - 1; i > 0; i--) {
+        buttonOrder[questionOrder[i]] = i;
+    }
+}
+
+// Restores the state of the question markers from the session storage
+function initSession() {
+    if (typeof(Storage) !== "undefined") {
+      if (sessionStorage.correct)
+        correct = JSON.parse(sessionStorage.correct);
+      if (sessionStorage.wrongAnswers)
+        wrongAnswers = JSON.parse(sessionStorage.wrongAnswers);
+    }
+
+    for (i = 0; i < qTotal+1; i++) {
+      updateQuestionMarker(buttonOrder[i],i);
+    }
+
+    // make the browser history remember the first question
+    qnum = (dTotal > 0) ? -1 : questionOrder[1];
+    history.replaceState(qnum, null, null);
+}
+
+// initialise the quiz, loading specifications and setting up the first question
+function WebQuizInit(questions, discussions, quizfile) {
+    // process init options
+
+    // callback for browser history events
+    window.addEventListener('popstate', function(e) {
+       gotoQuestionHelper(e.state);
+    });
+
+    qTotal = questions;
+    dTotal = discussions;
+
+    // remove question arrows when there are no questions
+    if (qTotal==0) {
+        document.getElementsByClassName('arrows')[0].style.display='none'
+    }
+
+    // display the first question or discussion item
+    currentB = 0;
+    currentQ = 0;
+    var newQ = (dTotal > 0) ? -1 : 1;
+
+    // set up arrays for tracking how many times the questions have been attempted
+    var i;
+    for (i = 0; i < qTotal+1; i++) {
+        wrongAnswers[i] = 0;    // the number of times the question has been attempted
+        correct[i] = false;     // whether or not the supplied answer is correct
+        questionOrder[i] = i; // will determine the order of the questions
+        buttonOrder[i] = i;    // will determine the order of the buttons
+    }
+
+    // read the question specifications for the quiz
+    // and then wait for the QuizSpecifications to load
+    var script = document.createElement('script');
+    script.src =  quizfile + "/wq-" + quizfile + ".js";
+    script.type = "text/javascript";
+    document.head.appendChild(script);
+
+    // compute these only once
+    side_menu = document.getElementById('sidemenu');
+    side_open = document.getElementById('sidelabelopen');
+    side_closed = document.getElementById('sidelabelclosed');
+    quizindex_menu = document.getElementById("quizindex-menu");
+    //theme_menu = document.getElementById('theme-menu');
+
+    // make the drop down menu if QuizTitles has some entries
+    if (QuizTitles.length > 0 && quizindex_menu) {
+        create_quizindex_menu();
+    }
+}
+
+