Commit | Line | Data |
---|---|---|
e99c53fb BA |
1 | // UNIMPLEMENTED |
2 | ||
3 | // TODO: onglets pour chaque groupe + section déroulante questionnaire (chargé avec réponses) | |
4 | // NOM Prenom (par grp, puis alphabétique) | |
5 | // réponse : vert si OK (+ choix), rouge si faux, gris si texte (clic pour voir) | |
6 | // + temps total ? | |
7 | // click sur en-tête de colonne : tri alphabétique, tri décroissant... | |
8 | // Affiché si (hash du) mdp du cours est correctement entré | |
9 | // Doit reprendre les données en base si refresh (sinon : sockets) | |
10 | ||
11 | // Also buttons "start exam", "end exam" for logged in teacher | |
e5ec7dea BA |
12 | |
13 | // TODO: réutiliser le component... trouver un moyen | |
14 | ||
15 | let socket = null; //monitor answers in real time | |
16 | ||
17 | function libsRefresh() | |
18 | { | |
19 | // Run Prism + MathJax on questions text | |
20 | $("#statements").find("code[class^=language-]").each( (i,elem) => { | |
21 | Prism.highlightElement(elem); | |
22 | }); | |
23 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,"statements"]); | |
24 | } | |
25 | ||
26 | new Vue({ | |
27 | el: "#monitor", | |
28 | data: { | |
29 | password: "", //from password field | |
30 | assessment: null, //obtained after authentication | |
31 | // Stage 0: unauthenticated (password), | |
32 | // 1: authenticated (password hash validated), start monitoring | |
33 | stage: 0, | |
34 | }, | |
35 | components: { | |
36 | "statements": { | |
37 | props: ['assessment','inputs','student','stage'], | |
38 | // TODO: general render function for nested exercises | |
39 | // There should be a questions navigator below, or next (visible if display=='all') | |
40 | // Full questions tree is rendered, but some parts hidden depending on display settings | |
41 | render(h) { | |
42 | let self = this; | |
43 | let questions = (assessment.questions || [ ]).map( (q,i) => { | |
44 | let questionContent = [ ]; | |
45 | questionContent.push( | |
46 | h( | |
47 | "div", | |
48 | { | |
49 | "class": { | |
50 | wording: true, | |
51 | }, | |
52 | domProps: { | |
53 | innerHTML: q.wording, | |
54 | }, | |
55 | } | |
56 | ) | |
57 | ); | |
58 | let optionsOrder = _.range(q.options.length); | |
59 | if (!q.fixed) | |
60 | optionsOrder = _.shuffle(optionsOrder); | |
61 | let optionList = [ ]; | |
62 | optionsOrder.forEach( idx => { | |
63 | let option = [ ]; | |
64 | option.push( | |
65 | h( | |
66 | "input", | |
67 | { | |
68 | domProps: { | |
69 | checked: this.inputs.length > 0 && this.inputs[i][idx], | |
70 | }, | |
71 | attrs: { | |
72 | id: this.inputId(i,idx), | |
73 | type: "checkbox", | |
74 | }, | |
75 | on: { | |
76 | change: e => { this.inputs[i][idx] = e.target.checked; }, | |
77 | }, | |
78 | }, | |
79 | ) | |
80 | ); | |
81 | option.push( | |
82 | h( | |
83 | "label", | |
84 | { | |
85 | domProps: { | |
86 | innerHTML: q.options[idx], | |
87 | }, | |
88 | attrs: { | |
89 | "for": this.inputId(i,idx), | |
90 | }, | |
91 | } | |
92 | ) | |
93 | ); | |
94 | optionList.push( | |
95 | h( | |
96 | "div", | |
97 | { | |
98 | "class": { | |
99 | option: true, | |
100 | choiceCorrect: this.stage == 4 && assessment.questions[i].answer.includes(idx), | |
101 | choiceWrong: this.stage == 4 && this.inputs[i][idx] && !assessment.questions[i].answer.includes(idx), | |
102 | }, | |
103 | }, | |
104 | option | |
105 | ) | |
106 | ); | |
107 | }); | |
108 | questionContent.push( | |
109 | h( | |
110 | "div", | |
111 | { | |
112 | "class": { | |
113 | optionList: true, | |
114 | }, | |
115 | }, | |
116 | optionList | |
117 | ) | |
118 | ); | |
119 | return h( | |
120 | "div", | |
121 | { | |
122 | "class": { | |
123 | "question": true, | |
124 | "hide": this.stage == 2 && assessment.display == 'one' && assessment.indices[assessment.index] != i, | |
125 | }, | |
126 | }, | |
127 | questionContent | |
128 | ); | |
129 | }); | |
130 | if (this.stage == 2) | |
131 | { | |
132 | questions.unshift( | |
133 | h( | |
134 | "button", | |
135 | { | |
136 | "class": { | |
137 | "waves-effect": true, | |
138 | "waves-light": true, | |
139 | "btn": true, | |
140 | }, | |
141 | style: { | |
142 | "display": "block", | |
143 | "margin-left": "auto", | |
144 | "margin-right": "auto", | |
145 | }, | |
146 | on: { | |
147 | click: () => this.sendAnswer(assessment.indices[assessment.index]), | |
148 | }, | |
149 | }, | |
150 | "Send" | |
151 | ) | |
152 | ); | |
153 | } | |
154 | return h( | |
155 | "div", | |
156 | { | |
157 | attrs: { | |
158 | id: "statements", | |
159 | }, | |
160 | }, | |
161 | questions | |
162 | ); | |
163 | }, | |
164 | mounted: function() { | |
165 | libsRefresh(); | |
166 | }, | |
167 | methods: { | |
168 | inputId: function(i,j) { | |
169 | return "q" + i + "_" + "input" + j; | |
170 | }, | |
171 | }, | |
172 | }, | |
173 | }, | |
174 | methods: { | |
175 | // stage 0 --> 1 | |
176 | startMonitoring: function() { | |
177 | $.ajax("/start/monitoring", { | |
178 | method: "GET", | |
179 | data: { | |
180 | password: this., | |
181 | aname: examName, | |
182 | cname: courseName, | |
183 | }, | |
184 | dataType: "json", | |
185 | success: s => { | |
186 | if (!!s.errmsg) | |
187 | return this.warning(s.errmsg); | |
188 | this.stage = 1; | |
189 | }, | |
190 | }); | |
191 | }, | |
192 | // TODO: 2-level sockets, for prof and monitors | |
193 | socket = io.connect("/" + assessment.name, { | |
194 | query: "number=" + this.student.number + "&password=" + this.password | |
195 | }); | |
196 | socket.on(message.allAnswers, this.setAnswers); | |
197 | initializeStage2(s.questions, s.paper); | |
198 | }, | |
199 | }); | |
200 | }, | |
201 | // stage 2 --> 3 (or 4) | |
202 | // from a message by statements component, or time over | |
203 | // TODO: also function startAssessment (for main teacher only) | |
204 | endAssessment: function() { | |
205 | // Set endTime, destroy password | |
206 | $("#leftButton, #rightButton").show(); | |
207 | if (assessment.mode == "open") | |
208 | { | |
209 | this.stage = 4; | |
210 | return; | |
211 | } | |
212 | $.ajax("/end/assessment", { | |
213 | method: "GET", | |
214 | data: { | |
215 | aid: assessment._id, | |
216 | number: this.student.number, | |
217 | password: this.student.password, | |
218 | }, | |
219 | dataType: "json", | |
220 | success: ret => { | |
221 | if (!!ret.errmsg) | |
222 | return this.warning(ret.errmsg); | |
223 | assessment.conclusion = ret.conclusion; | |
224 | this.stage = 3; | |
225 | delete this.student["password"]; //unable to send new answers now | |
226 | socket.disconnect(); | |
227 | socket = null; | |
228 | }, | |
229 | }); | |
230 | }, | |
231 | }, | |
232 | }); |