/*eslint no-var: "error"*/ /*eslint no-console: "off"*/ /*eslint no-unused-vars: warn */ /*eslint max-len: ["error", { "code": 160 }] */ /*eslint-disable no-trailing-spaces */ /*eslint-env es6*/ // Put this file in path/to/plugin/amd/src import {SimpleLine} from './simpleline/simpleline'; import {get_strings} from 'core/str'; import {load_strings} from './util/string-helper'; import {format_date,studyplanPageTiming,studyplanTiming} from './util/date-helper'; import {call} from 'core/ajax'; import notification from 'core/notification'; import {svgarcpath} from './util/svgarc'; import Debugger from './util/debugger'; import Config from 'core/config'; import {ProcessStudyplan, ProcessStudyplanPage, objCopy} from './studyplan-processor'; import TSComponents from './treestudyplan-components'; import {eventTypes as editSwEventTypes} from 'core/edit_switch'; // Make π available as a constant const π = Math.PI; // Gravity value for arrow lines - determines how much a line is pulled in the direction of the start/end before changing direction const LINE_GRAVITY = 1.3; export default { install(Vue/*,options*/){ Vue.use(TSComponents); let debug = new Debugger("treestudyplan-viewer"); let strings = load_strings({ report: { loading: "loadinghelp@core", studyplan_past: "studyplan_past", studyplan_present: "studyplan_present", studyplan_future: "studyplan_future", back: "back", }, invalid: { error: 'error', }, header: { overall: 'overall', students: 'students@core' }, studentresults: { completion_incomplete: "completion_incomplete", completion_failed: "completion_failed", completion_pending: "completion_pending", completion_progress: "completion_progress", completion_completed: "completion_completed", completion_good: "completion_good", completion_excellent: "completion_excellent", student_not_tracked: "student_not_tracked", } }); /************************************ * * * Treestudyplan Viewer components * * * ************************************/ Vue.component('q-studyplanreport', { props: { structure: { type: Object, }, }, data() { return { students: [], studentresults: {}, expansioninfo: { periods: {}, lines: {}, items: {}, }, groupinfo: {}, sorting: { name: "asc", } }; }, created() { this.loadStudents(); }, computed: { sortedstudents(){ return this.students; } }, watch:{ structure: { immediate: true, handler (structure) { // (Re)build expansion info structure for (const period of structure.periods) { const pid = period.period.id; if (!this.expansioninfo.periods[pid]) { // Use this.$set to make sure the properties are reactive. this.$set( this.expansioninfo.periods, pid, { expanded: false, } ); this.$set( this.expansioninfo.lines, period.period.id, {} ); } for (const line of period.lines) { const lid = line.line.id; if (!this.expansioninfo.lines[lid]) { // Use this.$set to make sure the properties are reactive. this.$set( this.expansioninfo.lines[pid], lid, { expanded: true, } ); } for (const item of line.items) { if (!this.expansioninfo.items[item.id]) { // Use this.$set to make sure the properties are reactive. this.$set( this.expansioninfo.items, item.id, { expanded: false, } ); } } } } } } }, methods: { loadStudents() { const self = this; call([{ methodname: 'local_treestudyplan_all_associated_grouped', args: { studyplan_id: this.structure.studyplan.id} }])[0].then(function(response){ self.students = response; for(const group of self.students) { self.$set( self.groupinfo, group.label, { expand: true, } ); for(const student of group.users){ self.$set( self.studentresults, student.id, { loading: true, results: [], } ); call([{ methodname: 'local_treestudyplan_get_report_data', args: { pageid: self.structure.page.id, userid: student.id, firstperiod: self.structure.firstperiod, lastperiod: self.structure.lastperiod, } }])[0].then(function(response){ self.studentresults[student.id].loading = false; self.studentresults[student.id].results = response; }).catch(notification.exception); } } }).catch(notification.exception); }, expansionChanged(parm, id, val) { if(parm[0] == 'p') { parm = 'periods'; } else if(parm[0] == 'l') { parm = 'lines'; } else { parm = 'items'; } debug.info('Expansion Changed',parm,id,val); if (parm == 'lines') { this.expansioninfo[parm][id[0]][id[1]].expanded = val; } else { this.expansioninfo[parm][id].expanded = val; } } }, template: `
`, }); Vue.component('q-header', { props: { structure: { type: Object, }, sorting: { type: Object, }, expansion: { type: Object }, }, data() { return { text: strings.header, }; }, computed: { }, methods: { conditions(item) { const course = item.course; const list = []; debug.info("Determining conditions", course); if (course.completion) { debug.info("Has Competencies"); for (const cmp of course.competencies) { list.push({ name: cmp.title, }); } } else if(course.completion) { debug.info("Has Core completion"); for (const cnd of course.completion.conditions) { for (const itm of cnd.items) { list.push({ name: itm.title, }); } } } else if(course.grades) { debug.info("Has selected grades"); for (const g of course.grades) { list.push({ name: g.name, }); } } return list; }, }, mounted() { }, updated() { }, template: `
{{text.students}}
{{ p.period.fullname}}
{{ item.course.displayname}}
{{ text.overall }}
`, }); Vue.component('q-groupheading', { props: { structure: { type: Object, }, }, data() { return { }; }, computed: { }, methods: { }, template: `
`, }); Vue.component('q-studentresults', { props: { student: { type: Object, }, structure: { type: Object, }, results: { type: Array, }, loading: { type: Boolean, default: false }, expansion: { type: Object, }, }, data() { return { text: strings.studentresults, }; }, computed: { }, methods: { hasprogressinfo(item) { if (!item.course.enrolled) { return false; } else { return (item.course.completion || item.course.competency || item.course.grades); } }, completion_icon(completion) { switch(completion){ default: // case "incomplete" return "circle-o"; case "pending": return "question-circle"; case "failed": return "times-circle"; case "progress": return "exclamation-circle"; case "completed": return "check-circle"; case "good": return "check-circle"; case "excellent": return "check-circle"; } }, circle_icon(completion) { switch(completion){ default: // case "incomplete" return null; case "failed": return "times"; case "progress": return ""; case "completed": return "check"; case "good": return "check"; case "excellent": return "check"; } }, courseprogress(item) { if (!item.course.enrolled) { return 0; } else if(item.course.completion) { return (item.course.completion.progress / item.course.completion.count); } else if(item.course.competency) { return (item.course.competency.progress / item.course.competency.count); } else if(item.course.grades) { return (this.gradeprogress(item.course.grades) / item.course.grades.length); } else { return 0; } }, gradeprogress(grades) { let progress = 0; for (const ix in grades) { const g = grades[ix]; if (["completed","excellent","good"].includes(g.completion)) { progress++; } } return progress; }, conditions(item) { }, useritems(line) { const list = []; for (const item of line.items) { let newitm = item; for (const itm of this.results) { if (item.id == itm.id) { newitm = itm; break; } } list.push(newitm); } return list; } }, /* https://css-tricks.com/position-sticky-and-table-headers/ */ template: `
{{student.firstname}} {{student.lastname}}
`, }); }, };