1 /*Draft format (compiled to json)
3 > Some global (HTML) intro
5 <some html question (or/+ exercise intro)>
7 <some html subQuestion>
8 * some answer [trigger input/index in answers]
23 <Some second question>
30 display: "assessments", //or "students", or "grades" (admin mode)
32 mode: "view", //or "edit" (some assessment)
34 newAssessment: { name: "" },
35 assessmentArray: assessmentArray
,
36 assessmentIndex: 0, //current edited assessment index
37 assessment: { }, //copy of assessment at editing index in array
38 assessmentText: "", //questions in an assessment, in text format
41 $('.modal').each( (i
,elem
) => {
42 if (elem
.id
!= "assessmentEdit")
46 $('#assessmentEdit').modal({
48 this.parseAssessment();
50 $("#questionList").find("code[class^=language-]").each( (i
,elem
) => {
51 Prism
.highlightElement(elem
);
53 MathJax
.Hub
.Queue(["Typeset",MathJax
.Hub
,"questionList"]);
60 toggleDisplay: function(area
) {
61 if (this.display
== area
)
66 studentList: function(group
) {
67 return this.course
.students
68 .filter( s
=> { return group
==0 || s
.group
== group
; })
69 .map( s
=> { return Object
.assign({}, s
); }) //not altering initial array
70 .sort( (a
,b
) => { return a
.name
.localeCompare(b
.name
); })
73 uploadTrigger: function() {
77 let file
= (e
.target
.files
|| e
.dataTransfer
.files
)[0];
81 complete: (results
,file
) => {
83 // Post-process: add group/number if missing
85 results
.data
.forEach( d
=> {
90 if (typeof d
.number
!== "string")
91 d
.number
= d
.number
.toString();
94 $.ajax("/courses/student-list", {
98 students: JSON
.stringify(students
),
103 this.course
.students
= students
;
112 addAssessment: function() {
115 // modal, fill code and description
116 let error
= Validator
.checkObject(this.newAssessment
, "Assessment");
120 $('#newAssessment').modal('close');
121 $.ajax("/assessments",
125 name: this.newAssessment
.name
,
132 this.newAssessment
["name"] = "";
133 this.assessmentArray
.push(res
);
141 materialOpenModal: function(id
) {
142 $("#" + id
).modal("open");
143 Materialize
.updateTextFields(); //textareas, time field...
145 updateAssessment: function() {
146 $.ajax("/assessments", {
148 data: {assessment: JSON
.stringify(this.assessment
)},
153 this.assessmentArray
[this.assessmentIndex
] = this.assessment
;
161 deleteAssessment: function(assessment
) {
164 if (confirm("Delete assessment '" + assessment
.name
+ "' ?"))
166 $.ajax("/assessments",
169 data: { qid: this.assessment
._id
},
173 this.assessmentArray
.splice( this.assessmentArray
.findIndex( item
=> {
174 return item
._id
== assessment
._id
;
183 toggleState: function(questionIndex
) {
184 // add or remove from activeSet of current assessment
185 let activeIndex
= this.assessment
.activeSet
.findIndex( item
=> { return item
== questionIndex
; });
186 if (activeIndex
>= 0)
187 this.assessment
.activeSet
.splice(activeIndex
, 1);
189 this.assessment
.activeSet
.push(questionIndex
);
191 setAssessmentText: function() {
193 this.assessment
.questions
.forEach( q
=> {
194 txt
+= q
.wording
; //already ended by \n
195 q
.options
.forEach( (o
,i
) => {
196 let symbol
= q
.answer
.includes(i
) ? "+" : "-";
197 txt
+= symbol
+ " " + o
+ "\n";
199 txt
+= "\n"; //separate questions by new line
201 this.assessmentText
= txt
;
203 parseAssessment: function() {
205 let lines
= this.assessmentText
.split("\n").map( L
=> { return L
.trim(); })
206 lines
.push(""); //easier parsing
207 let emptyQuestion
= () => {
212 active: true, //default
215 let q
= emptyQuestion();
216 lines
.forEach( L
=> {
219 if (['+','-'].includes(L
.charAt(0)))
221 if (L
.charAt(0) == '+')
222 q
.answer
.push(q
.options
.length
);
223 q
.options
.push(L
.slice(1).trim());
225 else if (L
.charAt(0) == '*')
227 // TODO: read current + next lines into q.answer (HTML, 1-elem array)
230 q
.wording
+= L
+ "\n";
234 // Flush current question (if any)
235 if (q
.wording
.length
> 0)
242 this.assessment
.questions
= questions
;
244 actionAssessment: function(index
) {
248 this.assessmentIndex
= index
;
249 this.assessment
= $.extend(true, {}, this.assessmentArray
[index
]);
250 this.setAssessmentText();
252 Vue
.nextTick( () => {
253 $("#questionList").find("code[class^=language-]").each( (i
,elem
) => {
254 Prism
.highlightElement(elem
);
256 MathJax
.Hub
.Queue(["Typeset",MathJax
.Hub
,"questionList"]);
259 else //external user: show assessment
260 this.redirect(this.assessmentArray
[index
].name
);
262 redirect: function(assessmentName
) {
263 document
.location
.href
= "/" + initials
+ "/" + course
.code
+ "/" + assessmentName
;
265 setPassword: function() {
266 let hashPwd
= Sha1
.Compute(this.monitorPwd
);
267 let error
= Validator
.checkObject({password:hashPwd
}, "Course");
268 if (error
.length
> 0)
270 $.ajax("/courses/password",
274 cid: this.course
._id
,
280 alert("Password saved!");
287 // NOTE: artifact required for Vue v-model to behave well
288 checkboxFixedId: function(i
) {
289 return "questionFixed" + i
;
291 checkboxActiveId: function(i
) {
292 return "questionActive" + i
;