Commit | Line | Data |
---|---|---|
43828378 | 1 | /*Draft format (compiled to json) |
14c9c66a | 2 | * TODO: separate questions and answers in Evaluation object |
43828378 | 3 | |
43828378 BA |
4 | <some html question (or/+ exercise intro)> |
5 | ||
6 | <some html subQuestion> | |
7 | * some answer [trigger input/index in answers] | |
8 | ||
9 | <another subquestion> | |
10 | ||
11 | <sub-subQuestion> | |
12 | + choix1 | |
13 | - choix 2 | |
14 | + choix 3 | |
15 | - choix4 | |
16 | ||
14c9c66a BA |
17 | <another sub sub> with params interpolation £ (tout simplement) |
18 | / params: javascript parameter generator (another function, body only) | |
43828378 BA |
19 | * answer 2 (which can |
20 | be on | |
21 | several lines) | |
22 | ||
23 | <Some second question> | |
24 | * With answer | |
14c9c66a BA |
25 | |
26 | dans le cas de parametetrized, answer est une fonction javascript !! qui prend en arg le(s) param(s) | |
27 | coté serveur on stock parameterized question + body func | |
28 | une fois côté client, extra work first to 1) execute each func 2) replace (and store!!!) all params | |
29 | https://stackoverflow.com/questions/7650071/is-there-a-way-to-create-a-function-from-a-string-with-javascript | |
30 | ||
31 | */ | |
e99c53fb | 32 | |
8a2b3260 BA |
33 | new Vue({ |
34 | el: '#course', | |
35 | data: { | |
14c9c66a | 36 | display: "evaluations", //or "students" (in admin mode) |
8a2b3260 | 37 | course: course, |
8a2b3260 | 38 | monitorPwd: "", |
a3080c33 BA |
39 | newEvaluation: { name: "" }, |
40 | evaluationArray: evaluationArray, | |
41 | mode: "view", //or "edit" (some evaluation) | |
42 | evaluationIndex: 0, //current edited evaluation index | |
43 | evaluation: { }, //copy of evaluation at editing index in array | |
44 | questionsText: "", //questions in an evaluation, in text format | |
8a2b3260 BA |
45 | }, |
46 | mounted: function() { | |
a3080c33 BA |
47 | |
48 | ||
49 | ||
8a2b3260 | 50 | $('.modal').each( (i,elem) => { |
a3080c33 | 51 | if (elem.id != "evaluationEdit") |
8a2b3260 BA |
52 | $(elem).modal(); |
53 | }); | |
a3080c33 BA |
54 | $('ul.tabs').tabs(); //--> migrate to grade.js |
55 | ||
56 | ||
57 | ||
58 | $('#evaluationEdit').modal({ | |
8a2b3260 | 59 | complete: () => { |
a3080c33 BA |
60 | this.parseEvaluation(); |
61 | Vue.nextTick(statementsLibsRefresh); | |
e99c53fb | 62 | }, |
8a2b3260 BA |
63 | }); |
64 | }, | |
65 | methods: { | |
66 | // GENERAL: | |
67 | toggleDisplay: function(area) { | |
68 | if (this.display == area) | |
69 | this.display = ""; | |
70 | else | |
71 | this.display = area; | |
72 | }, | |
73 | studentList: function(group) { | |
74 | return this.course.students | |
75 | .filter( s => { return group==0 || s.group == group; }) | |
76 | .map( s => { return Object.assign({}, s); }) //not altering initial array | |
77 | .sort( (a,b) => { return a.name.localeCompare(b.name); }) | |
78 | }, | |
79 | // STUDENTS: | |
80 | uploadTrigger: function() { | |
81 | $("#upload").click(); | |
82 | }, | |
83 | upload: function(e) { | |
84 | let file = (e.target.files || e.dataTransfer.files)[0]; | |
85 | Papa.parse(file, { | |
86 | header: true, | |
87 | skipEmptyLines: true, | |
88 | complete: (results,file) => { | |
89 | let students = [ ]; | |
90 | // Post-process: add group/number if missing | |
91 | let number = 1; | |
92 | results.data.forEach( d => { | |
93 | if (!d.group) | |
94 | d.group = 1; | |
95 | if (!d.number) | |
96 | d.number = number++; | |
97 | if (typeof d.number !== "string") | |
98 | d.number = d.number.toString(); | |
99 | students.push(d); | |
100 | }); | |
73609d3b BA |
101 | $.ajax("/courses/student-list", { |
102 | method: "PUT", | |
e99c53fb | 103 | data: { |
8a2b3260 BA |
104 | cid: this.course._id, |
105 | students: JSON.stringify(students), | |
e99c53fb BA |
106 | }, |
107 | dataType: "json", | |
108 | success: res => { | |
109 | if (!res.errmsg) | |
8a2b3260 | 110 | this.course.students = students; |
e99c53fb BA |
111 | else |
112 | alert(res.errmsg); | |
113 | }, | |
8a2b3260 BA |
114 | }); |
115 | }, | |
116 | }); | |
117 | }, | |
a3080c33 BA |
118 | // evaluation: |
119 | addEvaluation: function() { | |
8a2b3260 BA |
120 | if (!admin) |
121 | return; | |
122 | // modal, fill code and description | |
a3080c33 | 123 | let error = Validator.checkObject(this.newEvaluation, "Evaluation"); |
8a2b3260 BA |
124 | if (!!error) |
125 | return alert(error); | |
126 | else | |
a3080c33 BA |
127 | $('#newEvaluation').modal('close'); |
128 | $.ajax("/evaluations", | |
8a2b3260 | 129 | { |
73609d3b | 130 | method: "POST", |
8a2b3260 | 131 | data: { |
a3080c33 | 132 | name: this.newEvaluation.name, |
8a2b3260 BA |
133 | cid: course._id, |
134 | }, | |
e99c53fb BA |
135 | dataType: "json", |
136 | success: res => { | |
137 | if (!res.errmsg) | |
138 | { | |
a3080c33 BA |
139 | this.newEvaluation["name"] = ""; |
140 | this.evaluationArray.push(res); | |
e99c53fb BA |
141 | } |
142 | else | |
143 | alert(res.errmsg); | |
144 | }, | |
e99c53fb | 145 | } |
8a2b3260 BA |
146 | ); |
147 | }, | |
148 | materialOpenModal: function(id) { | |
149 | $("#" + id).modal("open"); | |
150 | Materialize.updateTextFields(); //textareas, time field... | |
151 | }, | |
a3080c33 BA |
152 | updateEvaluation: function() { |
153 | $.ajax("/evaluations", { | |
73609d3b | 154 | method: "PUT", |
a3080c33 | 155 | data: {evaluation: JSON.stringify(this.evaluation)}, |
8a2b3260 BA |
156 | dataType: "json", |
157 | success: res => { | |
158 | if (!res.errmsg) | |
e99c53fb | 159 | { |
a3080c33 | 160 | this.evaluationArray[this.evaluationIndex] = this.evaluation; |
8a2b3260 | 161 | this.mode = "view"; |
e99c53fb BA |
162 | } |
163 | else | |
8a2b3260 BA |
164 | alert(res.errmsg); |
165 | }, | |
166 | }); | |
167 | }, | |
a3080c33 | 168 | deleteEvaluation: function(evaluation) { |
8a2b3260 BA |
169 | if (!admin) |
170 | return; | |
a3080c33 | 171 | if (confirm("Delete evaluation '" + evaluation.name + "' ?")) |
8a2b3260 | 172 | { |
a3080c33 | 173 | $.ajax("/evaluations", |
e99c53fb | 174 | { |
73609d3b | 175 | method: "DELETE", |
a3080c33 | 176 | data: { qid: this.evaluation._id }, |
e99c53fb BA |
177 | dataType: "json", |
178 | success: res => { | |
179 | if (!res.errmsg) | |
a3080c33 BA |
180 | this.evaluationArray.splice( this.evaluationArray.findIndex( item => { |
181 | return item._id == evaluation._id; | |
8a2b3260 | 182 | }), 1 ); |
e99c53fb BA |
183 | else |
184 | alert(res.errmsg); | |
185 | }, | |
186 | } | |
187 | ); | |
8a2b3260 BA |
188 | } |
189 | }, | |
190 | toggleState: function(questionIndex) { | |
a3080c33 BA |
191 | // add or remove from activeSet of current evaluation |
192 | let activeIndex = this.evaluation.activeSet.findIndex( item => { return item == questionIndex; }); | |
8a2b3260 | 193 | if (activeIndex >= 0) |
a3080c33 | 194 | this.evaluation.activeSet.splice(activeIndex, 1); |
8a2b3260 | 195 | else |
a3080c33 | 196 | this.evaluation.activeSet.push(questionIndex); |
8a2b3260 | 197 | }, |
a3080c33 | 198 | setEvaluationText: function() { |
8a2b3260 | 199 | let txt = ""; |
a3080c33 | 200 | this.evaluation.questions.forEach( q => { |
8a2b3260 BA |
201 | txt += q.wording; //already ended by \n |
202 | q.options.forEach( (o,i) => { | |
203 | let symbol = q.answer.includes(i) ? "+" : "-"; | |
204 | txt += symbol + " " + o + "\n"; | |
205 | }); | |
206 | txt += "\n"; //separate questions by new line | |
207 | }); | |
a3080c33 | 208 | this.questionsText = txt; |
8a2b3260 | 209 | }, |
a3080c33 | 210 | parseEvaluation: function() { |
8a2b3260 | 211 | let questions = [ ]; |
a3080c33 | 212 | let lines = this.questionsText.split("\n").map( L => { return L.trim(); }) |
8a2b3260 BA |
213 | lines.push(""); //easier parsing |
214 | let emptyQuestion = () => { | |
215 | return { | |
216 | wording: "", | |
217 | options: [ ], | |
218 | answer: [ ], | |
219 | active: true, //default | |
220 | }; | |
221 | }; | |
222 | let q = emptyQuestion(); | |
223 | lines.forEach( L => { | |
224 | if (L.length > 0) | |
225 | { | |
226 | if (['+','-'].includes(L.charAt(0))) | |
e99c53fb | 227 | { |
8a2b3260 BA |
228 | if (L.charAt(0) == '+') |
229 | q.answer.push(q.options.length); | |
230 | q.options.push(L.slice(1).trim()); | |
e99c53fb | 231 | } |
8a2b3260 BA |
232 | else if (L.charAt(0) == '*') |
233 | { | |
234 | // TODO: read current + next lines into q.answer (HTML, 1-elem array) | |
235 | } | |
236 | else | |
237 | q.wording += L + "\n"; | |
238 | } | |
239 | else | |
240 | { | |
241 | // Flush current question (if any) | |
242 | if (q.wording.length > 0) | |
243 | { | |
244 | questions.push(q); | |
245 | q = emptyQuestion(); | |
246 | } | |
247 | } | |
248 | }); | |
a3080c33 | 249 | this.evaluation.questions = questions; |
8a2b3260 | 250 | }, |
a3080c33 | 251 | actionEvaluation: function(index) { |
8a2b3260 BA |
252 | if (admin) |
253 | { | |
254 | // Edit screen | |
a3080c33 BA |
255 | this.evaluationIndex = index; |
256 | this.evaluation = $.extend(true, {}, this.evaluationArray[index]); | |
257 | this.setEvaluationText(); | |
8a2b3260 | 258 | this.mode = "edit"; |
a3080c33 | 259 | Vue.nextTick(statementsLibsRefresh); |
8a2b3260 | 260 | } |
a3080c33 BA |
261 | else //external user: show evaluation |
262 | this.redirect(this.evaluationArray[index].name); | |
e99c53fb | 263 | }, |
a3080c33 BA |
264 | redirect: function(evaluationName) { |
265 | document.location.href = "/" + initials + "/" + course.code + "/" + evaluationName; | |
8a2b3260 BA |
266 | }, |
267 | setPassword: function() { | |
268 | let hashPwd = Sha1.Compute(this.monitorPwd); | |
269 | let error = Validator.checkObject({password:hashPwd}, "Course"); | |
270 | if (error.length > 0) | |
271 | return alert(error); | |
73609d3b | 272 | $.ajax("/courses/password", |
8a2b3260 | 273 | { |
73609d3b | 274 | method: "PUT", |
8a2b3260 BA |
275 | data: { |
276 | cid: this.course._id, | |
277 | pwd: hashPwd, | |
278 | }, | |
279 | dataType: "json", | |
280 | success: res => { | |
281 | if (!res.errmsg) | |
282 | alert("Password saved!"); | |
283 | else | |
284 | alert(res.errmsg); | |
285 | }, | |
286 | } | |
287 | ); | |
288 | }, | |
289 | // NOTE: artifact required for Vue v-model to behave well | |
43828378 | 290 | checkboxFixedId: function(i) { |
8a2b3260 BA |
291 | return "questionFixed" + i; |
292 | }, | |
43828378 | 293 | checkboxActiveId: function(i) { |
8a2b3260 BA |
294 | return "questionActive" + i; |
295 | }, | |
8a2b3260 BA |
296 | }, |
297 | }); |