thoughts about time, refactor statements component
[qomet.git] / public / javascripts / components / statements.js
1 /*
2 * questions group by index prefix 1.2.3 1.1 ...etc --> '1'
3
4 NOTE: questions can contain parameterized exercises (how ?
5 --> describe variables (syntax ?)
6 --> write javascript script (OK, users trusted ? ==> safe mode possible if public website)
7 Imaginary example: (using math.js)
8 <params> (avant l'exo)
9 x: math.random()
10 y: math.random()
11 M: math.matrix([[7, x], [y, -3]]);
12 res: math.det(M)
13 </params>
14 <div>Calculer le déterminant de
15 $$\begin{matrix}7 & x\\y & -3\end{matrix}$$</div>
16 * ...
17 */
18
19 Vue.component("statements", {
20 // 'inputs': array of index (as in questions) + input (text or array of ints)
21 // display: 'all', 'one', 'solution'
22 // iidx: current level-0 integer index (can match a group of questions / inputs)
23 props: ['questions','inputs','display','iidx'],
24 data: function() {
25 return {
26 displayStyle: "compact", //or "all": all on same page
27 };
28 }
29 // Full questions tree is rendered, but some parts hidden depending on display settings
30 render(h) {
31 let domTree = (this.questions || [ ]).map( (q,i) => {
32 let questionContent = [ ];
33 questionContent.push(
34 h(
35 "h4",
36 {
37 "class": {
38 "questionIndex": true,
39 }
40 },
41 q.index
42 )
43 );
44 questionContent.push(
45 h(
46 "div",
47 {
48 "class": {
49 wording: true,
50
51 },
52 domProps: {
53 innerHTML: q.wording,
54 },
55 }
56 )
57 );
58 if (!!q.options)
59 {
60 // quiz-like question
61 let optionsOrder = _.range(q.options.length);
62 if (!q.fixed)
63 optionsOrder = _.shuffle(optionsOrder);
64 let optionList = [ ];
65 optionsOrder.forEach( idx => {
66 let option = [ ];
67 option.push(
68 h(
69 "input",
70 {
71 domProps: {
72 checked: this.answers.inputs.length > 0 && this.answers.inputs[i][idx],
73 disabled: monitoring,
74 },
75 attrs: {
76 id: this.inputId(i,idx),
77 type: "checkbox",
78 },
79 on: {
80 change: e => { this.answers.inputs[i][idx] = e.target.checked; },
81 },
82 },
83 [ '' ] //to work in Firefox 45.9 ESR @ ENSTA...
84 )
85 );
86 option.push(
87 h(
88 "label",
89 {
90 domProps: {
91 innerHTML: q.options[idx],
92 },
93 attrs: {
94 "for": this.inputId(i,idx),
95 },
96 }
97 )
98 );
99 optionList.push(
100 h(
101 "div",
102 {
103 "class": {
104 option: true,
105 choiceCorrect: this.answers.showSolution && this.questions[i].answer.includes(idx),
106 choiceWrong: this.answers.showSolution && this.answers.inputs[i][idx] && !q.answer.includes(idx),
107 },
108 },
109 option
110 )
111 );
112 });
113 questionContent.push(
114 h(
115 "div",
116 {
117 "class": {
118 optionList: true,
119 },
120 },
121 optionList
122 )
123 );
124 }
125 if (this.display == "all" && !this.navigator && i < this.questions.length-1)
126 questionContent.push( h("hr") );
127 const depth = (q.index.match(/\./g) || []).length;
128 return h(
129 "div",
130 {
131 "class": {
132 "question": true,
133 "hide": this.display == "one" && this.iidx != i,
134 "depth" + depth: true,
135 },
136 },
137 questionContent
138 );
139 });
140 const navigator = h(
141 "div",
142 {
143 "class": {
144 "hide": this.displayStyle == "all"
145 },
146 },
147 [
148 h(
149 "button",
150 {
151 "class": {
152 "btn": true,
153 },
154 on: {
155 click: () => {
156 this.index = Math.max(0, this.index - 1);
157 },
158 },
159 },
160 [ h("span", { "class": { "material-icon": true } }, "fast_rewind") ]
161 ), //onclick: index = max(0,index-1)
162 h("span",{ },(this.iidx+1).toString()),
163 h(
164 "button",
165 {
166 "class": {
167 "btn": true,
168 },
169 on: {
170 click: () => {
171 this.index = Math.min(this.index+1, this.questions.length-1)
172 },
173 },
174 },
175 [ h("span", { "class": { "material-icon": true } }, "fast_forward") ]
176 )
177 ]
178 );
179 domTree.push(navigator);
180 domTree.push(
181 h(
182 "button",
183 {
184 on: {
185 click: () => {
186 this.displayStyle = displayStyle == "compact" ? "all" : "compact";
187 },
188 },
189 },
190 this.displayStyle == "compact" ? "Show all" : "Navigator"
191 )
192 );
193 return h(
194 "div",
195 {
196 attrs: {
197 id: "statements",
198 },
199 },
200 domTree
201 );
202 },
203 mounted: function() {
204 statementsLibsRefresh();
205 },
206 updated: function() {
207 statementsLibsRefresh();
208 },
209 methods: {
210 inputId: function(i,j) {
211 return "q" + i + "_" + "input" + j;
212 },
213 },
214 });