moodle_local_treestudyplan/amd/build/studyplan-report-components.min.js.map
2024-06-03 23:24:16 +02:00

1 line
49 KiB
Plaintext

{"version":3,"file":"studyplan-report-components.min.js","sources":["../src/studyplan-report-components.js"],"sourcesContent":["/* eslint no-var: \"error\"*/\n/* eslint no-unused-vars: warn */\n/* eslint max-depth: [\"error\", 6] */\n/* eslint camelcase: \"off\" */\n/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n\nimport {loadStrings} from './util/string-helper';\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\nimport TSComponents from './treestudyplan-components';\nimport FitTextVue from './util/fittext-vue';\nimport {formatDatetime} from \"./util/date-helper\";\n\n\n/**\n * Strip tags from html\n * @param {*} html\n * @returns {string}\n */\nfunction striptags(html) {\n const tmp = document.createElement(\"DIV\");\n tmp.innerHTML = html;\n const text = tmp.textContent || tmp.innerText;\n tmp.remove();\n return text;\n}\n\n/**\n * Retrieve condition headers\n * @param {Object} item\n * @returns {Array}\n */\nfunction conditionHeaders(item) {\n const course = item.course;\n const list = [];\n if (course.competency) {\n for (const cmp of course.competency.competencies) {\n list.push({\n name: (cmp.details ? (`${cmp.title} - ${cmp.details}`) : cmp.title),\n tooltip: cmp.description,\n });\n }\n } else if (course.completion) {\n for (const cnd of course.completion.conditions) {\n for (const itm of cnd.items) {\n list.push({\n name: itm.title,\n tooltip: `${itm.details.type}: ${itm.details.requirement}`,\n });\n }\n }\n } else if (course.grades) {\n for (const g of course.grades) {\n if (g.selected) {\n list.push({\n name: g.name,\n tooltip: `${g.typename}: ${striptags(g.name)}`,\n });\n }\n }\n }\n return list;\n}\n\n/**\n * Retrieve conditions\n * @param {Object} item\n * @returns {Array}\n */\nfunction conditions(item) {\n const course = item.course;\n const list = [];\n if (course.competency) {\n for (const cmp of course.competency.competencies) {\n list.push(cmp);\n }\n } else if (course.completion) {\n for (const cnd of course.completion.conditions) {\n for (const itm of cnd.items) {\n list.push(itm);\n }\n }\n } else if (course.grades) {\n for (const g of course.grades) {\n if (g.selected) {\n list.push(g);\n }\n }\n }\n return list;\n}\n\n\nexport default {\n install(Vue /* ,options */) {\n Vue.use(TSComponents);\n Vue.use(FitTextVue);\n\n let strings = loadStrings({\n report: {\n loading: \"loadinghelp@core\",\n studyplan_past: \"studyplan_past\",\n studyplan_present: \"studyplan_present\",\n studyplan_future: \"studyplan_future\",\n back: \"back\",\n },\n\n invalid: {\n error: 'error',\n },\n header: {\n overall: 'overall',\n students: 'students@core',\n firstname: 'firstname@core',\n lastname: 'lastname@core',\n email: 'email@core',\n lastaccess: 'lastaccess@core',\n },\n studentresults: {\n completion_incomplete: \"completion_incomplete\",\n completion_failed: \"completion_failed\",\n completion_pending: \"completion_pending\",\n completion_progress: \"completion_progress\",\n completion_completed: \"completion_completed\",\n completion_good: \"completion_good\",\n completion_excellent: \"completion_excellent\",\n student_not_tracked: \"student_not_tracked\",\n never: \"never@core\",\n }\n });\n\n /* **********************************\n * *\n * Treestudyplan Viewer components *\n * *\n * **********************************/\n\n Vue.component('q-studyplanreport', {\n props: {\n structure: {\n type: Object,\n },\n },\n data() {\n return {\n students: [],\n studentresults: {},\n studentsloading: true,\n expansioninfo: {\n periods: {},\n lines: {},\n items: {},\n },\n groupinfo: {},\n\n sorting: {\n header: 'lastname',\n asc: true,\n }\n };\n },\n watch: {\n structure: {\n immediate: true,\n handler(structure) {\n this.loadStudents(); // Reload the student list\n // (Re)build expansion info structure\n let firstperiod = true;\n for (const period of structure.periods) {\n const pid = period.period.id;\n if (!this.expansioninfo.periods[pid]) {\n // Use this.$set to make sure the properties are reactive.\n this.$set(\n this.expansioninfo.periods,\n pid,\n {\n expanded: ((firstperiod && period.lines.length > 0) ? true : false),\n }\n );\n this.$set(\n this.expansioninfo.lines,\n period.period.id,\n {}\n );\n }\n for (const line of period.lines) {\n const lid = line.line.id;\n if (!this.expansioninfo.lines[lid]) {\n // Use this.$set to make sure the properties are reactive.\n this.$set(\n this.expansioninfo.lines[pid],\n lid,\n {\n expanded: true,\n }\n );\n }\n for (const item of line.items) {\n if (!this.expansioninfo.items[item.id]) {\n // Use this.$set to make sure the properties are reactive.\n this.$set(\n this.expansioninfo.items,\n item.id,\n {\n expanded: false,\n }\n );\n }\n }\n }\n firstperiod = false;\n }\n }\n }\n },\n computed: {\n sortedstudents() {\n // Probably could make a deep copy for purity's sake, but this works just as well.\n const students = this.students;\n for (const group of this.students) {\n group.users.sort((a, b) => {\n let d = a;\n let e = b;\n if (!this.sorting.asc) {\n d = b;\n e = a;\n }\n if (this.sorting.header == \"lastaccess\") {\n const dvalue = (d[this.sorting.header] ? d[this.sorting.header] : 0);\n const evalue = (e[this.sorting.header] ? e[this.sorting.header] : 0);\n return dvalue - evalue;\n } else {\n return String(d[this.sorting.header]).localeCompare(String(e[this.sorting.header]));\n }\n });\n }\n return students;\n },\n resultColCount() {\n let count = 0;\n for (const period of this.structure.periods) {\n const pid = period.period.id;\n if (!this.expansioninfo.periods[pid].expanded) {\n // This period is not expanded. Make it 3 units wide\n count += 2;\n } else {\n for (const line of period.lines) {\n const lid = line.line.id;\n if (!this.expansioninfo.lines[pid][lid].expanded) {\n count += 1;\n } else {\n for (const item of line.items) {\n if (!this.expansioninfo.items[item.id].expanded) {\n count += 1;\n } else {\n count += 1 + conditions(item).length;\n }\n }\n }\n }\n }\n }\n return count;\n }\n },\n methods: {\n loadStudents() {\n const self = this;\n self.studentsloading = true;\n call([{\n methodname: 'local_treestudyplan_all_associated_grouped',\n args: {'studyplan_id': this.structure.studyplan.id}\n }])[0].then((response) => {\n self.students = response;\n for (const group of self.students) {\n self.$set(\n self.groupinfo,\n group.id,\n {\n expanded: true,\n }\n );\n\n for (const student of group.users) {\n self.$set(\n self.studentresults,\n student.id,\n {\n loading: true,\n results: [],\n }\n );\n call([{\n methodname: 'local_treestudyplan_get_report_data',\n args: {\n pageid: self.structure.page.id,\n userid: student.id,\n firstperiod: self.structure.firstperiod,\n lastperiod: self.structure.lastperiod,\n }\n }])[0].then((response) => {\n self.studentresults[student.id].loading = false;\n self.studentresults[student.id].results = response;\n return;\n }).catch(notification.exception);\n }\n }\n self.studentsloading = false;\n return;\n }).catch(notification.exception);\n },\n expansionChanged(parm, id, val) {\n if (parm[0] == 'p') {\n parm = 'periods';\n } else if (parm[0] == 'l') {\n parm = 'lines';\n } else {\n parm = 'items';\n }\n\n if (parm == 'lines') {\n this.expansioninfo[parm][id[0]][id[1]].expanded = val;\n } else {\n this.expansioninfo[parm][id].expanded = val;\n }\n },\n groupExpansionChanged(group) {\n this.groupinfo[group.id].expanded = !this.groupinfo[group.id].expanded;\n },\n toggleSort(header) {\n if (this.sorting.header == header) {\n this.sorting.asc = !this.sorting.asc;\n } else {\n this.sorting.header = header;\n this.sorting.asc = true;\n }\n }\n },\n template: `\n <table class='q-studyplanreport'\n :style=\"'--resultColCount: '+resultColCount+';'\">\n <colgroup class=\"q-col-studentinfo\">\n <col class=\"q-name\"></col>\n <col class=\"q-lastaccess\"></col>\n </colgroup>\n <colgroup class=\"q-col-resultinfo\">\n <col v-for=\"n in resultColCount\"></col>\n </colgroup>\n <q-header \n :sorting='sorting' \n :structure='structure'\n :expansion='expansioninfo'\n @expansion='expansionChanged'\n @togglesort=\"toggleSort\"\n ></q-header>\n <template v-if=\"!studentsloading\">\n <template v-for=\"group in sortedstudents\">\n <q-groupheading \n v-if=\"group.users && group.users.length > 0\" \n :group=\"group\"\n :expanded=\"groupinfo[group.id].expanded\"\n @togglegroup=\"groupExpansionChanged\"\n :resultcolumns=\"resultColCount\"\n :studentinfocolumns=\"2\"\n ></q-groupheading>\n <template v-if='groupinfo[group.id].expanded'>\n <q-studentresults v-for=\"(student,idx) in group.users\"\n :key=\"student.id\"\n :student='student'\n :even=\"(idx%2==1)\"\n :structure='structure'\n :results='studentresults[student.id].results'\n :loading='studentresults[student.id].loading'\n :expansion='expansioninfo'\n ></q-studentresults>\n </template>\n </template>\n </template>\n <q-inforow v-else \n :resultcolumns=\"resultColCount\"\n :studentinfocolumns=\"2\"><div class=\"spinner-border spinner-border-sm text-info\" role=\"status\"></div></q-inforow>\n </table>\n `,\n });\n\n Vue.component('q-header', {\n props: {\n structure: {\n type: Object,\n },\n sorting: {\n type: Object,\n },\n expansion: {\n type: Object\n },\n },\n data() {\n return {\n text: strings.header,\n };\n },\n computed: {\n },\n methods: {\n conditions(item) {\n return conditionHeaders(item);\n },\n colspanPeriod(period) {\n const pid = period.period.id;\n if (this.expansion.periods[pid].expanded) {\n let sum = 0;\n for (const l of period.lines) {\n sum += this.colspanLine(period, l);\n }\n return sum;\n } else {\n return 2;\n }\n },\n colspanLine(period, line) {\n const pid = period.period.id;\n const lid = line.line.id;\n\n if (this.expansion.lines[pid][lid].expanded) {\n let sum = 0;\n for (const i of line.items) {\n sum += this.colspanItem(i);\n }\n return sum;\n } else {\n return 1;\n }\n },\n colspanItem(item) {\n if (this.expansion.items[item.id].expanded) {\n const cs = this.conditions(item);\n return 1 + cs.length;\n } else {\n return 1;\n }\n },\n togglePeriod(period, val) {\n if (val === undefined) {\n val = !(this.expansion.periods[period.id].expanded);\n }\n this.$emit('expansion', 'periods', period.id, val);\n },\n toggleLine(period, line, val) {\n if (val === undefined) {\n val = !(this.expansion.lines[period.id][line.id].expanded);\n }\n this.$emit('expansion', 'lines', [period.id, line.id], val);\n },\n toggleItem(item, val) {\n if (val === undefined) {\n val = !(this.expansion.items[item.id].expanded);\n }\n this.$emit('expansion', 'items', item.id, val);\n },\n toggleSort(heading) {\n this.$emit('togglesort', heading);\n }\n },\n /* TODO: https://css-tricks.com/position-sticky-and-table-headers/ */\n template: `\n <thead class='q-header'>\n <tr> <!-- period heading -->\n <th rowspan='4' colspan='2' class='q-studentinfo q-generic'><span>{{text.students}}</span></th>\n <th v-for=\"p in structure.periods\" \n :class=\"'q-period-heading '+ ((expansion.periods[p.period.id].expanded)?'expanded':'collapsed')\"\n :colspan='colspanPeriod(p)'\n :rowspan='(expansion.periods[p.period.id].expanded && p.lines.length > 0)?1:5'\n ><span class=\"q-wrap\"><a v-if='(p.lines.length > 0)' href='#' @click.prevent=\"togglePeriod(p.period)\"\n ><i v-if=\"expansion.periods[p.period.id].expanded\" \n class='q-chevron fa fa-minus'></i\n ><i v-else class='q-chevron fa fa-plus'></i\n >&nbsp;{{ p.period.fullname}}</a\n ><span v-else>{{ p.period.fullname}}</span></span\n ></th>\n </tr>\n <tr> <!-- line heading -->\n <template v-for=\"p in structure.periods\">\n <template v-if=\"expansion.periods[p.period.id].expanded\">\n <th v-for=\"l in p.lines\"\n :class=\"'q-line-heading ' \n + ((expansion.lines[p.period.id][l.line.id].expanded)?'expanded':'collapsed')\"\n :colspan=\"colspanLine(p,l)\"\n :rowspan='(expansion.lines[p.period.id][l.line.id].expanded)?1:4'\n ><span class=\"q-wrap\"><fittext vertical maxsize=\"18pt\"\n ><span class='q-label'\n :title=\"l.line.shortname\"\n v-html=\"l.line.shortname\"\n ></span\n ></fittext></span\n ></th>\n </template>\n </template>\n </tr>\n <tr> <!-- item heading -->\n <template v-for=\"p in structure.periods\"> \n <template v-if=\"expansion.periods[p.period.id].expanded\"> \n <template v-for=\"l in p.lines\">\n <template v-if=\"expansion.lines[p.period.id][l.line.id].expanded\">\n <th v-for=\"item in l.items\"\n :class=\"'q-item-heading ' + ((expansion.items[item.id].expanded)?'expanded':'collapsed')\"\n :colspan=\"colspanItem(item)\"\n :rowspan='(expansion.items[item.id].expanded)?1:3'\n ><a class=\"q-wrap\" href='#' @click.prevent=\"toggleItem(item)\"\n ><div class=\"q-toggle\"\n ><i v-if=\"expansion.items[item.id].expanded\" \n class='q-chevron fa fa-minus'></i\n ><i v-else \n class='q-chevron fa fa-plus'></i\n ></div><div class=\"q-title\"\n ><fittext vertical maxsize=\"12pt\" minsize=\"9pt\"\n ><span class='q-label'\n :title=\"item.course.displayname\" \n v-html=\"item.course.displayname\"\n ></span\n ></fittext\n ></div\n ></div\n ></th>\n </template>\n </template>\n </template>\n </template>\n </tr>\n <tr> <!-- condition heading -->\n <template v-for=\"p in structure.periods\">\n <template v-if=\"expansion.periods[p.period.id].expanded\"> \n <template v-for=\"l in p.lines\">\n <template v-if=\"expansion.lines[p.period.id][l.line.id].expanded\">\n <template v-for=\"item in l.items\">\n <template v-if=\"expansion.items[item.id].expanded\">\n <th class='q-condition-heading overall' rowspan=\"2\"\n ><span class='q-wrap'>{{ text.overall }}</span></th>\n <th v-for=\"c in conditions(item)\" \n rowspan=\"2\"\n class='q-condition-heading'\n ><span class=\"q-wrap\"\n ><fittext vertical maxsize=\"14pt\"><a class='q-label q-condition-label'\n :title=\"c.tooltip\" href=\"#\" @click.prevent\n v-b-tooltip.focus\n v-html=\"c.name\"></a\n ></fittext></span\n ></th>\n </template>\n </template>\n </template>\n </template>\n </template>\n </template>\n </tr>\n <tr> <!-- student info heading -->\n <th class=\"q-studentinfo q-name\">\n <fittext maxsize=\"12pt\"\n ><a href=\"#\" @click.prevent=\"toggleSort('firstname')\">{{text.firstname}}</a\n ><i v-if=\"sorting.header=='firstname' && sorting.asc\" class='fa fa-sort-asc fa-fw'></i\n ><i v-else-if=\"sorting.header=='firstname' && !sorting.asc\" class='fa fa-sort-desc fa-fw'></i>\n / <a href=\"#\" @click.prevent=\"toggleSort('lastname')\">{{text.lastname}}</a\n ><i v-if=\"sorting.header=='lastname' && sorting.asc\" class='fa fa-sort-asc fa-fw'></i\n ><i v-else-if=\"sorting.header=='lastname' && !sorting.asc\" class='fa fa-sort-desc fa-fw'></i\n ></fittext>\n </th>\n <th class=\"q-studentinfo q-email\">\n <fittext maxsize=\"12pt\"\n ><a href=\"#\" @click.prevent=\"toggleSort('lastaccess')\">{{text.lastaccess}}</a\n ><i v-if=\"sorting.header=='lastaccess' && sorting.asc\" class='fa fa-sort-asc fa-fw'></i\n ><i v-else-if=\"sorting.header=='lastaccess' && !sorting.asc\" class='fa fa-sort-desc fa-fw'></i\n ></fittext>\n </th>\n </tr>\n </thead>\n `,\n });\n\n Vue.component('q-groupheading', {\n props: {\n group: {\n type: Object,\n },\n resultcolumns: {\n type: Number,\n 'default': 1\n },\n studentinfocolumns: {\n type: Number,\n 'default': 1\n },\n expanded: {\n type: Boolean,\n }\n },\n data() {\n return {\n\n };\n },\n computed: {\n },\n methods: {\n toggleGroup() {\n this.$emit('togglegroup', this.group);\n }\n },\n template: `\n <tr class='q-groupheading'>\n <th :colspan=\"studentinfocolumns\"><a href=\"#\" @click.prevent=\"toggleGroup\"\n ><i v-if=\"expanded\" class=\"fa fa-minus\"></i\n ><i v-else class=\"fa fa-plus\"></i\n >&nbsp;{{group.label}}</a></th>\n <td :colspan=\"resultcolumns\"></td>\n </tr>\n `,\n });\n\n Vue.component('q-inforow', {\n props: {\n resultcolumns: {\n type: Number,\n 'default': 1\n },\n studentinfocolumns: {\n type: Number,\n 'default': 1\n },\n },\n data() {\n return {\n };\n },\n computed: {\n },\n methods: {\n },\n template: `\n <tr class='q-inforow'>\n <td :colspan=\"studentinfocolumns\"><slot></slot></td>\n <td :colspan=\"resultcolumns\"></td>\n </tr>\n `,\n });\n\n\n Vue.component('q-studentresults', {\n props: {\n student: {\n type: Object,\n },\n structure: {\n type: Object,\n },\n results: {\n type: Array,\n },\n loading: {\n type: Boolean,\n 'default': false\n },\n expansion: {\n type: Object,\n },\n even: {\n type: Boolean,\n 'default': false,\n }\n },\n data() {\n return {\n text: strings.studentresults,\n };\n },\n computed: {\n lastaccess() {\n if (this.student.lastaccess) {\n return formatDatetime(this.student.lastaccess); // Takes date in milliseconds\n } else {\n return this.text.never;\n }\n }\n },\n methods: {\n useritems(line) {\n const list = [];\n for (const item of line.items) {\n let newitm = item;\n for (const itm of this.results) {\n if (item.id == itm.id) {\n newitm = itm;\n break;\n }\n }\n list.push(newitm);\n }\n return list;\n },\n conditions(item) {\n return conditions(item);\n },\n },\n /* https://css-tricks.com/position-sticky-and-table-headers/ */\n template: `\n <tr :class=\"'q-student-results userrow ' + (even?'even':'odd')\">\n <td class='q-studentinfo q-name'><fittext maxsize=\"12pt\">{{student.firstname}} {{student.lastname}}</fittext></td>\n <td class='q-studentinfo q-email'><fittext maxsize=\"12pt\">{{lastaccess}}</fittext></td>\n <template v-for=\"p in structure.periods\">\n <template v-if=\"expansion.periods[p.period.id].expanded && p.lines.length > 0\">\n <template v-for=\"l in p.lines\">\n <template v-if=\"expansion.lines[p.period.id][l.line.id].expanded\">\n <template v-for=\"item in useritems(l)\">\n <td class='q-result overall'\n ><q-courseresult\n :item=\"item\"\n :student=\"student\"\n :loading=\"loading\"\n ></q-courseresult\n ></td>\n <template v-if=\"expansion.items[item.id].expanded\">\n <td v-for=\"(c,idx) in conditions(item)\"\n class='q-result'\n ><q-conditionresult\n :item=\"item\"\n :conditionidx=\"idx\"\n :student=\"student\"\n :loading=\"loading\"\n ></q-conditionresult\n ></td>\n </template>\n </template>\n </template>\n <td v-else class='q-result collapsed'>&nbsp;</td>\n </template>\n </template>\n <td v-else colspan=\"2\" class='q-result collapsed'>&nbsp;</td>\n </template>\n </tr>\n `,\n });\n\n Vue.component('q-courseresult', {\n props: {\n student: {\n type: Object,\n },\n item: {\n type: Object,\n },\n loading: {\n type: Boolean,\n 'default': false\n },\n },\n data() {\n return {\n text: strings.studentresults,\n };\n },\n computed: {\n hasprogressinfo() {\n const course = this.item.course;\n if (!course.enrolled) {\n return false;\n } else {\n return (course.completion || course.competency || course.grades) ? true : false;\n }\n },\n completion_icon() {\n const completion = this.item.completion;\n switch (completion) {\n default: // Case \"incomplete\"\n return \"circle-o\";\n case \"pending\":\n return \"question-circle\";\n case \"failed\":\n return \"times-circle\";\n case \"progress\":\n return \"exclamation-circle\";\n case \"completed\":\n return \"check-circle\";\n case \"good\":\n return \"check-circle\";\n case \"excellent\":\n return \"check-circle\";\n }\n },\n },\n methods: {\n },\n template: `\n <span class='q-courseresult'>\n <template v-if=\"loading\">\n <div class=\"spinner-border spinner-border-sm text-info\" role=\"status\"></div>\n </template>\n <template v-else-if='!item.course.enrolled'>\n <i v-b-popover.top\n class=\"fa fa-exclamation-triangle t-not-enrolled-alert\"\n :title=\"text.student_not_tracked\"></i>\n </template>\n <template v-else-if=\"item.lineenrolled\" >\n <i v-b-popover.top\n :class=\"'fa fa-'+completion_icon+\n ' r-completion-'+item.completion\"\n :title=\"text['completion_'+item.completion]\"></i>\n </template>\n </span>\n `,\n });\n\n Vue.component('q-conditionresult', {\n props: {\n student: {\n type: Object,\n },\n item: {\n type: Object,\n },\n loading: {\n type: Boolean,\n 'default': false\n },\n conditionidx: {\n type: Number,\n }\n },\n data() {\n return {\n text: strings.studentresults,\n };\n },\n computed: {\n conditions() {\n return conditions(this.item);\n },\n condition() {\n if (this.conditionidx >= 0 && this.conditionidx < this.conditions.length) {\n return this.conditions[this.conditionidx];\n } else {\n return null;\n }\n },\n hasprogressinfo() {\n const course = this.item.course;\n if (!course.enrolled) {\n return false;\n } else {\n return (course.completion || course.competency || course.grades);\n }\n },\n completion_icon() {\n const completion = this.condition_completion();\n switch (completion) {\n default: // Case \"incomplete\"\n return \"circle-o\";\n case \"pending\":\n return \"question-circle\";\n case \"failed\":\n return \"times-circle\";\n case \"progress\":\n return \"exclamation-circle\";\n case \"completed\":\n return \"check-circle\";\n case \"good\":\n return \"check-circle\";\n case \"excellent\":\n return \"check-circle\";\n }\n },\n condition_value() {\n const course = this.item.course;\n if (course.competency) {\n if (this.condition.grade) {\n // Return grade if possible.\n return this.condition.grade;\n }\n } else if (course.completion) {\n if (this.condition.grade) {\n // Return grade if possible.\n return this.condition.grade;\n }\n } else if (course.grades) {\n return this.condition.grade;\n }\n // Fallback to completion icon.\n const icon = this.completion_icon();\n return `<i class='fa fa-${icon}'></i>`;\n },\n condition_completion() {\n // Unify completion information\n const course = this.item.course;\n if (course.competency) {\n const competency = this.condition;\n if (competency.proficient && competency.courseproficient) {\n return \"completed\";\n } else if (competency.proficient) {\n return \"completed\";\n } else if (competency.proficient === false) {\n return \"failed\";\n } else if (competency.progress) {\n return \"progress\";\n } else {\n return \"incomplete\";\n }\n } else if (course.completion) {\n return this.condition.status;\n } else if (course.grades) {\n return this.condition.completion;\n } else {\n return \"incomplete\";\n }\n }\n\n },\n methods: {\n },\n template: `\n <span class='q-conditionresult'>\n <fittext v-if=\"item.lineenrolled\" maxsize=\"10pt\" singleline dynamic>\n <template v-if=\"loading\">\n <div class=\"spinner-border spinner-border-sm text-info\" role=\"status\"></div>\n </template>\n <template v-else-if='!item.course.enrolled'>\n <i class=\"fa fa-ellipsis-h\"\n :title=\"text.student_not_tracked\"></i>\n </template>\n <template v-else>\n <span \n :class=\"'r-completion-'+condition_completion\"\n :title=\"text['completion_'+condition_completion]\"\n >{{condition_value}}</span\n >\n </template>\n </fittext>\n </span>\n `,\n });\n },\n};"],"names":["striptags","html","tmp","document","createElement","innerHTML","text","textContent","innerText","remove","conditions","item","course","list","competency","cmp","competencies","push","completion","cnd","itm","items","grades","g","selected","install","Vue","use","TSComponents","FitTextVue","strings","report","loading","studyplan_past","studyplan_present","studyplan_future","back","invalid","error","header","overall","students","firstname","lastname","email","lastaccess","studentresults","completion_incomplete","completion_failed","completion_pending","completion_progress","completion_completed","completion_good","completion_excellent","student_not_tracked","never","component","props","structure","type","Object","data","studentsloading","expansioninfo","periods","lines","groupinfo","sorting","asc","watch","immediate","handler","loadStudents","firstperiod","period","pid","id","this","$set","expanded","length","line","lid","computed","sortedstudents","group","users","sort","a","b","d","e","String","localeCompare","resultColCount","count","methods","self","methodname","args","studyplan","then","response","student","results","pageid","page","userid","lastperiod","catch","notification","exception","expansionChanged","parm","val","groupExpansionChanged","toggleSort","template","expansion","name","details","title","tooltip","description","requirement","typename","conditionHeaders","colspanPeriod","sum","l","colspanLine","i","colspanItem","togglePeriod","undefined","$emit","toggleLine","toggleItem","heading","resultcolumns","Number","studentinfocolumns","Boolean","toggleGroup","Array","even","useritems","newitm","hasprogressinfo","enrolled","completion_icon","conditionidx","condition","condition_completion","condition_value","grade","proficient","courseproficient","progress","status"],"mappings":"qYAoBSA,UAAUC,YACTC,IAAMC,SAASC,cAAc,OACnCF,IAAIG,UAAYJ,WACVK,KAAOJ,IAAIK,aAAeL,IAAIM,iBACpCN,IAAIO,SACGH,cA6CFI,WAAWC,YACVC,OAASD,KAAKC,OACdC,KAAO,MACTD,OAAOE,eACF,MAAMC,OAAOH,OAAOE,WAAWE,aAChCH,KAAKI,KAAKF,UAEX,GAAIH,OAAOM,eACT,MAAMC,OAAOP,OAAOM,WAAWR,eAC3B,MAAMU,OAAOD,IAAIE,MAClBR,KAAKI,KAAKG,UAGf,GAAIR,OAAOU,WACT,MAAMC,KAAKX,OAAOU,OACfC,EAAEC,UACFX,KAAKI,KAAKM,UAIfV,gRAII,CACXY,QAAQC,KACJA,IAAIC,IAAIC,kCACRF,IAAIC,IAAIE,yBAEJC,SAAU,6BAAY,CACtBC,OAAQ,CACJC,QAAS,mBACTC,eAAgB,iBAChBC,kBAAmB,oBACnBC,iBAAkB,mBAClBC,KAAM,QAGVC,QAAS,CACLC,MAAO,SAEXC,OAAQ,CACJC,QAAS,UACTC,SAAU,gBACVC,UAAW,iBACXC,SAAU,gBACVC,MAAO,aACPC,WAAY,mBAEhBC,eAAgB,CACZC,sBAAuB,wBACvBC,kBAAmB,oBACnBC,mBAAoB,qBACpBC,oBAAqB,sBACrBC,qBAAsB,uBACtBC,gBAAiB,kBACjBC,qBAAsB,uBACtBC,oBAAqB,sBACrBC,MAAO,gBAUf7B,IAAI8B,UAAU,oBAAqB,CAC/BC,MAAO,CACHC,UAAW,CACPC,KAAMC,SAGdC,KAAI,KACO,CACHpB,SAAU,GACVK,eAAgB,GAChBgB,iBAAiB,EACjBC,cAAe,CACXC,QAAS,GACTC,MAAO,GACP5C,MAAO,IAEX6C,UAAW,GAEXC,QAAS,CACL5B,OAAQ,WACR6B,KAAK,KAIjBC,MAAO,CACHX,UAAW,CACPY,WAAW,EACXC,QAAQb,gBACCc,mBAEDC,aAAc,MACb,MAAMC,UAAUhB,UAAUM,QAAS,OAC9BW,IAAMD,OAAOA,OAAOE,GACrBC,KAAKd,cAAcC,QAAQW,YAEvBG,KACDD,KAAKd,cAAcC,QACnBW,IACA,CACII,YAAYN,aAAeC,OAAOT,MAAMe,OAAS,UAGpDF,KACDD,KAAKd,cAAcE,MACnBS,OAAOA,OAAOE,GACd,SAGH,MAAMK,QAAQP,OAAOT,MAAO,OACvBiB,IAAMD,KAAKA,KAAKL,GACjBC,KAAKd,cAAcE,MAAMiB,WAErBJ,KACDD,KAAKd,cAAcE,MAAMU,KACzBO,IACA,CACIH,UAAU,QAIjB,MAAMpE,QAAQsE,KAAK5D,MACfwD,KAAKd,cAAc1C,MAAMV,KAAKiE,UAE1BE,KACDD,KAAKd,cAAc1C,MACnBV,KAAKiE,GACL,CACAG,UAAU,IAM1BN,aAAc,MAK9BU,SAAU,CACNC,uBAEU3C,SAAWoC,KAAKpC,aACjB,MAAM4C,SAASR,KAAKpC,SACrB4C,MAAMC,MAAMC,MAAK,CAACC,EAAGC,SACbC,EAAIF,EACJG,EAAIF,KACHZ,KAAKV,QAAQC,MACdsB,EAAID,EACJE,EAAIH,GAEmB,cAAvBX,KAAKV,QAAQ5B,OAAwB,QACrBmD,EAAEb,KAAKV,QAAQ5B,QAAUmD,EAAEb,KAAKV,QAAQ5B,QAAU,IAClDoD,EAAEd,KAAKV,QAAQ5B,QAAUoD,EAAEd,KAAKV,QAAQ5B,QAAU,UAG3DqD,OAAOF,EAAEb,KAAKV,QAAQ5B,SAASsD,cAAcD,OAAOD,EAAEd,KAAKV,QAAQ5B,oBAI/EE,UAEXqD,qBACQC,MAAQ,MACP,MAAMrB,UAAUG,KAAKnB,UAAUM,QAAS,OACnCW,IAAMD,OAAOA,OAAOE,MACrBC,KAAKd,cAAcC,QAAQW,KAAKI,aAI5B,MAAME,QAAQP,OAAOT,MAAO,OACvBiB,IAAMD,KAAKA,KAAKL,MACjBC,KAAKd,cAAcE,MAAMU,KAAKO,KAAKH,aAG/B,MAAMpE,QAAQsE,KAAK5D,MACfwD,KAAKd,cAAc1C,MAAMV,KAAKiE,IAAIG,SAGnCgB,OAAS,EAAIrF,WAAWC,MAAMqE,OAF9Be,OAAS,OAJjBA,OAAS,OALjBA,OAAS,SAkBVA,QAGfC,QAAS,CACLxB,qBACUyB,KAAOpB,KACboB,KAAKnC,iBAAkB,iBAClB,CAAC,CACFoC,WAAY,6CACZC,KAAM,cAAiBtB,KAAKnB,UAAU0C,UAAUxB,OAChD,GAAGyB,MAAMC,WACTL,KAAKxD,SAAW6D,aACX,MAAMjB,SAASY,KAAKxD,SAAU,CAC/BwD,KAAKnB,KACDmB,KAAK/B,UACLmB,MAAMT,GACN,CACEG,UAAU,QAIX,MAAMwB,WAAWlB,MAAMC,MACxBW,KAAKnB,KACDmB,KAAKnD,eACLyD,QAAQ3B,GACR,CACI5C,SAAS,EACTwE,QAAS,oBAGZ,CAAC,CACFN,WAAY,sCACZC,KAAM,CACFM,OAAQR,KAAKvC,UAAUgD,KAAK9B,GAC5B+B,OAAQJ,QAAQ3B,GAChBH,YAAawB,KAAKvC,UAAUe,YAC5BmC,WAAYX,KAAKvC,UAAUkD,eAE/B,GAAGP,MAAMC,WACTL,KAAKnD,eAAeyD,QAAQ3B,IAAI5C,SAAU,EAC1CiE,KAAKnD,eAAeyD,QAAQ3B,IAAI4B,QAAUF,YAE3CO,MAAMC,sBAAaC,WAG9Bd,KAAKnC,iBAAkB,KAExB+C,MAAMC,sBAAaC,YAE1BC,iBAAiBC,KAAMrC,GAAIsC,KASX,UAPRD,KADW,KAAXA,KAAK,GACE,UACW,KAAXA,KAAK,GACL,QAEA,cAIFlD,cAAckD,MAAMrC,GAAG,IAAIA,GAAG,IAAIG,SAAWmC,SAE7CnD,cAAckD,MAAMrC,IAAIG,SAAWmC,KAGhDC,sBAAsB9B,YACbnB,UAAUmB,MAAMT,IAAIG,UAAYF,KAAKX,UAAUmB,MAAMT,IAAIG,UAElEqC,WAAW7E,QACHsC,KAAKV,QAAQ5B,QAAUA,YAClB4B,QAAQC,KAAOS,KAAKV,QAAQC,UAE5BD,QAAQ5B,OAASA,YACjB4B,QAAQC,KAAM,KAI/BiD,SAAW,wxEA+Cf3F,IAAI8B,UAAU,WAAY,CACtBC,MAAO,CACHC,UAAW,CACPC,KAAMC,QAEVO,QAAS,CACLR,KAAMC,QAEV0D,UAAW,CACP3D,KAAMC,SAGdC,KAAI,KACO,CACHvD,KAAMwB,QAAQS,SAGtB4C,SAAU,GAEVa,QAAS,CACLtF,WAAWC,eArXDA,YAChBC,OAASD,KAAKC,OACdC,KAAO,MACTD,OAAOE,eACF,MAAMC,OAAOH,OAAOE,WAAWE,aAChCH,KAAKI,KAAK,CACNsG,KAAOxG,IAAIyG,QAAY,GAAEzG,IAAI0G,WAAW1G,IAAIyG,UAAazG,IAAI0G,MAC7DC,QAAS3G,IAAI4G,mBAGlB,GAAI/G,OAAOM,eACT,MAAMC,OAAOP,OAAOM,WAAWR,eAC3B,MAAMU,OAAOD,IAAIE,MAClBR,KAAKI,KAAK,CACNsG,KAAMnG,IAAIqG,MACVC,QAAU,GAAEtG,IAAIoG,QAAQ7D,SAASvC,IAAIoG,QAAQI,qBAItD,GAAIhH,OAAOU,WACT,MAAMC,KAAKX,OAAOU,OACfC,EAAEC,UACFX,KAAKI,KAAK,CACNsG,KAAMhG,EAAEgG,KACRG,QAAU,GAAEnG,EAAEsG,aAAa7H,UAAUuB,EAAEgG,iBAKhD1G,KAyVgBiH,CAAiBnH,MAE5BoH,cAAcrD,cACJC,IAAMD,OAAOA,OAAOE,MACtBC,KAAKyC,UAAUtD,QAAQW,KAAKI,SAAU,KAClCiD,IAAM,MACL,MAAMC,KAAKvD,OAAOT,MACnB+D,KAAOnD,KAAKqD,YAAYxD,OAAQuD,UAE7BD,WAEA,GAGfE,YAAYxD,OAAQO,YACVN,IAAMD,OAAOA,OAAOE,GACpBM,IAAMD,KAAKA,KAAKL,MAElBC,KAAKyC,UAAUrD,MAAMU,KAAKO,KAAKH,SAAU,KACrCiD,IAAM,MACL,MAAMG,KAAKlD,KAAK5D,MACjB2G,KAAOnD,KAAKuD,YAAYD,UAErBH,WAEA,GAGfI,YAAYzH,SACJkE,KAAKyC,UAAUjG,MAAMV,KAAKiE,IAAIG,SAAU,QAEjC,EADIF,KAAKnE,WAAWC,MACbqE,cAEP,GAGfqD,aAAa3D,OAAQwC,UACLoB,IAARpB,MACAA,KAAQrC,KAAKyC,UAAUtD,QAAQU,OAAOE,IAAIG,eAEzCwD,MAAM,YAAa,UAAW7D,OAAOE,GAAIsC,MAElDsB,WAAW9D,OAAQO,KAAMiC,UACToB,IAARpB,MACAA,KAAQrC,KAAKyC,UAAUrD,MAAMS,OAAOE,IAAIK,KAAKL,IAAIG,eAEhDwD,MAAM,YAAa,QAAS,CAAC7D,OAAOE,GAAIK,KAAKL,IAAKsC,MAE3DuB,WAAW9H,KAAMuG,UACDoB,IAARpB,MACAA,KAAQrC,KAAKyC,UAAUjG,MAAMV,KAAKiE,IAAIG,eAErCwD,MAAM,YAAa,QAAS5H,KAAKiE,GAAIsC,MAE9CE,WAAWsB,cACFH,MAAM,aAAcG,WAIjCrB,SAAW,s/OAiHf3F,IAAI8B,UAAU,iBAAkB,CAC5BC,MAAO,CACH4B,MAAO,CACH1B,KAAMC,QAEV+E,cAAe,CACXhF,KAAMiF,eACK,GAEfC,mBAAoB,CAChBlF,KAAMiF,eACK,GAEf7D,SAAU,CACNpB,KAAMmF,UAGdjF,KAAI,KACO,IAIXsB,SAAU,GAEVa,QAAS,CACL+C,mBACSR,MAAM,cAAe1D,KAAKQ,SAGvCgC,SAAW,8YAWf3F,IAAI8B,UAAU,YAAa,CACvBC,MAAO,CACHkF,cAAe,CACXhF,KAAMiF,eACK,GAEfC,mBAAoB,CAChBlF,KAAMiF,eACK,IAGnB/E,KAAI,KACO,IAGXsB,SAAU,GAEVa,QAAS,GAETqB,SAAW,sMASf3F,IAAI8B,UAAU,mBAAoB,CAC9BC,MAAO,CACH8C,QAAS,CACL5C,KAAMC,QAEVF,UAAW,CACPC,KAAMC,QAEV4C,QAAS,CACL7C,KAAMqF,OAEVhH,QAAS,CACL2B,KAAMmF,iBACK,GAEfxB,UAAW,CACP3D,KAAMC,QAEVqF,KAAM,CACFtF,KAAMmF,iBACK,IAGnBjF,KAAI,KACO,CACHvD,KAAMwB,QAAQgB,iBAGtBqC,SAAU,CACNtC,oBACQgC,KAAK0B,QAAQ1D,YACN,8BAAegC,KAAK0B,QAAQ1D,YAE5BgC,KAAKvE,KAAKiD,QAI7ByC,QAAS,CACLkD,UAAUjE,YACApE,KAAO,OACR,MAAMF,QAAQsE,KAAK5D,MAAO,KACvB8H,OAASxI,SACR,MAAMS,OAAOyD,KAAK2B,WACf7F,KAAKiE,IAAMxD,IAAIwD,GAAI,CACnBuE,OAAS/H,UAIjBP,KAAKI,KAAKkI,eAEPtI,MAEXH,WAAWC,MACAD,WAAWC,OAI1B0G,SAAW,osEAsCf3F,IAAI8B,UAAU,iBAAkB,CAC5BC,MAAO,CACH8C,QAAS,CACL5C,KAAMC,QAEVjD,KAAM,CACFgD,KAAMC,QAEV5B,QAAS,CACL2B,KAAMmF,iBACK,IAGnBjF,KAAI,KACO,CACHvD,KAAMwB,QAAQgB,iBAGtBqC,SAAU,CACNiE,wBACUxI,OAASiE,KAAKlE,KAAKC,eACpBA,OAAOyI,aAGAzI,OAAOM,YAAcN,OAAOE,YAAcF,OAAOU,SAGjEgI,yBACuBzE,KAAKlE,KAAKO,0BAGd,eACN,gBACM,sBACN,eACM,mBACN,iBACM,yBACN,gBAEA,WAEA,kBACM,kBAIvB8E,QAAS,GAETqB,SAAW,o2BAoBf3F,IAAI8B,UAAU,oBAAqB,CAC/BC,MAAO,CACH8C,QAAS,CACL5C,KAAMC,QAEVjD,KAAM,CACFgD,KAAMC,QAEV5B,QAAS,CACL2B,KAAMmF,iBACK,GAEfS,aAAc,CACV5F,KAAMiF,SAGd/E,KAAI,KACO,CACHvD,KAAMwB,QAAQgB,iBAGtBqC,SAAU,CACNzE,oBACWA,WAAWmE,KAAKlE,OAE3B6I,mBACQ3E,KAAK0E,cAAgB,GAAK1E,KAAK0E,aAAe1E,KAAKnE,WAAWsE,OACvDH,KAAKnE,WAAWmE,KAAK0E,cAErB,MAGfH,wBACUxI,OAASiE,KAAKlE,KAAKC,eACpBA,OAAOyI,WAGAzI,OAAOM,YAAcN,OAAOE,YAAcF,OAAOU,SAGjEgI,yBACuBzE,KAAK4E,sCAGT,eACN,gBACM,sBACN,eACM,mBACN,iBACM,yBACN,gBAEA,WAEA,kBACM,iBAGnBC,wBACU9I,OAASiE,KAAKlE,KAAKC,UACrBA,OAAOE,eACH+D,KAAK2E,UAAUG,aAER9E,KAAK2E,UAAUG,WAEvB,GAAI/I,OAAOM,eACV2D,KAAK2E,UAAUG,aAER9E,KAAK2E,UAAUG,WAEvB,GAAI/I,OAAOU,cACPuD,KAAK2E,UAAUG,YAIlB,mBADK9E,KAAKyE,2BAGtBG,6BAEU7I,OAASiE,KAAKlE,KAAKC,UACrBA,OAAOE,WAAY,OACbA,WAAa+D,KAAK2E,iBACpB1I,WAAW8I,YAAc9I,WAAW+I,kBAE7B/I,WAAW8I,WADX,aAG0B,IAA1B9I,WAAW8I,WACX,SACA9I,WAAWgJ,SACX,WAEA,aAER,OAAIlJ,OAAOM,WACP2D,KAAK2E,UAAUO,OACfnJ,OAAOU,OACPuD,KAAK2E,UAAUtI,WAEf,eAKnB8E,QAAS,GAETqB,SAAW"}