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) | |
c8f68697 | 42 | evaluationIndex: -1, //current edited evaluation index |
a3080c33 BA |
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() { | |
cb39647a | 47 | $('.modal').modal(); |
c8f68697 | 48 | //Materialize.updateTextFields(); //textareas, time field... |
8a2b3260 BA |
49 | }, |
50 | methods: { | |
51 | // GENERAL: | |
52 | toggleDisplay: function(area) { | |
53 | if (this.display == area) | |
54 | this.display = ""; | |
55 | else | |
56 | this.display = area; | |
57 | }, | |
58 | studentList: function(group) { | |
59 | return this.course.students | |
60 | .filter( s => { return group==0 || s.group == group; }) | |
61 | .map( s => { return Object.assign({}, s); }) //not altering initial array | |
62 | .sort( (a,b) => { return a.name.localeCompare(b.name); }) | |
63 | }, | |
64 | // STUDENTS: | |
65 | uploadTrigger: function() { | |
66 | $("#upload").click(); | |
67 | }, | |
68 | upload: function(e) { | |
69 | let file = (e.target.files || e.dataTransfer.files)[0]; | |
70 | Papa.parse(file, { | |
71 | header: true, | |
72 | skipEmptyLines: true, | |
73 | complete: (results,file) => { | |
74 | let students = [ ]; | |
75 | // Post-process: add group/number if missing | |
76 | let number = 1; | |
77 | results.data.forEach( d => { | |
78 | if (!d.group) | |
79 | d.group = 1; | |
80 | if (!d.number) | |
81 | d.number = number++; | |
82 | if (typeof d.number !== "string") | |
83 | d.number = d.number.toString(); | |
84 | students.push(d); | |
85 | }); | |
73609d3b BA |
86 | $.ajax("/courses/student-list", { |
87 | method: "PUT", | |
e99c53fb | 88 | data: { |
8a2b3260 BA |
89 | cid: this.course._id, |
90 | students: JSON.stringify(students), | |
e99c53fb BA |
91 | }, |
92 | dataType: "json", | |
93 | success: res => { | |
94 | if (!res.errmsg) | |
8a2b3260 | 95 | this.course.students = students; |
e99c53fb BA |
96 | else |
97 | alert(res.errmsg); | |
98 | }, | |
8a2b3260 BA |
99 | }); |
100 | }, | |
101 | }); | |
102 | }, | |
a3080c33 BA |
103 | // evaluation: |
104 | addEvaluation: function() { | |
8a2b3260 BA |
105 | if (!admin) |
106 | return; | |
107 | // modal, fill code and description | |
a3080c33 | 108 | let error = Validator.checkObject(this.newEvaluation, "Evaluation"); |
8a2b3260 BA |
109 | if (!!error) |
110 | return alert(error); | |
111 | else | |
a3080c33 BA |
112 | $('#newEvaluation').modal('close'); |
113 | $.ajax("/evaluations", | |
8a2b3260 | 114 | { |
73609d3b | 115 | method: "POST", |
8a2b3260 | 116 | data: { |
a3080c33 | 117 | name: this.newEvaluation.name, |
8a2b3260 BA |
118 | cid: course._id, |
119 | }, | |
e99c53fb BA |
120 | dataType: "json", |
121 | success: res => { | |
122 | if (!res.errmsg) | |
123 | { | |
a3080c33 BA |
124 | this.newEvaluation["name"] = ""; |
125 | this.evaluationArray.push(res); | |
e99c53fb BA |
126 | } |
127 | else | |
128 | alert(res.errmsg); | |
129 | }, | |
e99c53fb | 130 | } |
8a2b3260 BA |
131 | ); |
132 | }, | |
a3080c33 BA |
133 | updateEvaluation: function() { |
134 | $.ajax("/evaluations", { | |
73609d3b | 135 | method: "PUT", |
a3080c33 | 136 | data: {evaluation: JSON.stringify(this.evaluation)}, |
8a2b3260 BA |
137 | dataType: "json", |
138 | success: res => { | |
139 | if (!res.errmsg) | |
e99c53fb | 140 | { |
a3080c33 | 141 | this.evaluationArray[this.evaluationIndex] = this.evaluation; |
8a2b3260 | 142 | this.mode = "view"; |
e99c53fb BA |
143 | } |
144 | else | |
8a2b3260 BA |
145 | alert(res.errmsg); |
146 | }, | |
147 | }); | |
148 | }, | |
a3080c33 | 149 | deleteEvaluation: function(evaluation) { |
8a2b3260 BA |
150 | if (!admin) |
151 | return; | |
a3080c33 | 152 | if (confirm("Delete evaluation '" + evaluation.name + "' ?")) |
8a2b3260 | 153 | { |
a3080c33 | 154 | $.ajax("/evaluations", |
e99c53fb | 155 | { |
73609d3b | 156 | method: "DELETE", |
a3080c33 | 157 | data: { qid: this.evaluation._id }, |
e99c53fb BA |
158 | dataType: "json", |
159 | success: res => { | |
160 | if (!res.errmsg) | |
a3080c33 BA |
161 | this.evaluationArray.splice( this.evaluationArray.findIndex( item => { |
162 | return item._id == evaluation._id; | |
8a2b3260 | 163 | }), 1 ); |
e99c53fb BA |
164 | else |
165 | alert(res.errmsg); | |
166 | }, | |
167 | } | |
168 | ); | |
8a2b3260 BA |
169 | } |
170 | }, | |
171 | toggleState: function(questionIndex) { | |
a3080c33 BA |
172 | // add or remove from activeSet of current evaluation |
173 | let activeIndex = this.evaluation.activeSet.findIndex( item => { return item == questionIndex; }); | |
8a2b3260 | 174 | if (activeIndex >= 0) |
a3080c33 | 175 | this.evaluation.activeSet.splice(activeIndex, 1); |
8a2b3260 | 176 | else |
a3080c33 | 177 | this.evaluation.activeSet.push(questionIndex); |
8a2b3260 | 178 | }, |
a3080c33 | 179 | setEvaluationText: function() { |
8a2b3260 | 180 | let txt = ""; |
a3080c33 | 181 | this.evaluation.questions.forEach( q => { |
8a2b3260 BA |
182 | txt += q.wording; //already ended by \n |
183 | q.options.forEach( (o,i) => { | |
184 | let symbol = q.answer.includes(i) ? "+" : "-"; | |
185 | txt += symbol + " " + o + "\n"; | |
186 | }); | |
187 | txt += "\n"; //separate questions by new line | |
188 | }); | |
a3080c33 | 189 | this.questionsText = txt; |
8a2b3260 | 190 | }, |
a3080c33 | 191 | parseEvaluation: function() { |
8a2b3260 | 192 | let questions = [ ]; |
a3080c33 | 193 | let lines = this.questionsText.split("\n").map( L => { return L.trim(); }) |
8a2b3260 BA |
194 | lines.push(""); //easier parsing |
195 | let emptyQuestion = () => { | |
196 | return { | |
197 | wording: "", | |
198 | options: [ ], | |
199 | answer: [ ], | |
200 | active: true, //default | |
201 | }; | |
202 | }; | |
203 | let q = emptyQuestion(); | |
204 | lines.forEach( L => { | |
205 | if (L.length > 0) | |
206 | { | |
207 | if (['+','-'].includes(L.charAt(0))) | |
e99c53fb | 208 | { |
8a2b3260 BA |
209 | if (L.charAt(0) == '+') |
210 | q.answer.push(q.options.length); | |
211 | q.options.push(L.slice(1).trim()); | |
e99c53fb | 212 | } |
8a2b3260 BA |
213 | else if (L.charAt(0) == '*') |
214 | { | |
215 | // TODO: read current + next lines into q.answer (HTML, 1-elem array) | |
216 | } | |
217 | else | |
218 | q.wording += L + "\n"; | |
219 | } | |
220 | else | |
221 | { | |
222 | // Flush current question (if any) | |
223 | if (q.wording.length > 0) | |
224 | { | |
225 | questions.push(q); | |
226 | q = emptyQuestion(); | |
227 | } | |
228 | } | |
229 | }); | |
a3080c33 | 230 | this.evaluation.questions = questions; |
8a2b3260 | 231 | }, |
a3080c33 | 232 | actionEvaluation: function(index) { |
8a2b3260 BA |
233 | if (admin) |
234 | { | |
235 | // Edit screen | |
a3080c33 BA |
236 | this.evaluationIndex = index; |
237 | this.evaluation = $.extend(true, {}, this.evaluationArray[index]); | |
238 | this.setEvaluationText(); | |
8a2b3260 | 239 | this.mode = "edit"; |
a3080c33 | 240 | Vue.nextTick(statementsLibsRefresh); |
8a2b3260 | 241 | } |
a3080c33 BA |
242 | else //external user: show evaluation |
243 | this.redirect(this.evaluationArray[index].name); | |
e99c53fb | 244 | }, |
a3080c33 BA |
245 | redirect: function(evaluationName) { |
246 | document.location.href = "/" + initials + "/" + course.code + "/" + evaluationName; | |
8a2b3260 BA |
247 | }, |
248 | setPassword: function() { | |
249 | let hashPwd = Sha1.Compute(this.monitorPwd); | |
250 | let error = Validator.checkObject({password:hashPwd}, "Course"); | |
251 | if (error.length > 0) | |
252 | return alert(error); | |
73609d3b | 253 | $.ajax("/courses/password", |
8a2b3260 | 254 | { |
73609d3b | 255 | method: "PUT", |
8a2b3260 BA |
256 | data: { |
257 | cid: this.course._id, | |
258 | pwd: hashPwd, | |
259 | }, | |
260 | dataType: "json", | |
261 | success: res => { | |
262 | if (!res.errmsg) | |
263 | alert("Password saved!"); | |
264 | else | |
265 | alert(res.errmsg); | |
266 | }, | |
267 | } | |
268 | ); | |
269 | }, | |
270 | // NOTE: artifact required for Vue v-model to behave well | |
43828378 | 271 | checkboxFixedId: function(i) { |
8a2b3260 BA |
272 | return "questionFixed" + i; |
273 | }, | |
43828378 | 274 | checkboxActiveId: function(i) { |
8a2b3260 BA |
275 | return "questionActive" + i; |
276 | }, | |
8a2b3260 BA |
277 | }, |
278 | }); |