m-examn.mkiv /size: 16 Kb    last modification: 2020-07-01 14:35
1%D \module
2%D   [       file=m-examn,
3%D        version=2000.01.29,
4%D          title=\CONTEXT\ Extra Modules,
5%D       subtitle=Testing and Examination,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14%D This is a pretty old style, written in 2000 so after 20 years it's time to check
15%D if it works with \MKIV. The original version looks mostly the same as below and
16%D runs ok with \MKII. The differences are in not using percent sign triggered
17%D comments in the \JAVASCRIPT\ section (that was dropped), using \type {Yes}
18%D instead of \type {On} as field value (because in those decades the \type {On}
19%D value has proven to be fragile (maybe because of some hard coded \type {Yes}
20%D checking). The macros lost \type {\long}, became \type {\unexpanded} and were
21%D reformatted.
22%D
23%D If there is really demand for this I'll do a more major update. I see no reason
24%D to change the 2000 \MKII\ logic now.
25
26% n         number of permitted answers
27% answer  (set of) right answer(s) (one or list)
28% weight    weight of the answer(s) (one or list)
29% method    calculation method, for the moment 1
30
31% hidden = true -> display = display.hidden
32
33% disguise methods, numbers and meaning secret
34% randomizing answers
35% allert will be a properly typeset message
36% all checkfields instead of radio, gives more control
37
38\unprotect
39
40\def\c!answer  {answer}
41\def\c!question{question}
42\def\c!weight  {weight}
43
44\startJSpreamble {mpc} used now
45
46    var RealTimeMode    = false ;
47    var FeedBackMode    = false ;
48    var CurrentFeedback = -1 ;
49
50    var MPCnames   = new Array() ;
51    var MPCanswers = new Array() ;
52    var MPCnumbers = new Array() ;
53    var MPCweights = new Array() ;
54    var MPCmethods = new Array() ;
55    var MPCerrors  = new Array() ;
56
57    function Warning (str) {
58        app.alert("warning: " + str)
59    }
60
61    function FieldYN (name,n) {
62        return this.getField(name + ":" + n + ":yn")
63    }
64
65    function FieldRW (name,n) {
66        return this.getField(name + ":" + n + ":rw")
67    }
68
69    function NOfFields (name) {
70        var nof = 1 ;
71        while (FieldYN(name,nof)) {
72            ++nof
73        }
74        return --nof
75    }
76
77    function SetScore (score,total) {
78        mpcs = this.getField("mpc-score") ;
79        mpct = this.getField("mpc-total") ;
80        mpcp = this.getField("mpc-percent") ;
81        if (RealTimeMode) {
82            var percent = 0 ;
83            if (Number(total) > 0) {
84                percent = Math.round(100.0 * (Number(score) / Number(total)))
85            }
86            if (mpcs) {
87                mpcs.value = score
88            }
89            if (mpct) {
90                mpct.value = total
91            }
92            if (mpcp) {
93                mpcp.value = percent
94            }
95        } else {
96            if (mpcs) {
97                mpcs.value = ""
98            }
99            if (mpct) {
100                mpct.value = ""
101            }
102            if (mpcp) {
103                mpcp.value = ""
104            }
105        }
106        this.dirty = false
107    }
108
109    function CheckMPCmode () {
110        mpcr = this.getField("mpc-realtime") ;
111        if (mpcr) {
112            RealTimeMode = (mpcr.value == "Yes")
113        }
114        CheckScore() ;
115        this.dirty = false
116    }
117
118    function DefineMPC (name, answer, number, weight, method) {
119        SetScore(0,0) ;
120        MPCnames[MPCnames.length] = name ;
121        if (answer=="") {
122            MPCanswers[name] = "0"
123        } else {
124            MPCanswers[name] = answer
125        }
126        if (number=="") {
127            MPCnumbers[name] = "0"
128        } else {
129            MPCnumbers[name] = number
130        }
131        if (weight=="") {
132            MPCweights[name] = "0"
133        } else {
134            MPCweights[name] = weight
135        }
136        if (method=="") {
137            MPCmethods[name] = "0"
138        } else {
139            MPCmethods[name] = method
140        }
141    }
142
143    function CheckScore () {
144        var score = 0 ;
145        var total = 0 ;
146        var ok = false ;
147        for (var i=0;i<MPCnames.length;i++) {
148            var name = MPCnames[i] ;
149            var answer = MPCanswers[name] ;
150            var number = Number(MPCnumbers[name]) ;
151            var weight = MPCweights[name] ;
152            var method = MPCmethods[name] ;
153            var fields = Number(NOfFields(name)) ;
154            var answers = answer.split(",") ;
155            var weights = weight.split(",") ;
156            var sorted = weight.split(",") ;
157            sorted = sorted.sort() ;
158            sorted = sorted.reverse() ;
159            for (var k = 0; k < number; k++) {
160                if (weights.length < answers.length) {
161                    total += Number(weight)
162                } else {
163                    total += Number(sorted[k])
164                }
165            }
166            for (var j = 1; j <= fields; j++) {
167                if (FeedBackMode) {
168                    ok = (! FieldRW(name,j).hidden && (FieldRW(name,j).value == "Yes"))
169                } else {
170                    ok = (FieldYN(name,j).value == "Yes")
171                }
172                if (ok) {
173                    for (var k = 0; k < answers.length; k++) {
174                        if (Number(answers[k]) == j) {
175                            if (weights.length < answers.length) {
176                                score += Number(weight)
177                            } else {
178                                score += Number(weights[k])
179                            }
180                        }
181                    }
182                }
183            }
184        }
185        CurrentFeedback = -1 ;
186        SetScore(score,total)
187    }
188
189    function CalculateItems () {
190        CheckScore() ;
191        for (var i = 0;i < MPCnames.length; i++) {
192            var name = MPCnames[i] ;
193            var answer = MPCanswers[name] ;
194            var fields = Number(NOfFields(name)) ;
195            var answers = answer.split(",") ;
196            for (var j = 1; j <= fields; j++) {
197                FieldRW(name,j).hidden = true ;
198                FieldRW(name,j).readonly = true ;
199                FieldRW(name,j).value = "Off" ;
200                FieldYN(name,j).readonly = true ;
201                if (FieldYN(name,j).value=="Off") {
202                    for (var k = 0; k < answers.length; k++) {
203                        if (Number(answers[k]) == j) {
204                            FieldYN(name,j).value = "Yes"
205                        }
206                    }
207                } else {
208                    FieldRW(name,j).hidden = false ;
209                    for (var k = 0; k < answers.length; k++) {
210                        if (Number(answers[k]) == j) {
211                            FieldRW(name,j).value = "Yes"
212                        }
213                    }
214                }
215            }
216            var SomeW = false ;
217            var SomeRW = false ;
218            for (var j = 1; j <= fields; j++) {
219                if (! FieldRW(name,j).hidden) {
220                    SomeRW = true ;
221                    if (FieldRW(name,j).value == "Off") {
222                        SomeW = true
223                    }
224                }
225            }
226            MPCerrors[name] = (SomeW || (! SomeRW)) ;
227        }
228        CurrentFeedback = -1 ;
229        FeedBackMode = true ;
230        this.dirty = false
231    }
232
233    function ResetItems () {
234        for (var i = 0; i < MPCnames.length; i++) {
235            var name = MPCnames[i] ;
236            var fields = Number(NOfFields(name)) ;
237            for (var j = 1; j <= fields; j++) {
238                FieldRW(name,j).hidden = true ;
239                FieldYN(name,j).hidden = false ;
240                FieldYN(name,j).readonly = false ;
241                FieldYN(name,j).value = "Off" ;
242                SetScore(0,0)
243            }
244        }
245        CurrentFeedback = -1 ;
246        FeedBackMode = false ;
247        this.dirty = false
248    }
249
250    function CheckMPCone (name, number) {
251        nofitems = Number(NOfFields(name)) ;
252        for (var i = 1; i <= nofitems; i++) {
253            if (i != Number(number)) {
254                FieldYN(name,i).value = "Off"
255            }
256        }
257    }
258
259    function CheckMPCmore (name, number) {
260        var nofitems = Number(NOfFields(name)) ;
261        var currentnumber = 0 ;
262        for (var i = 1; i <= nofitems; i++) {
263            if (FieldYN(name,i).value == "Yes") {
264                ++currentnumber
265            }
266        }
267        if (currentnumber>Number(MPCnumbers[name])) {
268            Warning("only " + MPCnumbers[name] + " choices permitted") ;
269            var v = FieldYN(name,number) ;
270            if (v.value == "Yes") {
271                v.value = "Off"
272            }
273        }
274    }
275
276    function CheckMPC (name, number) {
277        if (! FeedBackMode) {
278            if (MPCnumbers[name] == 1) {
279                CheckMPCone(name,number)
280            } else {
281                CheckMPCmore(name,number)
282            }
283            if (RealTimeMode) {
284                CheckScore()
285            } else {
286                SetScore(0,0)
287            }
288        } else {
289            SetScore(0,0)
290        }
291    }
292
293    function GoneToFeedback () {
294        var name = MPCnames[CurrentFeedback] ;
295        if (MPCerrors[name]) {
296            console.println("feedback:" + name) ;
297            this.gotoNamedDest("feedback:" + name) ;
298            return true
299        } else {
300            return false
301        }
302    }
303
304    function NextFeedback () {
305        ++CurrentFeedback ;
306        while (CurrentFeedback < MPCnames.length) {
307            if (GoneToFeedback()) {
308                return
309            } else {
310                ++CurrentFeedback
311            }
312        }
313        CurrentFeedback = 0 ;
314        while (CurrentFeedback < MPCnames.length) {
315            if (GoneToFeedback()) {
316                return
317            } else {
318                ++CurrentFeedback
319            }
320        }
321        CurrentFeedback = -1
322    }
323
324    function PreviousFeedback () {
325        --CurrentFeedback ;
326        while (CurrentFeedback >= 0) {
327            if (GoneToFeedback()) {
328                return
329            } else {
330                --CurrentFeedback
331            }
332        }
333        CurrentFeedback = MPCnames.length ;
334        while (CurrentFeedback >= 0)  {
335            if (GoneToFeedback()) {
336                return
337            } else {
338                --CurrentFeedback
339            }
340        }
341        CurrentFeedback = MPCnames.length + 1
342    }
343
344\stopJSpreamble
345
346\definecolor[clickMPCcolor][blue]
347\definecolor[rightMPCcolor][green]
348\definecolor[wrongMPCcolor][red]
349
350\definecolor[MPCcolor][clickMPCcolor]
351
352\appendtoks
353    \definesymbol [mpc-y] [\mathematics{\color[clickMPCcolor]{\star}}] % yes
354    \definesymbol [mpc-n] [\hphantom{\symbol[mpc-y]}]                  % no
355    \definesymbol [mpc-r] [\mathematics{\color[rightMPCcolor]{\star}}] % right
356    \definesymbol [mpc-w] [\mathematics{\color[wrongMPCcolor]{\star}}] % wrong
357\to \everystarttext
358
359\definereference [ResetItems]       [JS(ResetItems)]
360\definereference [CalculateItems]   [JS(CalculateItems)]
361\definereference [PreviousFeedback] [JS(PreviousFeedback)]
362\definereference [NextFeedback]     [JS(NextFeedback)]
363
364\setupfield
365  [mpc-field-yn]
366  [%\c!frame=\v!off,
367   \c!height=.8em,
368   \c!width=.8em,
369   \c!background=\v!color,
370   \c!backgroundcolor=gray]
371
372\setupfield
373  [mpc-field-rw]
374  [%\c!frame=\v!off,
375   \c!height=.8em,
376   \c!width=.8em,
377   \c!background=\v!color,
378   \c!background=gray]
379
380\setupfield
381  [mpc-data]
382  [%\c!frame=\v!off,
383   \c!height=3ex,
384   \c!location=\v!low,
385   \c!align=\v!middle,
386   \c!color=MPCcolor,
387   \c!background=\v!color,
388   \c!background=gray,
389   \c!option=\v!readonly]
390
391\setupfield
392  [mpc-mode]
393  [%\c!frame=\v!off,
394   \c!height=3ex,
395   \c!width=3ex,
396   \c!location=\v!low,
397   \c!color=MPCcolor,
398   \c!background=\v!color,
399   \c!background=gray,
400   \c!clickout=JS(CheckMPCmode)]
401
402\appendtoks
403    \definemainfield[mpc-score]   [line] [mpc-data][][]
404    \definemainfield[mpc-total]   [line] [mpc-data][][]
405    \definemainfield[mpc-percent] [line] [mpc-data][][]
406    \definemainfield[mpc-realtime][check][mpc-mode][mpc-y,mpc-n][mpc-n]
407\to \everystarttext
408
409\newif\iftraceitems % \traceitemstrue
410
411\unexpanded\def\startMPCitems
412  {\dotripleempty\dostartMPCitems}
413
414\let\stopMPCitems\relax
415\let\startMPCitem\relax
416\let\stopMPCitem \relax
417
418\unexpanded\def\dostartMPCitems[#1][#2][#3]#4\stopMPCitems
419  {\bgroup
420   \getgparameters
421     [mpc:#1:]
422     [\c!answer=1,
423      \c!n=1,
424      \c!weight=1,
425      \c!method=1,
426      #2]%
427   \doglobal\newcounter\MPCitems
428   \unexpanded\def\startMPCitem##1\stopMPCitem
429     {\doglobal\increment\MPCitems
430      \edef\MPCitem{MPC:\MPCitems}%
431      \expandafter\setvalue\expandafter\MPCitem\expandafter
432        {\expandafter\handleMPCitem\expandafter{\MPCitems}{##1}}}
433   #4\relax
434   \unexpanded\def\handleMPCitem##1##2%
435     {\setJSpreamble{mpc:#1}
436        {DefineMPC
437           ("mpc:#1",%
438            "\getvalue{mpc:#1:\c!answer}",%
439            "\getvalue{mpc:#1:\c!n}",%
440            "\getvalue{mpc:#1:\c!weight}",%
441            "\getvalue{mpc:#1:\c!method}");}%
442      \definefield[mpc:#1:##1:rw][check][mpc-field-rw][mpc-r,mpc-w][mpc-r]
443      \definefield[mpc:#1:##1:yn][check][mpc-field-yn][mpc-y,mpc-n][mpc-n]
444      \setupfield[mpc-field-rw][\c!option={\v!readonly,\v!hidden}]
445      \setupfield[mpc-field-yn][\c!clickout=JS(CheckMPC{mpc:#1,##1})]
446      \mar{\iftraceitems{\txx##1}\hskip.5em\fi
447          %\fitfield[mpc:#1:##1:rw]\hskip.25em
448          %\fitfield[mpc:#1:##1:yn]}
449           \field[mpc:#1:##1:rw]\hskip.25em
450           \field[mpc:#1:##1:yn]}
451      ##2\par}%
452  \global\let\MPCdone\MPCitems
453  \global\unexpanded\def\fetchMPCitems
454    {\getrandomnumber\MPCitem{1}{\MPCitems}%
455     \doifdefined{MPC:\MPCitem}
456       {\getvalue{MPC:\MPCitem}
457        \doglobal\decrement\MPCdone
458        \global\letbeundefined{MPC:\MPCitem}}%
459     \ifcase\MPCdone\else
460       \expandafter\fetchMPCitems
461     \fi}
462  \startitemize[#3]
463    \fetchMPCitems
464  \stopitemize
465  \egroup}
466
467% \setupsystem
468%   [\c!random=\v!small]
469
470\protect
471
472\continueifinputfile{m-examn.mkiv}
473
474% \nopdfcompression
475
476\setupbodyfont[pagella,10pt]
477
478% \usemodule[m][examn]
479
480\setupinteraction
481  [state=start,
482   color=MPCcolor,
483   menu=on]
484
485\setupinteractionmenu
486  [right]
487  [state=start]
488
489\setupinteractionscreen
490  [option=max]
491
492\setuppapersize
493  [S6][S6]
494
495\setuplayout
496  [topspace=15pt,
497   backspace=40pt,
498   header=0pt,
499   footer=0pt,
500   height=middle,
501   rightmargin=0pt,
502   leftmargin=20pt,
503   leftmargindistance=5pt,
504   rightedge=100pt,
505   rightedgedistance=15pt,
506   width=430pt]
507
508\setupbackgrounds
509  [text][rightedge]
510  [frame=on,
511   frameoffset=5pt,
512   framecolor=MPCcolor]
513
514\startinteractionmenu[right]
515    \startalignment[middle]
516        \dontleavehmode \gotobox{\strut example test} [examplepage]                      \blank
517        \dontleavehmode \gotobox{\strut next feedback}[NextFeedback]                     \blank
518        \dontleavehmode \gotobox{\strut prev feedback}[PreviousFeedback]                 \blank
519        \dontleavehmode \gotobox{\strut submit}       [SubmitForm{mailto:pragma@wxs.nl}] \blank
520        \dontleavehmode \gotobox{\strut reset}        [ResetItems]                       \blank
521        \dontleavehmode \gotobox{\strut calculate}    [CalculateItems]                   \blank
522        \vfill
523        score      \blank[small] \dontleavehmode \field[mpc-score]    \blank
524        max score  \blank[small] \dontleavehmode \field[mpc-total]    \blank
525        percentage \blank[small] \dontleavehmode \field[mpc-percent]  \blank
526        realtime   \blank[small] \dontleavehmode \field[mpc-realtime] \blank
527        \kern0pt
528    \stopalignment
529\stopinteractionmenu
530
531\starttext
532
533\title [examplepage] {A simple MPC demo (toggle mode)}
534
535\startMPCitems[mpc-1][answer=3][a,packed]
536
537    \startMPCitem this is alpha \stopMPCitem
538    \startMPCitem and this is beta \stopMPCitem
539    \startMPCitem but how about gamma (ok) \stopMPCitem
540
541\stopMPCitems
542
543\startMPCitems[mpc-5][answer={2,3,4},n=2][n,packed]
544
545    \startMPCitem this is alpha \stopMPCitem
546    \startMPCitem and this is beta (ok, 2 ok's permitted) \stopMPCitem
547    \startMPCitem but how about gamma (ok, 2 ok's permitted) \stopMPCitem
548    \startMPCitem or delta (ok, 2 ok's permitted) \stopMPCitem
549    \startMPCitem or epsilon \stopMPCitem
550
551\stopMPCitems
552
553\startMPCitems[mpc-6][answer={2,3,4},weight={2,1,3},n=2][g,packed]
554
555    \startMPCitem this is alpha \stopMPCitem
556    \startMPCitem and this is beta (ok, 2 ok's permitted, weight is 2) \stopMPCitem
557    \startMPCitem but how about gamma (ok, 2 ok's permitted, weight is 1) \stopMPCitem
558    \startMPCitem or delta (ok, 2 ok's permitted, weight is 3) \stopMPCitem
559    \startMPCitem or epsilon \stopMPCitem
560
561\stopMPCitems
562
563\startMPCitems[mpc-8][answer=1,weight=2][packed]
564
565    \startMPCitem this is alpha (ok, weight is 2) \stopMPCitem
566    \startMPCitem and this is beta \stopMPCitem
567    \startMPCitem but how about gamma \stopMPCitem
568    \startMPCitem or delta \stopMPCitem
569
570\stopMPCitems
571
572\title [feedback:mpc:mpc-1] {Feedback on MPC 1}  whatever
573\title [feedback:mpc:mpc-5] {Feedback on MPC 5}  whatever
574\title [feedback:mpc:mpc-6] {Feedback on MPC 6}  whatever
575\title [feedback:mpc:mpc-8] {Feedback on MPC 8}  whatever
576
577\stoptext
578