X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=public%2Fjavascripts%2Fcourse.js;h=65b6ab75ec385efc96ed60c3acdbefa02236bad9;hb=a3080c337cfaca9d600911396cae5a9233d43554;hp=8064eaf8c676d93b984d98ab83d4ba15280a3d71;hpb=8a2b3260841fc5c2e0d24758bf94628ac52300d3;p=qomet.git diff --git a/public/javascripts/course.js b/public/javascripts/course.js index 8064eaf..65b6ab7 100644 --- a/public/javascripts/course.js +++ b/public/javascripts/course.js @@ -1,45 +1,56 @@ -// TODO: YAML format for questions, parsed from text (nested questions) -// Then yaml parsed to json --> array of indexed questions -// Use open mode for question banks: add setting "nbQuestions" to show nbQuestions -// at random among active questions +/*Draft format (compiled to json) + + + + + * some answer [trigger input/index in answers] + + + + + + choix1 + - choix 2 + + choix 3 + - choix4 + + + * answer 2 (which can + be on + several lines) + + +* With answer +*/ new Vue({ el: '#course', data: { - display: "assessments", //or "students", or "grades" (admin mode) + display: "evaluations", //or "students", or "grades" (admin mode) course: course, - mode: "view", //or "edit" (some assessment) - // assessment data: monitorPwd: "", - newAssessment: { name: "" }, - assessmentArray: assessmentArray, - assessmentIndex: 0, //current edited assessment index - assessment: { }, //copy of assessment at editing index in array - assessmentText: "", //questions in an assessment, in text format - // grades data: - settings: { - totalPoints: 20, - halfPoints: false, - zeroSum: false, - }, - group: 1, //for detailed grades tables - grades: { }, //computed + newEvaluation: { name: "" }, + evaluationArray: evaluationArray, + mode: "view", //or "edit" (some evaluation) + evaluationIndex: 0, //current edited evaluation index + evaluation: { }, //copy of evaluation at editing index in array + questionsText: "", //questions in an evaluation, in text format }, mounted: function() { + + + $('.modal').each( (i,elem) => { - if (elem.id != "assessmentEdit") + if (elem.id != "evaluationEdit") $(elem).modal(); }); - $('ul.tabs').tabs(); - $('#assessmentEdit').modal({ + $('ul.tabs').tabs(); //--> migrate to grade.js + + + + $('#evaluationEdit').modal({ complete: () => { - this.parseAssessment(); - Vue.nextTick( () => { - $("#questionList").find("code[class^=language-]").each( (i,elem) => { - Prism.highlightElement(elem); - }); - MathJax.Hub.Queue(["Typeset",MathJax.Hub,"questionList"]); - }); + this.parseEvaluation(); + Vue.nextTick(statementsLibsRefresh); }, }); }, @@ -79,8 +90,8 @@ new Vue({ d.number = d.number.toString(); students.push(d); }); - $.ajax("/import/students", { - method: "POST", + $.ajax("/courses/student-list", { + method: "PUT", data: { cid: this.course._id, students: JSON.stringify(students), @@ -96,29 +107,29 @@ new Vue({ }, }); }, - // ASSESSMENT: - addAssessment: function() { + // evaluation: + addEvaluation: function() { if (!admin) return; // modal, fill code and description - let error = Validator.checkObject(this.newAssessment, "Assessment"); + let error = Validator.checkObject(this.newEvaluation, "Evaluation"); if (!!error) return alert(error); else - $('#newAssessment').modal('close'); - $.ajax("/add/assessment", + $('#newEvaluation').modal('close'); + $.ajax("/evaluations", { - method: "GET", + method: "POST", data: { - name: this.newAssessment.name, + name: this.newEvaluation.name, cid: course._id, }, dataType: "json", success: res => { if (!res.errmsg) { - this.newAssessment["name"] = ""; - this.assessmentArray.push(res); + this.newEvaluation["name"] = ""; + this.evaluationArray.push(res); } else alert(res.errmsg); @@ -130,15 +141,15 @@ new Vue({ $("#" + id).modal("open"); Materialize.updateTextFields(); //textareas, time field... }, - updateAssessment: function() { - $.ajax("/update/assessment", { - method: "POST", - data: {assessment: JSON.stringify(this.assessment)}, + updateEvaluation: function() { + $.ajax("/evaluations", { + method: "PUT", + data: {evaluation: JSON.stringify(this.evaluation)}, dataType: "json", success: res => { if (!res.errmsg) { - this.assessmentArray[this.assessmentIndex] = this.assessment; + this.evaluationArray[this.evaluationIndex] = this.evaluation; this.mode = "view"; } else @@ -146,20 +157,20 @@ new Vue({ }, }); }, - deleteAssessment: function(assessment) { + deleteEvaluation: function(evaluation) { if (!admin) return; - if (confirm("Delete assessment '" + assessment.name + "' ?")) + if (confirm("Delete evaluation '" + evaluation.name + "' ?")) { - $.ajax("/remove/assessment", + $.ajax("/evaluations", { - method: "GET", - data: { qid: this.assessment._id }, + method: "DELETE", + data: { qid: this.evaluation._id }, dataType: "json", success: res => { if (!res.errmsg) - this.assessmentArray.splice( this.assessmentArray.findIndex( item => { - return item._id == assessment._id; + this.evaluationArray.splice( this.evaluationArray.findIndex( item => { + return item._id == evaluation._id; }), 1 ); else alert(res.errmsg); @@ -169,16 +180,16 @@ new Vue({ } }, toggleState: function(questionIndex) { - // add or remove from activeSet of current assessment - let activeIndex = this.assessment.activeSet.findIndex( item => { return item == questionIndex; }); + // add or remove from activeSet of current evaluation + let activeIndex = this.evaluation.activeSet.findIndex( item => { return item == questionIndex; }); if (activeIndex >= 0) - this.assessment.activeSet.splice(activeIndex, 1); + this.evaluation.activeSet.splice(activeIndex, 1); else - this.assessment.activeSet.push(questionIndex); + this.evaluation.activeSet.push(questionIndex); }, - setAssessmentText: function() { + setEvaluationText: function() { let txt = ""; - this.assessment.questions.forEach( q => { + this.evaluation.questions.forEach( q => { txt += q.wording; //already ended by \n q.options.forEach( (o,i) => { let symbol = q.answer.includes(i) ? "+" : "-"; @@ -186,11 +197,11 @@ new Vue({ }); txt += "\n"; //separate questions by new line }); - this.assessmentText = txt; + this.questionsText = txt; }, - parseAssessment: function() { + parseEvaluation: function() { let questions = [ ]; - let lines = this.assessmentText.split("\n").map( L => { return L.trim(); }) + let lines = this.questionsText.split("\n").map( L => { return L.trim(); }) lines.push(""); //easier parsing let emptyQuestion = () => { return { @@ -227,37 +238,32 @@ new Vue({ } } }); - this.assessment.questions = questions; + this.evaluation.questions = questions; }, - actionAssessment: function(index) { + actionEvaluation: function(index) { if (admin) { // Edit screen - this.assessmentIndex = index; - this.assessment = $.extend(true, {}, this.assessmentArray[index]); - this.setAssessmentText(); + this.evaluationIndex = index; + this.evaluation = $.extend(true, {}, this.evaluationArray[index]); + this.setEvaluationText(); this.mode = "edit"; - Vue.nextTick( () => { - $("#questionList").find("code[class^=language-]").each( (i,elem) => { - Prism.highlightElement(elem); - }); - MathJax.Hub.Queue(["Typeset",MathJax.Hub,"questionList"]); - }); + Vue.nextTick(statementsLibsRefresh); } - else //external user: show assessment - this.redirect(this.assessmentArray[index].name); + else //external user: show evaluation + this.redirect(this.evaluationArray[index].name); }, - redirect: function(assessmentName) { - document.location.href = "/" + initials + "/" + course.code + "/" + assessmentName; + redirect: function(evaluationName) { + document.location.href = "/" + initials + "/" + course.code + "/" + evaluationName; }, setPassword: function() { let hashPwd = Sha1.Compute(this.monitorPwd); let error = Validator.checkObject({password:hashPwd}, "Course"); if (error.length > 0) return alert(error); - $.ajax("/set/password", + $.ajax("/courses/password", { - method: "GET", + method: "PUT", data: { cid: this.course._id, pwd: hashPwd, @@ -273,79 +279,11 @@ new Vue({ ); }, // NOTE: artifact required for Vue v-model to behave well - checkBoxFixedId: function(i) { + checkboxFixedId: function(i) { return "questionFixed" + i; }, - checkBoxActiveId: function(i) { + checkboxActiveId: function(i) { return "questionActive" + i; }, - // GRADES: - gradeSettings: function() { - $("#gradeSettings").modal("open"); - Materialize.updateTextFields(); //total points field in grade settings overlap - }, - download: function() { - // Download (all) grades as a CSV file - let data = [ ]; - this.studentList(0).forEach( s => { - let finalGrade = 0.; - let gradesCount = 0; - if (!!this.grades[s.number]) - { - Object.keys(this.grades[s.number]).forEach( assessmentName => { - s[assessmentName] = this.grades[s.number][assessmentName]; - if (_.isNumeric(s[assessmentName]) && !isNaN(s[assessmentName])) - { - finalGrade += s[assessmentName]; - gradesCount++; - } - if (gradesCount >= 1) - finalGrade /= gradesCount; - s["final"] = finalGrade; //TODO: forbid "final" as assessment name - }); - } - data.push(s); //number,name,group,assessName1...assessNameN,final - }); - let csv = Papa.unparse(data, { - quotes: true, - header: true, - }); - let downloadAnchor = $("#download"); - downloadAnchor.attr("download", this.course.code + "_results.csv"); - downloadAnchor.attr("href", "data:text/plain;charset=utf-8," + encodeURIComponent(csv)); - this.$refs.download.click() - //downloadAnchor.click(); //fails - }, - showDetails: function(group) { - this.group = group; - $("#detailedGrades").modal("open"); - }, - groupList: function() { - let maxGrp = 1; - this.course.students.forEach( s => { - if (s.group > maxGrp) - maxGrp = s.group; - }); - return _.range(1,maxGrp+1); - }, - grade: function(assessmentIndex, studentNumber) { - if (!this.grades[assessmentIndex] || !this.grades[assessmentIndex][studentNumber]) - return ""; //no grade yet - return this.grades[assessmentIndex][studentNumber]; - }, - groupId: function(group, prefix) { - return (prefix || "") + "group" + group; - }, - togglePresence: function(number, index) { - // UNIMPLEMENTED - // TODO: if no grade (thus automatic 0), toggle "exempt" state on student for current exam - // --> automatic update of grades view (just a few number to change) - }, - computeGrades: function() { - // UNIMPLEMENTED - // TODO: compute all grades using settings (points, coefficients, bonus/malus...). - // If some questions with free answers (open), display answers and ask teacher action. - // TODO: need a setting for that too (by student, by exercice, by question) - }, }, });