| 1 | //TODO: compute grades after exam (in teacher's view) |
| 2 | |
| 3 | new Vue({ |
| 4 | el: '#grade', |
| 5 | data: { |
| 6 | evaluationArray: evaluationArray, |
| 7 | settings: { |
| 8 | totalPoints: 20, |
| 9 | halfPoints: false, |
| 10 | zeroSum: false, |
| 11 | }, |
| 12 | group: 1, //for detailed grades tables |
| 13 | grades: { }, //computed |
| 14 | }, |
| 15 | mounted: function() { |
| 16 | // TODO |
| 17 | $('ul.tabs').tabs(); //--> migrate to grade.js |
| 18 | }, |
| 19 | methods: { |
| 20 | // GRADES: |
| 21 | gradeSettings: function() { |
| 22 | $("#gradeSettings").modal("open"); |
| 23 | Materialize.updateTextFields(); //total points field in grade settings overlap |
| 24 | }, |
| 25 | download: function() { |
| 26 | // Download (all) grades as a CSV file |
| 27 | let data = [ ]; |
| 28 | this.studentList(0).forEach( s => { |
| 29 | let finalGrade = 0.; |
| 30 | let gradesCount = 0; |
| 31 | if (!!this.grades[s.number]) |
| 32 | { |
| 33 | Object.keys(this.grades[s.number]).forEach( evaluationName => { |
| 34 | s[evaluationName] = this.grades[s.number][evaluationName]; |
| 35 | if (_.isNumeric(s[evaluationName]) && !isNaN(s[evaluationName])) |
| 36 | { |
| 37 | finalGrade += s[evaluationName]; |
| 38 | gradesCount++; |
| 39 | } |
| 40 | if (gradesCount >= 1) |
| 41 | finalGrade /= gradesCount; |
| 42 | s["final"] = finalGrade; //TODO: forbid "final" as evaluation name |
| 43 | }); |
| 44 | } |
| 45 | data.push(s); //number,name,group,assessName1...assessNameN,final |
| 46 | }); |
| 47 | let csv = Papa.unparse(data, { |
| 48 | quotes: true, |
| 49 | header: true, |
| 50 | }); |
| 51 | let downloadAnchor = $("#download"); |
| 52 | downloadAnchor.attr("download", this.course.code + "_results.csv"); |
| 53 | downloadAnchor.attr("href", "data:text/plain;charset=utf-8," + encodeURIComponent(csv)); |
| 54 | this.$refs.download.click() |
| 55 | //downloadAnchor.click(); //fails |
| 56 | }, |
| 57 | showDetails: function(group) { |
| 58 | this.group = group; |
| 59 | $("#detailedGrades").modal("open"); |
| 60 | }, |
| 61 | groupList: function() { |
| 62 | let maxGrp = 1; |
| 63 | this.course.students.forEach( s => { |
| 64 | if (s.group > maxGrp) |
| 65 | maxGrp = s.group; |
| 66 | }); |
| 67 | return _.range(1,maxGrp+1); |
| 68 | }, |
| 69 | grade: function(evaluationIndex, studentNumber) { |
| 70 | if (!this.grades[evaluationIndex] || !this.grades[evaluationIndex][studentNumber]) |
| 71 | return ""; //no grade yet |
| 72 | return this.grades[evaluationIndex][studentNumber]; |
| 73 | }, |
| 74 | groupId: function(group, prefix) { |
| 75 | return (prefix || "") + "group" + group; |
| 76 | }, |
| 77 | togglePresence: function(number, index) { |
| 78 | // UNIMPLEMENTED |
| 79 | // TODO: if no grade (thus automatic 0), toggle "exempt" state on student for current exam |
| 80 | // --> automatic update of grades view (just a few number to change) |
| 81 | }, |
| 82 | computeGrades: function() { |
| 83 | // UNIMPLEMENTED |
| 84 | // TODO: compute all grades using settings (points, coefficients, bonus/malus...). |
| 85 | // If some questions with free answers (open), display answers and ask teacher action. |
| 86 | // TODO: need a setting for that too (by student, by exercice, by question) |
| 87 | }, |
| 88 | }, |
| 89 | }); |