moodle_local_treestudyplan/amd/build/studyplan-editor-components.min.js.map
2024-08-30 12:42:52 +02:00

1 line
265 KiB
Plaintext

{"version":3,"file":"studyplan-editor-components.min.js","sources":["../src/studyplan-editor-components.js"],"sourcesContent":["/* eslint no-var: \"error\"*/\n/* eslint no-console: \"off\"*/\n/* eslint no-unused-vars: warn */\n/* eslint max-len: [\"error\", { \"code\": 160 }] */\n/* eslint promise/no-nesting: \"off\" */\n/* eslint no-trailing-spaces: warn */\n/* eslint max-depth: [\"error\", 6] */\n/* eslint-env es6*/\n\nimport {SimpleLine} from \"./simpleline/simpleline\";\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\nimport {loadStringKeys, loadStrings, strformat} from './util/string-helper';\nimport {formatDate, addDays, datespaninfo} from './util/date-helper';\nimport {objCopy, transportItem} from './studyplan-processor';\nimport Debugger from './util/debugger';\nimport Config from 'core/config';\nimport {download, upload} from './downloader';\nimport {processStudyplan, processStudyplanPage} from './studyplan-processor';\nimport FitTextVue from './util/fittext-vue';\nimport {settings} from \"./util/settings\";\nimport TSComponents from './treestudyplan-components';\nimport mFormComponents from \"./util/mform-helper\";\nimport pSideBarComponents from \"./util/psidebar-vue\";\n\nimport {Drag, Drop, DropList} from './vue-easy-dnd/vue-easy-dnd.esm';\n\nconst STUDYPLAN_EDITOR_FIELDS =\n['name', 'shortname', 'description', 'idnumber', 'context_id', 'aggregation', 'aggregation_config'];\nconst PERIOD_EDITOR_FIELDS =\n['fullname', 'shortname', 'startdate', 'enddate'];\n\nconst LINE_GRAVITY = 1.3;\n\nexport default {\n install(Vue/* ,options */) {\n Vue.component('drag', Drag);\n Vue.component('drop', Drop);\n Vue.component('drop-list', DropList);\n Vue.use(TSComponents);\n Vue.use(mFormComponents);\n Vue.use(pSideBarComponents);\n Vue.use(FitTextVue);\n let debug = new Debugger(\"treestudyplan-editor\");\n /* **********************************\n * *\n * Treestudyplan Editor components *\n * *\n * **********************************/\n\n /**\n * Check if element is visible\n * @param {Object} elem The element to check\n * @returns {boolean} True if visible\n */\n function isVisible(elem) {\n return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);\n }\n\n // Create new eventbus for interaction between item components\n const ItemEventBus = new Vue();\n\n /*\n // Add event listener for the edit mode event so we can react to it, or at the very least ignore it\n document.addEventListener(editSwEventTypes.editModeSet,(e) => {\n e.preventDefault();\n ItemEventBus.$emit('editModeSet', e.detail.editMode);\n });\n */\n\n let stringKeys = loadStringKeys({\n conditions: [\n {value: 'ALL', textkey: 'condition_all'},\n {value: 'ANY', textkey: 'condition_any'},\n ],\n });\n\n let strings = loadStrings({\n studyplanText: {\n 'studyline_editmode': 'studyline_editmode',\n 'toolbox_toggle': 'toolbox_toggle',\n 'editmode_modules_hidden': 'editmode_modules_hidden',\n 'studyline_add': 'studyline_add',\n add: 'add@core',\n edit: 'edit@core',\n 'delete': \"delete@core\",\n 'studyline_name': 'studyline_name',\n 'studyline_name_ph': 'studyline_name_ph',\n 'studyline_shortname': 'studyline_shortname',\n 'studyline_shortname_ph': 'studyline_shortname_ph',\n 'studyline_enrollable': 'studyline_enrollable',\n 'studyline_enrolroles': 'studyline_enrolroles',\n 'studyline_color': 'studyline_color',\n associations: 'associations',\n 'associated_cohorts': 'associated_cohorts',\n 'associated_users': 'associated_users',\n 'studyline_edit': 'studyline_edit',\n 'studyplan_name': 'studyplan_name',\n 'studyplan_name_ph': 'studyplan_name_ph',\n 'studyplan_shortname': 'studyplan_shortname',\n 'studyplan_shortname_ph': 'studyplan_shortname_ph',\n 'studyplan_description': 'studyplan_description',\n 'studyplan_description_ph': 'studyplan_description_ph',\n 'studyplan_idnumber': 'studyplan_idnumber',\n 'studyplan_idnumber_ph': 'studyplan_idnumber_ph',\n 'studyplan_slots': 'studyplan_slots',\n 'studyplan_startdate': 'studyplan_startdate',\n 'studyplan_enddate': 'studyplan_enddate',\n 'line_enrollable_0': 'line_enrollable:0',\n 'line_enrollable_1': 'line_enrollable:1',\n 'line_enrollable_2': 'line_enrollable:2',\n 'line_enrollable_3': 'line_enrollable:3',\n drophere: 'drophere',\n studylineConfirmRemove: 'studyline_confirm_remove',\n studyplanConfirmRemove: 'studyplan_confirm_remove',\n\n },\n studyplanAdvanced: {\n 'advanced_tools': 'advanced_tools',\n 'confirm_cancel': 'confirm_cancel',\n 'confirm_ok': 'confirm_ok',\n success: 'success@core',\n error: 'failed@completion',\n 'advanced_converted': 'advanced_converted',\n 'advanced_skipped': 'advanced_skipped',\n 'advanced_failed': 'advanced_failed',\n 'advanced_locked': 'advanced_locked',\n 'advanced_multiple': 'advanced_multiple',\n 'advanced_error': 'advanced_error',\n 'advanced_tools_heading': 'advanced_tools_heading',\n 'advanced_warning_title': 'advanced_warning_title',\n 'advanced_warning': 'advanced_warning',\n 'advanced_pick_scale': 'advanced_pick_scale',\n 'advanced_course_manipulation_title': 'advanced_course_manipulation_title',\n 'advanced_bulk_course_timing': 'advanced_bulk_course_timing',\n 'advanced_bulk_course_timing_desc': 'advanced_bulk_course_timing_desc',\n 'advanced_force_scale_title': 'advanced_force_scale_title',\n 'advanced_force_scale_desc': 'advanced_force_scale_desc',\n 'advanced_force_scale_button': 'advanced_force_scale_button',\n 'advanced_confirm_header': 'advanced_confirm_header',\n 'advanced_force_scale_confirm': 'advanced_force_scale_confirm',\n 'advanced_backup_restore': 'advanced_backup_restore',\n 'advanced_restore': 'advanced_restore',\n 'advanced_backup': 'advanced_backup',\n 'advanced_restore_pages': 'advanced_restore_pages',\n 'advanced_restore_lines': 'advanced_restore_lines',\n 'advanced_backup_plan': 'advanced_backup_plan',\n 'advanced_backup_page': 'advanced_backup_page',\n 'advanced_export': 'advanced_export',\n 'advanced_export_csv_plan': 'advanced_export_csv_plan',\n 'advanced_export_csv_page': 'advanced_export_csv_page',\n 'advanced_import_from_file': 'advanced_import_from_file',\n 'advanced_purge': \"advanced_purge\",\n 'advanced_purge_plan': \"advanced_purge_plan\",\n 'advanced_purge_plan_expl': \"advanced_purge_plan_expl\",\n 'advanced_purge_page': \"advanced_purge_page\",\n 'advanced_purge_page_expl': \"advanced_purge_page_expl\",\n 'advanced_cascade_cohortsync_title': \"advanced_cascade_cohortsync_title\",\n 'advanced_cascade_cohortsync_desc': \"advanced_cascade_cohortsync_desc\",\n 'advanced_cascade_cohortsync': \"advanced_cascade_cohortsync\",\n currentpage: \"currentpage\",\n },\n studyplanEdit: {\n studyplanEdit: 'studyplan_edit',\n 'studyplan_add': 'studyplan_add',\n 'studyplanpage_add': 'studyplanpage_add',\n 'studyplanpage_edit': 'studyplanpage_edit',\n 'info_periodsextended': 'studyplanpage_info_periodsextended',\n warning: 'warning@core',\n },\n periodEdit: {\n edit: 'period_edit',\n fullname: 'studyplan_name',\n shortname: 'studyplan_shortname',\n startdate: 'studyplan_startdate',\n enddate: 'studyplan_enddate',\n },\n courseTiming: {\n title: 'course_timing_title',\n desc: 'course_timing_desc',\n question: 'course_timing_question',\n warning: 'course_timing_warning',\n 'timing_ok': 'course_timing_ok',\n 'timing_off': 'course_timing_off',\n course: 'course@core',\n period: 'period',\n yes: 'yes$core',\n no: 'no$core',\n duration: 'duration',\n years: 'years$core',\n year: 'year$core',\n weeks: 'weeks$core',\n week: 'week$core',\n days: 'days$core',\n day: 'day$core',\n rememberchoice: 'course_timing_rememberchoice',\n hidewarning: 'course_timing_hidewarning',\n periodspan: 'course_period_span',\n periods: 'periods',\n 'periodspan_desc': 'course_period_span_desc',\n },\n studyplanAssociate: {\n 'associations': 'associations',\n 'associated_cohorts': 'associated_cohorts',\n 'associated_users': 'associated_users',\n 'associated_coaches': 'associated_coaches',\n 'associate_cohorts': 'associate_cohorts',\n 'associate_users': 'associate_users',\n 'associate_coached': 'associate_coaches',\n 'add_association': 'add_association',\n 'delete_association': 'delete_association',\n 'associations_empty': 'associations_empty',\n 'associations_search': 'associations_search',\n cohorts: 'cohorts',\n users: 'users',\n coaches: 'coaches',\n selected: 'selected',\n name: 'name',\n context: 'context',\n search: 'search',\n },\n itemText: {\n 'select_conditions': \"select_conditions\",\n 'item_configuration': \"item_configuration\",\n ok: \"ok@core\",\n 'delete': \"delete@core\",\n 'item_delete_message': \"item_delete_message\",\n 'type_course': \"course@core\",\n 'type_junction': \"tool-junction\",\n 'type_start': \"tool-start\",\n 'type_finish': \"tool-finish\",\n 'type_badge': \"tool-badge\",\n 'type_invalid': \"course-invalid\",\n },\n itemCourseText: {\n 'select_conditions': \"select_conditions\",\n 'select_grades': \"select_grades\",\n 'coursetiming_past': \"coursetiming_past\",\n 'coursetiming_present': \"coursetiming_present\",\n 'coursetiming_future': \"coursetiming_future\",\n 'grade_include': \"grade_include\",\n 'grade_require': \"grade_require\",\n ok: \"ok@core\",\n cancel: \"cancel@core\",\n 'delete': \"delete@core\",\n noenddate: \"noenddate\",\n },\n invalid: {\n error: 'error',\n },\n completion: {\n 'completion_completed': \"completion_completed\",\n 'completion_incomplete': \"completion_incomplete\",\n 'aggregation_all': \"aggregation_all\",\n 'aggregation_any': \"aggregation_any\",\n 'aggregation_overall_all': \"aggregation_overall_all\",\n 'aggregation_overall_any': \"aggregation_overall_any\",\n 'completion_not_configured': \"completion_not_configured\",\n 'configure_completion': \"configure_completion\",\n },\n competency: {\n 'competency_not_configured': \"competency_not_configured\",\n 'configure_competency': \"configure_competency\",\n when: \"when\",\n required: \"required\",\n points: \"points@core_grades\",\n heading: \"competency_heading\",\n details: \"competency_details\",\n },\n badge: {\n 'share_badge': \"share_badge\",\n dateissued: \"dateissued\",\n dateexpire: \"dateexpire\",\n badgeinfo: \"badgeinfo\",\n },\n toolbox: {\n toolbox: 'toolbox',\n toolbarRight: 'toolbar-right',\n courses: 'courses',\n flow: 'flow',\n toolJunction: 'tool-junction',\n toolFinish: 'tool-finish',\n toolStart: 'tool-start',\n badges: 'badges',\n relatedbadges: 'relatedbages@badges', /* [sic] as in badges translation file */\n filter: 'filter@core',\n sitebadges: 'sitebadges@badges',\n }\n });\n\n /*\n * T-STUDYPLAN-ADVANCED\n */\n Vue.component('t-studyplan-advanced', {\n props: {\n value: {\n type: Object,\n default() {\n return null;\n },\n },\n selectedpage: {\n type: Object,\n default() {\n return null;\n },\n }\n\n },\n data() {\n return {\n forceScales: {\n selectedScale: null,\n result: [],\n },\n text: strings.studyplanAdvanced,\n };\n },\n computed: {\n scales() {\n return [{\n id: null,\n disabled: true,\n name: this.text.advanced_pick_scale,\n }].concat(this.value.advanced.force_scales.scales);\n },\n },\n methods: {\n forceScalesStart() {\n // Set confirmation box\n const self = this;\n this.$bvModal.msgBoxConfirm(this.text.advanced_force_scale_confirm, {\n title: this.text.advanced_force_scale_confirm,\n okVariant: 'danger',\n okTitle: this.text.confirm_ok,\n cancelTitle: this.text.confirm_cancel,\n }).then(value => {\n if (value == true) {\n call([{\n methodname: 'local_treestudyplan_force_studyplan_scale',\n args: {\n 'studyplan_id': this.value.id,\n 'scale_id': this.forceScales.selectedScale,\n }\n }])[0].then((response) => {\n self.forceScales.result = response;\n return;\n }).catch(notification.exception);\n }\n return;\n }).catch(notification.exception);\n },\n exportPage(format) {\n const self = this;\n if (format == undefined || ![\"json\", \"csv\"].includes(format)) {\n format = \"json\";\n }\n call([{\n methodname: 'local_treestudyplan_export_page',\n args: {\n 'page_id': this.selectedpage.id,\n format: format,\n },\n }])[0].then((response) => {\n download(self.value.shortname + \".page.\" + format, response.content, response.format);\n return;\n }).catch(notification.exception);\n },\n exportPlan() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_export_plan',\n args: {\n 'studyplan_id': this.value.id,\n format: \"json\",\n },\n }])[0].then((response) => {\n download(self.value.shortname + \".plan.json\", response.content, response.format);\n return;\n }).catch(notification.exception);\n },\n bulkCourseTiming() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_bulk_course_timing',\n args: {\n 'page_id': this.selectedpage.id,\n },\n }])[0].then((response) => {\n if (response.success) {\n // Reloading the webpage saves trouble reloading the specific page updated.\n location.reload();\n } else {\n self.$bvModal.msgBoxOk(response.msg, {title: \"Could not set bulk course timing\"});\n debug.error(\"Could not set bulk course timing: \", response.msg);\n }\n return;\n }).catch(notification.exception);\n },\n importStudylines() {\n const self = this;\n upload((filename, content)=>{\n call([{\n methodname: 'local_treestudyplan_import_studylines',\n args: {\n 'page_id': this.selectedpage.id,\n content: content,\n format: \"application/json\",\n },\n }])[0].then((response) => {\n if (response.success) {\n location.reload();\n } else {\n self.$bvModal.msgBoxOk(response.msg, {title: \"Import failed\"});\n debug.error(\"Import failed: \", response.msg);\n }\n return;\n }).catch(notification.exception);\n }, \"application/json\");\n },\n importPages() {\n const self = this;\n upload((filename, content)=>{\n call([{\n methodname: 'local_treestudyplan_import_pages',\n args: {\n 'studyplan_id': this.value.id,\n content: content,\n format: \"application/json\",\n },\n }])[0].then((response) => {\n if (response.success) {\n location.reload();\n } else {\n self.$bvModal.msgBoxOk(response.msg, {title: \"Import failed\"});\n debug.error(\"Import failed: \", response.msg);\n }\n return;\n }).catch(notification.exception);\n }, \"application/json\");\n },\n purgeStudyplan() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_delete_studyplan',\n args: {\n id: this.value.id,\n force: true,\n },\n }])[0].then((response) => {\n if (response.success) {\n location.reload();\n } else {\n self.$bvModal.msgBoxOk(response.msg, {title: \"Could not delete plan \"});\n debug.error(\"Could not delete plan: \", response.msg);\n }\n return;\n }).catch(notification.exception);\n },\n purgeStudyplanpage() {\n const self = this;\n if (this.selectedpage) {\n call([{\n methodname: 'local_treestudyplan_delete_studyplanpage',\n args: {\n id: this.selectedpage.id,\n force: true,\n },\n }])[0].then((response) => {\n if (response.success) {\n location.reload();\n } else {\n self.$bvModal.msgBoxOk(response.msg, {title: \"Could not delete page\"});\n debug.error(\"Could not delete page: \", response.msg);\n }\n return;\n }).catch(notification.exception);\n }\n },\n cascadeCohortsync() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_cascade_cohortsync',\n args: {\n 'studyplan_id': this.value.id,\n },\n }])[0].then((response) => {\n self.$bvModal.msgBoxOk(response.success ? self.text.success : self.text.error,\n {title: self.text.advanced_cascade_cohortsync});\n return;\n }).catch(notification.exception);\n },\n modalClose() {\n this.forceScales.result = [];\n }\n },\n template:\n `\n <span>\n <a v-if=\"value.advanced\"\n href='#'\n @click.prevent=''\n class='text-danger'\n v-b-modal=\"'t-studyplan-'+value.id+'-advanced'\"\n ><i class='fa fa-wrench'></i> {{text.advanced_tools}}</a>\n <b-modal v-if=\"value.advanced\"\n :id=\"'t-studyplan-'+value.id+'-advanced'\"\n size=\"lg\"\n :title=\"text.advanced_tools_heading\"\n ok-only\n @hide=\"modalClose\"\n body-class=\"p-0\"\n >\n <b-tabs card>\n <b-tab :title=\"text.advanced_warning_title\" active>\n {{ text.advanced_warning}}\n </b-tab>\n <b-tab :title=\"text.advanced_course_manipulation_title\" >\n <h3>{{ text.advanced_cascade_cohortsync_title}}</h3>\n <p>{{ text.advanced_cascade_cohortsync_desc}}</p>\n <p class=\"mt-2\"><b-button\n variant=\"info\"\n @click.prevent=\"cascadeCohortsync\"\n >{{ text.advanced_cascade_cohortsync}}</b-button></p>\n <h3>{{ text.advanced_bulk_course_timing}}</h3>\n <p>{{ text.advanced_bulk_course_timing_desc}}</p>\n <p>{{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>\n <p class=\"mt-2\"><b-button\n variant=\"info\"\n @click.prevent=\"bulkCourseTiming\"\n >{{ text.advanced_bulk_course_timing}}</b-button></p>\n <template v-if=\"['bistate','tristate'].includes(value.aggregation)\">\n <h3>{{ text.advanced_force_scale_title}}</h3>\n {{ text.advanced_force_scale_desc}}\n <p class=\"mt-2\"><b-form-select v-model=\"forceScales.selectedScale\"\n :options=\"scales\" text-field=\"name\" value-field=\"id\"\n ></b-form-select>\n <b-button\n variant=\"danger\"\n :disabled=\"forceScales.selectedScale == null\"\n @click.prevent=\"forceScalesStart\"\n >{{ text.advanced_force_scale_button}}</b-button>\n </p>\n <p class=\"mt-2\">\n <ul class='t-advanced-scrollable' v-if=\"forceScales.result.length > 0\">\n <li v-for=\"c in forceScales.result\">\n <span class='t-advanced-coursename'>{{c.course.fullname}}</span>\n <ul v-if=\"c.grades.length > 0\">\n <li v-for='g in c.grades'\n ><span class='t-advanced-gradename'><span v-html=\"g.name\"></span></span>\n <span v-if=\"g.changed == 'converted'\" class='t-advanced-status changed'\n >{{text.advanced_converted}}</span\n ><span v-else-if=\"g.changed == 'skipped'\" class='t-advanced-status skipped'\n >{{text.advanced_skipped}}</span\n ><span v-else class='t-advanced-status skipped'\n >{{text.advanced_error}}</span\n ></li>\n </ul>\n </li>\n </ul>\n </p>\n </template>\n </b-tab>\n <b-tab :title='text.advanced_backup_restore'>\n <h3>{{ text.advanced_backup }}</h3>\n <p><b-button\n variant=\"primary\"\n @click.prevent=\"exportPage('json')\"\n >{{ text.advanced_backup_page }}</b-button>\n {{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>\n <p><b-button\n variant=\"primary\"\n @click.prevent=\"exportPlan('json')\"\n >{{ text.advanced_backup_plan }}</b-button></p>\n <h3>{{ text.advanced_restore }}</h3>\n <p><b-button\n variant=\"danger\"\n @click.prevent=\"importStudylines\"\n >{{ text.advanced_restore_lines}}</b-button></p>\n <p><b-button\n variant=\"danger\"\n @click.prevent=\"importPages\"\n >{{ text.advanced_restore_pages }}</b-button></p>\n <h3>{{ text.advanced_export }}</h3>\n <p><b-button\n variant=\"primary\"\n @click.prevent=\"exportPage('csv')\"\n >{{ text.advanced_export_csv_page }}</b-button>\n {{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>\n </b-tab>\n <b-tab :title='text.advanced_purge'>\n <p>{{text.advanced_purge_page_expl}}</p>\n <p>{{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>\n <p><b-button\n variant=\"danger\"\n @click.prevent=\"purgeStudyplanpage\"\n >{{ text.advanced_purge_page}}</b-button></p>\n <p>{{text.advanced_purge_plan_expl}}</p>\n <p><b-button\n variant=\"danger\"\n @click.prevent=\"purgeStudyplan\"\n >{{ text.advanced_purge_plan}}</b-button></p>\n </b-tab>\n </b-tabs>\n </b-modal>\n </span>\n `\n });\n\n\n /*\n * T-STUDYPLAN-EDIT\n */\n Vue.component('t-studyplan-edit', {\n props: {\n 'value': {\n type: Object,\n default() {\n return null;\n },\n },\n 'mode': {\n type: String,\n default() {\n return \"edit\";\n },\n },\n 'type': {\n type: String,\n default() {\n return \"link\";\n },\n },\n 'variant': {\n type: String,\n default() {\n return \"\";\n },\n },\n 'contextid': {\n type: Number,\n 'default': 1\n },\n },\n data() {\n return {\n text: strings.studyplanEdit,\n };\n },\n computed: {\n },\n methods: {\n planSaved(updatedplan) {\n const self = this;\n debug.info(\"Got new plan data\", updatedplan);\n\n if (self.mode == 'create') {\n // Inform parent of the details of the newly created plan\n self.$emit(\"created\", updatedplan);\n } else {\n // Determine if the plan moved context...\n const movedFrom = self.value.context_id;\n const movedTo = updatedplan.context_id;\n const moved = (movedFrom != movedTo);\n\n if (updatedplan.pages[0].periods != self.value.pages[0].periods) {\n // If the pages changed, just reload the entire model for the plan\n call([{\n methodname: 'local_treestudyplan_get_studyplan_map',\n args: {id: self.value.id}\n }])[0].then((response) => {\n self.value = processStudyplan(response, true);\n debug.info('studyplan processed');\n self.$emit('input', self.value);\n return;\n }).catch(function(error) {\n notification.exception(error);\n });\n } else {\n // Copy updated fields and trigger update\n objCopy(self.value, updatedplan, STUDYPLAN_EDITOR_FIELDS);\n self.$emit('input', self.value);\n if (moved) {\n self.$emit('moved', self.value, movedFrom, movedTo);\n }\n }\n }\n },\n },\n template:\n `\n <span class='s-studyplan-edit'>\n <mform\n name=\"studyplan_editform\"\n :params=\"{studyplan_id: value.id, mode: mode, contextid: contextid }\"\n @saved=\"planSaved\"\n :variant=\"variant\"\n :type=\"type\"\n :title=\"(mode == 'create')?text.studyplan_add:text.studyplanEdit\"\n ><slot><i class='fa fa-gear'></i></slot></mform>\n </span>\n `\n });\n\n /*\n * T-STUDYPLAN-EDIT\n */\n Vue.component('t-studyplan-page-edit', {\n props: {\n 'value': {\n type: Object,\n default() {\n return null;\n },\n },\n 'mode': {\n type: String,\n default() {\n return \"edit\";\n },\n },\n 'type': {\n type: String,\n default() {\n return \"link\";\n },\n },\n 'variant': {\n type: String,\n default() {\n return \"\";\n },\n },\n 'studyplan': {\n type: Object,\n },\n },\n data() {\n return {\n text: strings.studyplanEdit,\n };\n },\n computed: {\n },\n methods: {\n planSaved(updatedpage) {\n const self = this;\n\n if (self.mode == 'create') {\n // Inform parent of the details of the newly created plan\n self.$emit(\"created\", updatedpage);\n } else {\n const page = processStudyplanPage(updatedpage);\n debug.info('studyplan page processed');\n\n if (self.value.periods < page.periods) {\n this.$bvModal.msgBoxOk(this.text.info_periodsextended, {\n title: this.text.warning,\n okVariant: 'success',\n centered: true\n });\n }\n self.$emit('input', page);\n\n }\n },\n },\n template:\n `\n <span class='s-studyplan-page-edit'>\n <mform\n name=\"studyplanpage_editform\"\n :params=\"{page_id: value.id, studyplan_id: studyplan.id, mode: mode }\"\n @saved=\"planSaved\"\n :variant=\"variant\"\n :type=\"type\"\n :title=\"(mode == 'create')?text.studyplanpage_add:text.studyplanpage_edit\"\n ><slot><i class='fa fa-gear'></i></slot></mform>\n </span>\n `\n });\n\n\n /*\n * T-STUDYPLAN-ASSOCIATE\n */\n Vue.component('t-studyplan-associate', {\n props: ['value'],\n data() {\n return {\n show: false,\n config: {\n userfields: [\n {key: \"selected\"},\n {key: \"firstname\", \"sortable\": true},\n {key: \"lastname\", \"sortable\": true},\n ],\n cohortfields: [\n {key: \"selected\"},\n {key: \"name\", \"sortable\": true},\n {key: \"context\", \"sortable\": true},\n ]\n },\n association: {\n cohorts: [],\n users: [],\n coaches: []\n },\n loading: {\n cohorts: false,\n users: false,\n coaches: false,\n },\n search: {users: [], cohorts: [], coaches: []},\n selected: {\n search: {users: [], cohorts: [], coaches: []},\n associated: {users: [], cohorts: [], coaches: []}\n },\n text: strings.studyplanAssociate,\n };\n },\n methods: {\n showModal() {\n this.show = true;\n this.loadAssociations();\n },\n cohortOptionModel(c) {\n return {\n value: c.id,\n text: c.name + ' (' + c.context.path.join(' / ') + ')',\n };\n },\n userOptionModel(u) {\n return {\n value: u.id,\n text: u.firstname + ' ' + u.lastname,\n };\n },\n loadAssociations() {\n const self = this;\n self.loading.cohorts = true;\n self.loading.users = true;\n call([{\n methodname: 'local_treestudyplan_associated_users',\n args: {\n 'studyplan_id': self.value.id,\n }\n }])[0].then((response) => {\n self.association.users = response.map(self.userOptionModel);\n self.loading.users = false;\n return;\n }).catch(notification.exception);\n\n call([{\n methodname: 'local_treestudyplan_associated_cohorts',\n args: {\n 'studyplan_id': self.value.id,\n }\n }])[0].then((response) => {\n self.association.cohorts = response.map(self.cohortOptionModel);\n self.loading.cohorts = false;\n return;\n }).catch(notification.exception);\n\n self.loading.coaches = true;\n call([{\n methodname: 'local_treestudyplan_associated_coaches',\n args: {\n 'studyplan_id': self.value.id,\n }\n }])[0].then((response) => {\n self.association.coaches = response.map(self.userOptionModel);\n self.loading.coaches = false;\n return;\n }).catch(notification.exception);\n },\n searchCohorts(searchtext) {\n const self = this;\n\n if (searchtext.length > 0) {\n call([{\n methodname: 'local_treestudyplan_list_cohort',\n args: {\n like: searchtext,\n 'studyplan_id': self.value.id\n }\n }])[0].then((response) => {\n self.search.cohorts = response.map(self.cohortOptionModel);\n return;\n }).catch(notification.exception);\n } else {\n self.search.cohorts = [];\n }\n },\n cohortAssociate() {\n const self = this;\n let requests = [];\n const associated = self.association.cohorts;\n const search = self.search.cohorts;\n const searchselected = self.selected.search.cohorts;\n for (const i in searchselected) {\n const r = searchselected[i];\n call([{\n methodname: 'local_treestudyplan_connect_cohort',\n args: {\n 'studyplan_id': self.value.id,\n 'cohort_id': r,\n },\n }])[0].then((response) => {\n if (response.success) {\n transportItem(associated, search, r);\n }\n return;\n }).catch(notification.exception);\n }\n call(requests);\n },\n cohortDisassociate() {\n const self = this;\n const associatedselected = self.selected.associated.cohorts;\n const associated = self.association.cohorts;\n const search = self.search.cohorts;\n for (const i in associatedselected) {\n const r = associatedselected[i];\n call([{\n methodname: 'local_treestudyplan_disconnect_cohort',\n args: {\n 'studyplan_id': self.value.id,\n 'cohort_id': r,\n }\n }])[0].then((response) => {\n if (response.success) {\n transportItem(search, associated, r);\n }\n return;\n }).catch(notification.exception);\n }\n },\n searchUsers(searchtext) {\n const self = this;\n if (searchtext.length > 0) {\n call([{\n methodname: 'local_treestudyplan_find_user',\n args: {\n like: searchtext,\n 'studyplan_id': self.value.id\n }\n }])[0].then((response) => {\n self.search.users = response.map(self.userOptionModel);\n return;\n }).catch(notification.exception);\n } else {\n self.search.users = [];\n }\n },\n userAssociate() {\n const self = this;\n const associated = self.association.users;\n const search = self.search.users;\n const searchselected = self.selected.search.users;\n for (const i in searchselected) {\n const r = searchselected[i];\n call([{\n methodname: 'local_treestudyplan_connect_user',\n args: {\n 'studyplan_id': self.value.id,\n 'user_id': r,\n },\n }])[0].then((response) => {\n if (response.success) {\n transportItem(associated, search, r);\n }\n return;\n }).catch(notification.exception);\n }\n },\n userDisassociate() {\n const self = this;\n const associated = self.association.users;\n const associatedselected = self.selected.associated.users;\n const search = self.search.users;\n for (const i in associatedselected) {\n const r = associatedselected[i];\n call([{\n methodname: 'local_treestudyplan_disconnect_user',\n args: {\n 'studyplan_id': self.value.id,\n 'user_id': r,\n }\n }])[0].then((response) => {\n if (response.success) {\n transportItem(search, associated, r);\n }\n return;\n }).catch(notification.exception);\n }\n },\n searchCoaches(searchtext) {\n const self = this;\n if (searchtext.length > 0) {\n call([{\n methodname: 'local_treestudyplan_find_coach',\n args: {\n like: searchtext,\n 'studyplan_id': self.value.id,\n }\n }])[0].then((response) => {\n self.search.coaches = response.map(self.userOptionModel);\n return;\n }).catch(notification.exception);\n } else {\n self.search.coaches = [];\n }\n },\n coachAssociate() {\n const self = this;\n const associated = self.association.coaches;\n const search = self.search.coaches;\n const searchselected = self.selected.search.coaches;\n for (const i in searchselected) {\n const r = searchselected[i];\n\n call([{\n methodname: 'local_treestudyplan_connect_coach',\n args: {\n 'studyplan_id': self.value.id,\n 'user_id': r,\n },\n }])[0].then((response) => {\n if (response.success) {\n transportItem(associated, search, r);\n }\n return;\n }).catch(notification.exception);\n }\n },\n coachDisassociate() {\n const self = this;\n const associated = self.association.coaches;\n const associatedselected = self.selected.associated.coaches;\n const search = self.search.coaches;\n for (const i in associatedselected) {\n const r = associatedselected[i];\n\n call([{\n methodname: 'local_treestudyplan_disconnect_coach',\n args: {\n 'studyplan_id': self.value.id,\n 'user_id': r,\n }\n }])[0].then((response) => {\n if (response.success) {\n transportItem(search, associated, r);\n }\n return;\n }).catch(notification.exception);\n }\n },\n },\n template:\n`\n<span class='s-studyplan-associate'\n ><a href='#' @click.prevent=\"showModal\" ><slot><i class='fa fa-users'></i></slot></a>\n <b-modal\n v-model=\"show\"\n size=\"lg\"\n ok-variant=\"primary\"\n :title=\"text.associations + ' - ' + value.name\"\n ok-only>\n <b-tabs class='s-studyplan-associate-window'>\n <b-tab :title=\"text.cohorts\">\n <b-container>\n <b-row class='mb-2 mt-2'>\n <b-col>{{text.associated_cohorts}}</b-col>\n <b-col>{{text.associate_cohorts}}</b-col>\n </b-row>\n <b-row class='mb-2'>\n <b-col>\n </b-col>\n <b-col>\n <b-form-input\n type=\"text\" @input=\"searchCohorts($event)\"\n :placeholder=\"text.search\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col>\n <b-form-select\n multiple\n v-model=\"selected.associated.cohorts\"\n :options=\"association.cohorts\"\n :select-size=\"10\"\n ></b-form-select>\n </b-col>\n <b-col>\n <b-form-select\n multiple\n v-model=\"selected.search.cohorts\"\n :options=\"search.cohorts\"\n :select-size=\"10\"\n ></b-form-select>\n </b-col>\n </b-row>\n <b-row class='mt-2'>\n <b-col>\n <b-button variant='danger' @click.prevent=\"cohortDisassociate()\"\n ><i class='fa fa-chain-broken'></i>&nbsp;{{text.delete_association}}</b-button>\n </b-col>\n <b-col>\n <b-button variant='success' @click.prevent=\"cohortAssociate()\"\n ><i class='fa fa-link'></i>&nbsp;{{text.add_association}}</b-button>\n </b-col>\n </b-row>\n </b-container>\n </b-tab>\n <b-tab :title=\"text.users\">\n <b-container>\n <b-row class='mb-2 mt-2'>\n <b-col>{{text.associated_users}}</b-col>\n <b-col>{{text.associate_users}}</b-col>\n </b-row>\n <b-row class='mb-2'>\n <b-col>\n </b-col>\n <b-col>\n <b-form-input\n type=\"text\"\n @input=\"searchUsers($event)\"\n :placeholder=\"text.search + ' ' + text.users\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col>\n <b-form-select\n multiple\n v-model=\"selected.associated.users\"\n :options=\"association.users\"\n :select-size=\"10\"\n ></b-form-select>\n </b-col>\n <b-col>\n <b-form-select\n multiple\n v-model=\"selected.search.users\"\n :options=\"search.users\"\n :select-size=\"10\"\n ></b-form-select>\n </b-col>\n </b-row>\n <b-row class='mt-2'>\n <b-col>\n <b-button variant='danger' @click.prevent=\"userDisassociate()\"\n ><i class='fa fa-chain-broken'></i>&nbsp;{{text.delete_association}}</b-button>\n </b-col>\n <b-col>\n <b-button variant='success' @click.prevent=\"userAssociate()\"\n ><i class='fa fa-link'></i>&nbsp;{{text.add_association}}</b-button>\n </b-col>\n </b-row>\n </b-container>\n </b-tab>\n <b-tab :title=\"text.coaches\">\n <b-container>\n <b-row class='mb-2 mt-2'>\n <b-col>{{text.associated_coaches}}</b-col>\n <b-col>{{text.associate_coaches}}</b-col>\n </b-row>\n <b-row class='mb-2'>\n <b-col>\n </b-col>\n <b-col>\n <b-form-input\n type=\"text\"\n @input=\"searchCoaches($event)\"\n :placeholder=\"text.search + ' ' + text.coaches\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col>\n <b-form-select\n multiple\n v-model=\"selected.associated.coaches\"\n :options=\"association.coaches\"\n :select-size=\"10\"\n ></b-form-select>\n </b-col>\n <b-col>\n <b-form-select\n multiple\n v-model=\"selected.search.coaches\"\n :options=\"search.coaches\"\n :select-size=\"10\"\n ></b-form-select>\n </b-col>\n </b-row>\n <b-row class='mt-2'>\n <b-col>\n <b-button variant='danger' @click.prevent=\"coachDisassociate()\"\n ><i class='fa fa-chain-broken'></i>&nbsp;{{text.delete_association}}</b-button>\n </b-col>\n <b-col>\n <b-button variant='success' @click.prevent=\"coachAssociate()\"\n ><i class='fa fa-link'></i>&nbsp;{{text.add_association}}</b-button>\n </b-col>\n </b-row>\n </b-container>\n </b-tab>\n </b-tabs>\n </b-modal>\n</span>\n`\n });\n\n /* * ****************\n *\n * Period editor\n *\n *************/\n\n Vue.component('t-period-edit', {\n props: {\n 'value': {\n type: Object,\n default() {\n return null;\n },\n },\n 'type': {\n type: String,\n default() {\n return \"link\";\n },\n },\n 'variant': {\n type: String,\n default() {\n return \"\";\n },\n },\n 'minstart': {\n type: String,\n default() {\n return null;\n },\n },\n 'maxend': {\n type: String,\n default() {\n return null;\n },\n }\n },\n data() {\n return {\n show: false,\n editdata: {\n fullname: '',\n shortname: '',\n startdate: (new Date()).getFullYear() + '-08-01',\n enddate: ((new Date()).getFullYear() + 1) + '-08-01',\n },\n text: strings.periodEdit,\n };\n },\n methods: {\n editStart() {\n objCopy(this.editdata, this.value, PERIOD_EDITOR_FIELDS);\n this.show = true;\n },\n editFinish() {\n const self = this;\n let args = {'id': this.value.id};\n\n objCopy(args, this.editdata, PERIOD_EDITOR_FIELDS);\n\n call([{\n methodname: 'local_treestudyplan_edit_period',\n args: args\n }])[0].then((response) => {\n objCopy(self.value, response, PERIOD_EDITOR_FIELDS);\n self.$emit('input', self.value);\n self.$emit('edited', self.value);\n return;\n }).catch(notification.exception);\n },\n refresh() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_get_period',\n args: {'id': this.value.id},\n }])[0].then((response) => {\n objCopy(self.value, response, PERIOD_EDITOR_FIELDS);\n self.$emit('input', self.value);\n return;\n }).catch(notification.exception);\n },\n addDay(date, days) {\n if (days === undefined) {\n days = 1;\n }\n return addDays(date, days);\n },\n subDay(date, days) {\n if (days === undefined) {\n days = 1;\n }\n return addDays(date, 0 - days);\n },\n },\n template:\n `\n <span class='t-period-edit'>\n <b-button :variant=\"variant\" v-if='type == \"button\"' @click.prevent='editStart()'\n ><slot><i class='fa fa-gear'></i></slot></b-button>\n <a variant=\"variant\" v-else href='#' @click.prevent='editStart()'\n ><slot><i class='fa fa-gear'></i></slot></a>\n <b-modal\n v-model=\"show\"\n size=\"lg\"\n ok-variant=\"primary\"\n :title=\"text.edit\"\n @ok=\"editFinish()\"\n :ok-disabled=\"Math.min(editdata.fullname.length,editdata.shortname.length) == 0\"\n >\n <b-container>\n <b-row>\n <b-col cols=\"4\">{{ text.fullname}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"editdata.fullname\"\n :state='editdata.fullname.length>0'\n ></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.shortname}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"editdata.shortname\"\n :state='editdata.shortname.length>0'\n ></b-form-input>\n </b-col>\n </b-row>\n <b-row v-if=\"!value.timeless\">\n <b-col cols=\"4\">{{ text.studyplan_startdate}}</b-col>\n <b-col cols=\"8\">\n <b-form-datepicker\n start-weekday=\"1\"\n v-model=\"editdata.startdate\"\n :min=\"(minstart ? minstart : '')\"\n :max=\"subDay(value.enddate)\"\n ></b-form-datepicker>\n </b-col>\n </b-row>\n <b-row v-if=\"!value.timeless\">\n <b-col cols=\"4\">{{ text.studyplan_enddate}}</b-col>\n <b-col cols=\"8\">\n <b-form-datepicker\n start-weekday=\"1\"\n v-model=\"editdata.enddate\"\n :min=\"addDay(value.startdate)\"\n :max=\"(maxend ? maxend : '')\"\n ></b-form-datepicker>\n </b-col>\n </b-row>\n </b-container>\n </b-modal>\n </span>\n `\n });\n\n // TAG: Start studyplan component\n /*\n * T-STUDYPLAN\n */\n Vue.component('t-studyplan', {\n props: {\n 'value': {\n type: Object,\n },\n 'coaching': {\n type: Boolean,\n 'default': false,\n },\n },\n data() {\n return {\n config: {\n userfields: [\n {key: \"selected\"},\n {key: \"firstname\", \"sortable\": true},\n {key: \"lastname\", \"sortable\": true},\n ],\n cohortfields: [\n {key: \"selected\"},\n {key: \"name\", \"sortable\": true},\n {key: \"context\", \"sortable\": true},\n ]\n },\n create: {\n studyline: {\n name: '',\n shortname: '',\n color: '#DDDDDD',\n enrol: {\n enrollable: 0,\n enrolroles: [],\n }\n },\n page: {\n id: -1,\n name: '',\n shortname: ''\n }\n },\n edit: {\n toolboxShown: false,\n studyline: {\n editmode: false,\n data: {\n name: '',\n shortname: '',\n color: '#DDDDDD',\n enrol: {\n enrollable: 0,\n enrolroles: [],\n }\n },\n original: {},\n availableroles: [],\n },\n studyplan: {\n data: {\n name: '',\n shortname: '',\n description: '',\n slots: 4,\n startdate: '2020-08-01',\n enddate: '',\n aggregation: '',\n 'aggregation_config': '',\n 'aggregation_info': {\n useRequiredGrades: true,\n useItemCondition: false,\n },\n\n },\n original: {},\n }\n },\n text: strings.studyplanText,\n cache: {\n linelayers: {},\n },\n selectedpageindex: 0,\n emptyline: {\n id: -1,\n name: '<No study lines defined>',\n shortname: '<No study lines>',\n color: '#FF0000',\n filterslots: [{}],\n courseslots: [{}]\n },\n availableroles: [],\n };\n },\n created() {\n const self = this;\n // Listener for the signal that a new connection was made and needs to be drawn\n // Sent by the incoming item - By convention, outgoing items are responsible for drawing the lines\n ItemEventBus.$on('coursechange', () => {\n self.$emit('pagechanged', this.selectedpage);\n });\n },\n mounted() {\n const self = this;\n if (this.value.pages[0].studylines.length == 0 && !this.coaching) {\n // Start in editmode if studylines on first page are empty\n this.edit.studyline.editmode = true;\n }\n\n if (!self.coaching) {\n // Retrieve available roles (only needed as manager)\n call([{\n methodname: 'local_treestudyplan_list_roles',\n args: {\n 'studyplan_id': this.value.id,\n }\n }])[0].then((response) => {\n self.availableroles = response;\n return;\n }).catch(notification.exception);\n } else {\n self.edit.toolboxShown = true; // Defaults to on in coching view.\n }\n this.$root.$emit('redrawLines');\n this.$emit('pagechanged', this.selectedpage);\n },\n beforeUnmount() {\n this.edit.toolboxShown = false;\n debug.info(\"Hiding toolbar because of destroy\");\n },\n deactivated() {\n this.edit.toolboxShown = false;\n debug.info(\"Hiding toolbar because of deactivation\");\n },\n activated() {\n if (this.coaching) {\n self.edit.toolboxShown = true; // Defaults to on in coching view.\n }\n\n },\n updated() {\n this.$root.$emit('redrawLines');\n ItemEventBus.$emit('redrawLines');\n },\n computed: {\n selectedpage() {\n return this.value.pages[this.selectedpageindex];\n },\n hivizdrop() {\n return settings(\"hivizdropslots\");\n },\n },\n methods: {\n columns(page) {\n return 1 + (page.periods * 2);\n },\n columnsStylerule(page) {\n // Uses css variables, so width for slots and filters can be configured in css\n let s = \"grid-template-columns: var(--studyplan-filter-width)\"; // Use css variable here\n for (let i = 0; i < page.periods; i++) {\n s += \" var(--studyplan-course-width) var(--studyplan-filter-width)\";\n }\n return s + \";\";\n },\n trashbinAccepts(type) {\n if (type.item) {\n return true;\n } else {\n return false;\n }\n },\n countLineLayers(line, page) {\n // For some optimization, we cache the value of this calculation for about a second\n // Would be a lot nicer if we could use a computed property for this.....\n if (this.cache.linelayers[line.id]\n && ((new Date()) - this.cache.linelayers[line.id].timestamp < 1000)\n ) {\n return this.cache.linelayers[line.id].value;\n } else {\n let maxLayer = -1;\n for (let i = 0; i <= page.periods; i++) {\n if (line.slots[i]) {\n // Determine the amount of used layers in a studyline slot\n for (const ix in line.slots[i].courses) {\n const item = line.slots[i].courses[ix];\n if (item.layer > maxLayer) {\n maxLayer = item.layer;\n }\n }\n for (const ix in line.slots[i].filters) {\n const item = line.slots[i].filters[ix];\n if (item.layer > maxLayer) {\n maxLayer = item.layer;\n }\n }\n\n }\n }\n this.cache.linelayers[line.id] = {\n value: (maxLayer + 1),\n timestamp: (new Date()),\n };\n return maxLayer + 1;\n }\n },\n slotsempty(slots) {\n if (Array.isArray(slots)) {\n let count = 0;\n for (let i = 0; i < slots.length; i++) {\n if (Array.isArray(slots[i].courses)) {\n count += slots[i].courses.length;\n }\n if (Array.isArray(slots[i].filters)) {\n count += slots[i].filters.length;\n }\n }\n return (count == 0);\n } else {\n return false;\n }\n },\n movedStudyplan(plan, from, to) {\n this.$emit('moved', plan, from, to); // Throw the event up....\n },\n addStudyLine(page, newlineinfo) {\n call([{\n methodname: 'local_treestudyplan_add_studyline',\n args: {\n 'page_id': page.id,\n 'name': newlineinfo.name,\n 'shortname': newlineinfo.shortname,\n 'color': newlineinfo.color,\n 'sequence': page.studylines.length,\n 'enrollable': newlineinfo.enrol.enrollable,\n 'enrolroles': newlineinfo.enrol.enrolroles\n }\n }])[0].then((response) => {\n page.studylines.push(response);\n newlineinfo.name = '';\n newlineinfo.shortname = '';\n newlineinfo.color = \"#dddddd\";\n newlineinfo.enrol.enrollable = 0;\n newlineinfo.enrol.enrolroles = [];\n return;\n }).catch(notification.exception);\n },\n editLineStart(line) {\n const page = this.value.pages[this.selectedpageindex];\n debug.info(\"Starting line edit\", line);\n Object.assign(this.edit.studyline.data, line);\n this.edit.studyline.original = line;\n this.$bvModal.show('modal-edit-studyline-' + page.id);\n },\n editLineFinish() {\n let editedline = this.edit.studyline.data;\n let originalline = this.edit.studyline.original;\n call([{\n methodname: 'local_treestudyplan_edit_studyline',\n args: {'id': editedline.id,\n 'name': editedline.name,\n 'shortname': editedline.shortname,\n 'color': editedline.color,\n 'enrollable': editedline.enrol.enrollable,\n 'enrolroles': editedline.enrol.enrolroles\n }\n }])[0].then((response) => {\n originalline.name = response.name;\n originalline.shortname = response.shortname;\n originalline.color = response.color;\n originalline.enrol.enrollable = response.enrol.enrollable;\n originalline.enrol.enrolroles = response.enrol.enrolroles;\n return;\n }).catch(notification.exception);\n },\n deleteLine(page, line) {\n const self = this;\n\n self.$bvModal.msgBoxConfirm(this.text.studylineConfirmRemove.replace('{$a}', line.name), {\n okTitle: this.text.delete,\n okVariant: 'danger',\n }).then((modalresponse) => {\n if (modalresponse) {\n call([{\n methodname: 'local_treestudyplan_delete_studyline',\n args: {'id': line.id}\n }])[0].then((response) => {\n if (response.success == true) {\n let index = page.studylines.indexOf(line);\n page.studylines.splice(index, 1);\n }\n return;\n }).catch(notification.exception);\n }\n return;\n }).catch(notification.exception);\n },\n reorderLines(event, lines) {\n\n // Apply reordering\n event.apply(lines);\n // Send the new sequence to the server\n let sequence = [];\n for (let idx in lines) {\n sequence.push({'id': lines[idx].id, 'sequence': idx});\n }\n call([{\n methodname: 'local_treestudyplan_reorder_studylines',\n args: {'sequence': sequence}\n }])[0].then(() => {\n return;\n }).catch(notification.exception);\n },\n deletePlan(studyplan) {\n const self = this;\n self.$bvModal.msgBoxConfirm(this.text.studyplabConfirmRemove.replace('{$a}', studyplan.name), {\n okTitle: this.text.delete,\n okVariant: 'danger',\n }).then(function(modalresponse) {\n if (modalresponse) {\n call([{\n methodname: 'local_treestudyplan_delete_studyplan',\n args: {'id': studyplan.id, force: true}\n }])[0].then((response) => {\n if (response.success == true) {\n self.$root.$emit(\"studyplanRemoved\", studyplan);\n }\n return;\n }).catch(notification.exception);\n }\n return;\n }).catch(notification.exception);\n },\n deleteStudyItem(event) {\n let item = event.data;\n call([{\n methodname: 'local_treestudyplan_delete_studyitem',\n args: {'id': item.id}\n }])[0].then((response) => {\n if (response.success == true) {\n event.source.$emit('cut', event);\n }\n return;\n }).catch(notification.exception);\n\n },\n showslot(page, line, index, layeridx, type) {\n // Check if the slot should be hidden because a previous slot has an item with a span\n // so big that it hides this slot\n const forGradable = (type == 'gradable') ? true : false;\n const periods = page.periods;\n let show = true;\n for (let i = 0; i < periods; i++) {\n if (line.slots[index - i] && line.slots[index - i].courses) {\n const list = line.slots[index - i].courses;\n for (const ix in list) {\n const item = list[ix];\n if (item.layer == layeridx) {\n if (forGradable) {\n if (i > 0 && (item.span - i) > 0) {\n show = false;\n }\n } else {\n if ((item.span - i) > 1) {\n show = false;\n }\n }\n }\n }\n }\n }\n\n return show;\n },\n periodEdited(pi) {\n const prev = this.$refs[\"periodeditor-\" + (pi.period - 1)];\n if (prev && prev[0]) {\n prev[0].refresh();\n }\n const next = this.$refs[\"periodeditor-\" + (pi.period + 1)];\n if (next && next[0]) {\n next[0].refresh();\n }\n },\n addDay(date, days) {\n if (days === undefined) {\n days = 1;\n }\n return addDays(date, days);\n },\n subDay(date, days) {\n if (days === undefined) {\n days = 1;\n }\n return addDays(date, 0 - days);\n },\n toolboxSwitched(event) {\n this.$emit('toggletoolbox', event);\n },\n pagecreated(page) {\n this.value.pages.push(page);\n },\n selectedpageChanged(newTabIndex /* , prevTabIndex*/) {\n const page = this.value.pages[newTabIndex];\n this.$emit('pagechanged', page);\n },\n sumLineLayers(idx, page) {\n if (idx < 0 || page.studylines.count == 0) {\n return 0;\n } else {\n let sum = 0;\n for (let i = 0; i < idx; i++) {\n sum += this.countLineLayers(page.studylines[i], page) + 1;\n }\n return sum;\n }\n },\n span(line, slot, layer) {\n let span = 1;\n for (const course of line.slots[slot].courses) {\n if (course.slot == slot && course.layer == layer) {\n span = course.span;\n }\n }\n return span;\n },\n onDrop(event, line, slot) {\n debug.info(\"dropping\", event, line, slot);\n const self = this;\n if (event.type.component) { // Double check in case filter fails\n debug.info(\"Adding new component\");\n if (event.type.type == \"gradable\") {\n // Determine first available layer;\n const lineslot = line.slots[slot].courses;\n let nextlayer = 0;\n for (const itm of lineslot) {\n if (itm.layer >= nextlayer) {\n nextlayer = itm.layer + 1;\n }\n }\n\n call([{\n methodname: 'local_treestudyplan_add_studyitem',\n args: {\n \"line_id\": line.id,\n \"slot\": slot,\n \"layer\": nextlayer,\n \"type\": 'course',\n \"details\": {\n \"competency_id\": null,\n 'conditions': '',\n 'course_id': event.data.id,\n 'badge_id': null,\n 'continuation_id': null,\n }\n }\n }])[0].then((response) => {\n let item = response;\n lineslot.push(item);\n self.$emit(\"input\", self.value);\n\n // Call the validate period function on next tick,\n // since it paints the item in the slot first\n this.$nextTick(() => {\n if (this.$refs.timingChecker) {\n this.$refs.timingChecker.validateCoursePeriod();\n }\n });\n ItemEventBus.$emit('coursechange');\n return;\n }).catch(notification.exception);\n } else if (event.type.type == \"filter\") {\n debug.info(\"Adding new filter compenent\");\n // Determine first available layer;\n const lineslot = line.slots[slot].filters;\n let nextlayer = 0;\n for (const itm of lineslot) {\n if (itm.layer >= nextlayer) {\n nextlayer = itm.layer + 1;\n }\n }\n call([{\n methodname: 'local_treestudyplan_add_studyitem',\n args: {\n \"line_id\": line.id,\n \"slot\": slot,\n \"type\": event.data.type,\n \"layer\": nextlayer,\n \"details\": {\n \"badge_id\": event.data.badge ? event.data.badge.id : undefined,\n }\n }\n }])[0].then((response) => {\n let item = response;\n lineslot.push(item);\n self.$emit(\"input\", self.value);\n return;\n }).catch(notification.exception);\n }\n }\n },\n checkTypeCourse(type) {\n if (type.type == \"gradable\") {\n if (settings(\"hivizdropslots\") && !type.item) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n },\n checkTypeFilter(type) {\n if (type.type == \"filter\") {\n if (settings(\"hivizdropslots\") && !type.item) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n }\n },\n template:\n `\n <div>\n <t-toolbox v-model=\"edit.toolboxShown\"\n :activepage=\"selectedpage\"\n :coaching=\"coaching\"\n :studyplanid=\"value.id\"></t-toolbox>\n <div class='controlbox t-studyplan-controlbox'>\n <div class=\"controlbox-group\">\n <b-form-checkbox v-if=\"!coaching\"\n v-model=\"edit.studyline.editmode\" class=\"sw-studyplan-toolbar\" switch\n @change=\"toolboxSwitched(edit.toolboxShown && !edit.studyline.editmode); \"\n >{{ text.studyline_editmode }}</b-form-checkbox>\n <b-form-checkbox\n v-if=\"!edit.studyline.editmode\" v-model=\"edit.toolboxShown\" class=\"sw-studyplan-toolbar\" switch\n @change=\"toolboxSwitched\"\n >{{ text.toolbox_toggle}}</b-form-checkbox>\n <drop\n mode='copy'\n class='t-item-deletebox text-danger border-danger'\n @drop='deleteStudyItem'\n :accepts-type=\"trashbinAccepts\"\n ><i class='fa fa-trash'></i>\n </drop>\n </div>\n <div class=\"controlbox-group\" v-if=\"!coaching\">\n <span class='control editable'>\n <t-studyplan-advanced v-model=\"value\" :selectedpage=\"selectedpage\"></t-studyplan-advanced>\n </span>\n <span class='control editable'>\n <t-studyplan-associate\n v-model=\"value\"><i class='fa fa-users'></i>&nbsp;{{text.associations}}</t-studyplan-associate>\n </span>\n <span class='control editable'>\n <t-studyplan-edit v-model=\"value\" @moved=\"movedStudyplan\"\n ><i class='fa fa-gear'></i>&nbsp;{{text.edit}}</t-studyplan-edit>\n </span>\n <span class='control deletable'>\n <a v-if='value.pages.length == 0' href='#' @click.prevent='deletePlan(value)'\n ><i class='text-danger fa fa-trash'></i></a>\n </span>\n </div>\n </div>\n <b-card no-body>\n <b-tabs\n v-model='selectedpageindex'\n @activate-tab='selectedpageChanged'\n content-class=\"mt-1\">\n <!-- New Tab Button (Using tabs-end slot) -->\n <template #tabs-end>\n <t-studyplan-page-edit\n v-if=\"!coaching\"\n :studyplan=\"value\"\n v-model=\"create.page\"\n type=\"link\"\n mode=\"create\"\n @created=\"pagecreated\"\n ><i class='fa fa-plus'></i></t-studyplan-page-edit>\n </template>\n <b-tab\n v-for=\"(page,pageindex) in value.pages\"\n :key=\"page.id\"\n >\n <template #title>\n {{page.shortname}}\n <t-studyplan-page-edit\n v-if=\"!coaching && (pageindex == selectedpageindex)\"\n v-model=\"value.pages[pageindex]\"\n :studyplan=\"value\"\n type=\"link\"\n ></t-studyplan-page-edit>\n </template>\n <div class='t-studyplan-content-edit'\n v-if=\"edit.studyline.editmode\">\n <drop-list\n :items=\"page.studylines\"\n class=\"t-slot-droplist\"\n :accepts-type=\"'studyline-'+page.id\"\n @reorder=\"reorderLines($event,page.studylines)\"\n mode=\"copy\"\n row\n >\n <template v-slot:item=\"{item}\">\n <drag\n :key=\"item.id\"\n class='t-studyline-drag'\n :data=\"item\"\n :type=\"'studyline-'+page.id\"\n >\n <template v-slot:drag-image>\n <i class=\"fa fa-arrows text-primary\"></i>\n </template>\n <t-studyline-edit\n v-if=\"!coaching\"\n v-model=\"item\"\n @edit='editLineStart(item)'\n @delete='deleteLine(page,item)'\n >\n <div v-if=\"!slotsempty(item.slots)\"> {{ text.editmode_modules_hidden}} </div>\n </t-studyline-edit>\n </drag>\n </template>\n </drop-list>\n </div>\n <div class='t-studyplan-content' v-else>\n <!-- Now paint the headings column -->\n <div class='t-studyplan-headings'>\n <s-studyline-header-heading :identifier='Number(page.id)'></s-studyline-header-heading>\n <template v-if=\"page.studylines.length > 0\">\n <t-studyline-heading v-for=\"(line,lineindex) in page.studylines\"\n :key=\"line.id\"\n @resize=\"headingresized(lineindex,$event)\"\n v-model=\"page.studylines[lineindex]\"\n :layers='countLineLayers(line,page)+1'\n :class=\" 't-studyline' + ((lineindex%2==0)?' odd ' :' even ' )\n + ((lineindex==0)?' first ':' ')\n + ((lineindex==page.studylines.length-1)?' last ':' ')\"\n ></t-studyline-heading>\n </template>\n <t-studyline-heading v-else\n @resize=\"headingresized(0,$event)\"\n\n :layers=\"1\"\n :class=\"'odd first last'\"\n ></t-studyline-heading>\n </div>\n <!-- Next, paint all the cells in the scrollable -->\n <div class=\"t-studyplan-scrollable\" >\n <div class=\"t-studyplan-timeline\" :style=\"columnsStylerule(page)\">\n <!-- add period information -->\n <template v-for=\"(n,index) in (page.periods+1)\">\n <s-studyline-header-period\n mode=\"edit\"\n :x-index=\"index\"\n :style=\"'grid-area: 1 / '+ ((2*index)) +';'\"\n :identifier='Number(page.id)'\n v-if=\"index > 0\"\n v-model=\"page.perioddesc[index-1]\"\n ><t-period-edit\n v-if=\"!coaching\"\n :ref=\"'periodeditor-'+index\"\n @edited=\"periodEdited\"\n v-model=\"page.perioddesc[index-1]\"\n :minstart=\"(index > 1) ? addDay(page.perioddesc[index-2].startdate,2) : null\"\n :maxend=\"(index < page.periods) ? subDay(page.perioddesc[index].enddate,2) : null\"\n ></t-period-edit\n ></s-studyline-header-period>\n <div class=\"s-studyline-header-filter\"\n :x-index=\"index\"\n :style=\"'grid-area: 1 / '+ ((2*index)+1) +';'\"\n ></div>\n </template>\n\n <!-- Line by line add the items -->\n <!-- The grid layout handles putting it in rows and columns -->\n <template v-for=\"(line,lineindex) in page.studylines\"\n ><template v-for=\"(layernr,layeridx) in countLineLayers(line,page)+1\"\n ><template v-for=\"(n,index) in (page.periods+1)\"\n ><t-studyline-slot\n v-if=\"index > 0 && showslot(page,line, index, layeridx, 'gradable')\"\n :style=\"'grid-area: '+ (1+sumLineLayers(lineindex,page)+layernr)\n + ' / ' + (2 * index)\n + ' / ' + (1 + sumLineLayers(lineindex,page)+layernr)\n + ' / ' + ( (2 * index) + (2*span(line,index,layeridx) - 1)) + ';'\"\n type='gradable'\n v-model=\"line.slots[index].courses\"\n :key=\"'c-'+lineindex+'-'+index+'-'+layernr\"\n :slotindex=\"index\"\n :line=\"line\"\n :plan=\"value\"\n :page=\"page\"\n :period=\"page.perioddesc[index-1]\"\n :layer=\"layeridx\"\n :class=\"'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')\n + ((lineindex==0 && layernr==1)?' first ':' ')\n + ((lineindex==page.studylines.length-1)?' last ':' ')\n + ((layernr == countLineLayers(line,page))?' lastlyr ':' ')\n + ((layernr == countLineLayers(line,page)+1)?' newlyr ':' ')\"\n ></t-studyline-slot\n ><t-studyline-slot\n type='filter'\n :style=\"'grid-area: '+ (1+sumLineLayers(lineindex,page)+layernr) + ' / ' + (2*index+1) +';'\"\n v-if=\"showslot(page,line, index, layeridx, 'filter')\"\n v-model=\"line.slots[index].filters\"\n :key=\"'f-'+lineindex+'-'+index+'-'+layernr\"\n :slotindex=\"index\"\n :line=\"line\"\n :plan=\"value\"\n :page=\"page\"\n :layer=\"layeridx\"\n :class=\"'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')\n + ((lineindex==0 && layernr==1)?' first ':'')\n + ((lineindex==page.studylines.length-1)?' last ':' ')\n + ((index==page.periods)?' rightmost':'')\n + ((layernr == countLineLayers(line,page))?' lastlyr ':' ')\n + ((layernr == countLineLayers(line,page)+1)?' newlyr ':' ')\"\n ></t-studyline-slot\n ></template\n ></template\n ></template\n ><template v-if=\"hivizdrop\"\n ><template v-for=\"(line,lineindex) in page.studylines\"\n ><template v-for=\"(n,index) in (page.periods+1)\"\n ><drop v-if=\"index > 0\"\n :style=\"'grid-area: '+ (2 + sumLineLayers(lineindex,page))\n + ' / ' + (2 * index)\n + ' / ' + (1 + sumLineLayers(lineindex + 1,page))\n + ' / ' + (2 * index) + '; overflow: hidden;'\"\n :class=\"'t-slot-drop t-slot-linedrop course hiviz'\"\n :accepts-type=\"checkTypeCourse\"\n @drop=\"onDrop($event,line,index)\"\n mode=\"cut\"\n ><span>{{text.drophere}}</span></drop\n ><drop\n :style=\"'grid-area: '+ (2 + sumLineLayers(lineindex,page))\n + ' / ' + ((2 * index) + 1)\n + ' / ' + (1 + sumLineLayers(lineindex + 1,page))\n + ' / ' + ( (2 * index) + 1 ) + '; overflow: hidden;'\"\n :class=\"'t-slot-drop t-slot-linedrop filter hiviz'\"\n :accepts-type=\"checkTypeFilter\"\n @drop=\"onDrop($event,line,index)\"\n mode=\"cut\"\n ><span>{{text.drophere}}</span></drop\n ></template\n ></template\n ></template\n ></div>\n </div>\n </div>\n <div v-if=\"edit.studyline.editmode\" class='t-studyline-add ml-2 mt-1'>\n <a href=\"#\" v-b-modal=\"'modal-add-studyline-'+page.id\" @click.prevent=\"false;\"\n ><i class='fa fa-plus'></i>{{ text.studyline_add }}</a>\n </div>\n <b-modal\n :id=\"'modal-add-studyline-'+page.id\"\n size=\"lg\"\n :ok-title=\"text.add\"\n ok-variant=\"primary\"\n :title=\"text.studyline_add\"\n @ok=\"addStudyLine(page,create.studyline)\"\n :ok-disabled=\"Math.min(create.studyline.name.length,create.studyline.shortname.length) == 0\"\n >\n <b-container>\n <b-row>\n <b-col cols=\"3\">{{text.studyline_name}}</b-col>\n <b-col>\n <b-form-input v-model=\"create.studyline.name\" :placeholder=\"text.studyline_name_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{text.studyline_shortname}}</b-col>\n <b-col>\n <b-form-input\n v-model=\"create.studyline.shortname\"\n :placeholder=\"text.studyline_shortname_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{text.studyline_color}}</b-col>\n <b-col>\n <input type=\"color\" v-model=\"create.studyline.color\" />\n <!-- hsluv-picker v-model=\"create.studyline.color\" horizontal displaysize=\"175\" ></hsluv-picker -->\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_enrollable}}</b-col>\n <b-col>\n <b-form-select v-model=\"create.studyline.enrol.enrollable\">\n <b-form-select-option\n v-for=\"(nr,n) in 4\"\n :value=\"n\"\n :key=\"n\"\n >{{text['line_enrollable_'+n]}}</b-form-select-option>\n </b-form-select>\n </b-col>\n </b-row>\n <b-row v-if='[2,3].includes(create.studyline.enrol.enrollable)'>\n <b-col cols=\"3\">{{ text.studyline_enrolroles}}</b-col>\n <b-col>\n <b-form-select\n v-model=\"create.studyline.enrol.enrolroles\"\n :options=\"availableroles\"\n multiple\n value-field=\"id\"\n text-field=\"name\"\n :select-size=\"6\"\n ></b-form-select>\n </b-col>\n </b-row>\n </b-container>\n </b-modal>\n <b-modal\n :id=\"'modal-edit-studyline-'+page.id\"\n size=\"lg\"\n ok-variant=\"primary\"\n :title=\"text.studyline_edit\"\n @ok=\"editLineFinish()\"\n :ok-disabled=\"Math.min(edit.studyline.data.name.length,edit.studyline.data.shortname.length) == 0\"\n >\n <b-container>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_name}}</b-col>\n <b-col>\n <b-form-input\n v-model=\"edit.studyline.data.name\"\n :placeholder=\"text.studyline_name_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_shortname}}</b-col>\n <b-col>\n <b-form-input\n v-model=\"edit.studyline.data.shortname\"\n :placeholder=\"text.studyline_shortname_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_color}}</b-col>\n <b-col>\n <input type=\"color\" v-model=\"edit.studyline.data.color\" />\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_enrollable}}</b-col>\n <b-col>\n <b-form-select v-model=\"edit.studyline.data.enrol.enrollable\">\n <b-form-select-option\n v-for=\"(nr,n) in 4\"\n :value=\"n\"\n >{{text['line_enrollable_'+n]}}</b-form-select-option>\n </b-form-select>\n </b-col>\n </b-row>\n <b-row v-if='[2,3].includes(edit.studyline.data.enrol.enrollable)'>\n <b-col cols=\"3\">{{ text.studyline_enrolroles}}</b-col>\n <b-col>\n <b-form-select\n v-model=\"edit.studyline.data.enrol.enrolroles\"\n :options=\"availableroles\"\n multiple\n value-field=\"id\"\n text-field=\"name\"\n :select-size=\"6\"\n ></b-form-select>\n </b-col>\n </b-row>\n </b-container>\n </b-modal>\n </b-tab>\n </b-tabs>\n </b-card>\n </div>\n `\n });\n\n /*\n * T-STUDYLINE-HEADER\n */\n Vue.component('t-studyline-heading', {\n props: {\n value: {\n type: Object, // Studyline\n default() {\n return {};\n },\n },\n layers: {\n type: Number,\n 'default': 1,\n },\n },\n data() {\n return {\n layerHeights: {}\n };\n },\n created() {\n // Listener for the signal that a new connection was made and needs to be drawn\n // Sent by the incoming item - By convention, outgoing items are responsible for drawing the lines\n ItemEventBus.$on('lineHeightChange', this.onLineHeightChange);\n },\n computed: {\n\n },\n methods: {\n onLineHeightChange(lineid) { // Is called with parameters (lineid, layerid, newheight)\n // All layers for this line have the first slot send an update message on layer height change.\n // When one of those updates is received, record the height and recalculate the total height of the\n // header\n if (this.$refs.main && lineid == this.value.id) {\n const items = document.querySelectorAll(\n `.t-studyline-slot-0[data-studyline='${this.value.id}']`);\n\n // Determine the height of all the lines and add them up.\n let heightSum = 0;\n items.forEach((el) => {\n // Func getBoundingClientRect() Gets the actual fractional height instead of rounded to integer pixels\n const r = el.getBoundingClientRect();\n const height = r.height;\n heightSum += height;\n });\n\n const heightStyle = `${heightSum}px`;\n this.$refs.main.style.height = heightStyle;\n }\n }\n },\n template: `\n <div class=\"t-studyline t-studyline-heading \"\n :data-studyline=\"value.id\" ref=\"main\"\n ><div class=\"t-studyline-handle\" :style=\"'background-color: ' + value.color\"></div>\n <div class=\"t-studyline-title\">\n <abbr v-b-tooltip.hover.right :title=\"value.name\">{{ value.shortname }}</abbr>\n </div>\n </div>\n `,\n });\n\n /*\n * T-STUDYLINE (Used only for study line edit mode)\n */\n Vue.component('t-studyline-edit', {\n props: {\n value: {\n type: Object, // Studyline\n default() {\n return {};\n },\n }\n },\n data() {\n return {\n };\n },\n computed: {\n deletable() {\n // Check if all the slots are empty\n const slots = this.value.slots;\n if (Array.isArray(slots)) {\n let count = 0;\n for (let i = 0; i < slots.length; i++) {\n if (Array.isArray(slots[i].courses)) {\n count += slots[i].courses.length;\n }\n if (Array.isArray(slots[i].filters)) {\n count += slots[i].filters.length;\n }\n }\n return (count == 0);\n } else {\n return false;\n }\n },\n editable() {\n return true;\n }\n },\n methods: {\n onEdit() {\n this.$emit('edit', this.value);\n },\n onDelete() {\n this.$emit('delete', this.value);\n },\n\n },\n template: `\n <div :class=\"'t-studyline '\" >\n <div class=\"t-studyline-handle\" :style=\"'background-color: ' + value.color\"></div>\n <div class=\"t-studyline-title\">\n <div>\n <i class='fa fa-arrows text-primary'></i>\n <abbr v-b-tooltip.hover :title=\"value.name\">{{ value.shortname }}</abbr>\n </div>\n </div>\n <div class='t-studyline-editmode-content'>\n <slot></slot>\n </div>\n <div class='controlbox'>\n <template v-if='editable || deletable'>\n <span class='control editable' v-if='editable'>\n <a href='#' @click.prevent='onEdit'><i class='fa fa-pencil'></i></a>\n </span>\n <span class='control deletable' v-if='deletable'>\n <a v-if='deletable' href='#' @click.prevent='onDelete'><i class='text-danger fa fa-trash'></i></a>\n </span>\n </template>\n </div>\n </div>\n `,\n });\n\n /*\n * During a redisign it was decided to have the studyline still get the entire array as a value,\n * even though it only shows one drop slot for the layer it is in. This is to make repainting easier,\n * since we modify the array for the layer we handle. FIXME: Make this less weird\n */\n Vue.component('t-studyline-slot', {\n props: {\n type: {\n type: String,\n 'default': 'gradable',\n },\n slotindex: {\n type: Number,\n 'default': '',\n },\n line: {\n type: Object,\n default() {\n return null;\n },\n },\n layer: {\n type: Number,\n },\n value: {\n type: Array, // Dict with layer as index\n default() {\n return [];\n },\n },\n plan: {\n type: Object, // Studyplan data\n default() {\n return null;\n },\n },\n page: {\n type: Object, // Studyplan data\n default() {\n return null;\n },\n },\n period: {\n type: Object, // Studyplan data\n default() {\n return null;\n },\n },\n },\n mounted() {\n const self = this;\n if (self.type == \"gradable\" && self.slotindex == 1) {\n self.resizeListener = new ResizeObserver(() => {\n if (self.$refs.main) {\n const size = self.$refs.main.getBoundingClientRect();\n\n ItemEventBus.$emit('lineHeightChange', self.line.id, self.layer, size.height);\n }\n }).observe(self.$refs.main);\n }\n },\n unmounted() {\n if (this.resizeListener) {\n this.resizeListener.disconnect();\n }\n },\n computed: {\n slotkey() {\n return `${this.type}'-'${this.line.id}-${this.slotindex}-${this.layer}`;\n },\n itemidx() {\n for (const ix in this.value) {\n const itm = this.value[ix];\n if (itm.layer == this.layer) {\n return ix;\n }\n }\n return null;\n },\n item() {\n for (const ix in this.value) {\n const itm = this.value[ix];\n if (itm.layer == this.layer) {\n return itm;\n }\n }\n return null;\n },\n listtype() {\n return this.type;\n },\n courseHoverDummy() {\n return {course: this.hover.component};\n },\n spanCss() {\n if (this.item && this.item.span > 1) {\n // Calculate span like this:\n // const span = (2 * this.item.span) - 1;\n return `width: 100%; `;\n } else {\n return \"\";\n }\n }\n },\n data() {\n return {\n text: strings.courseTiming,\n plantext: strings.studyplanText,\n resizeListener: null,\n hover: {\n component: null,\n type: null,\n },\n datechanger: {\n coursespan: null,\n periodspan: null,\n 'default': false,\n defaultchoice: false,\n hidewarn: false,\n }\n };\n },\n methods: {\n hivizdrop() {\n return settings(\"hivizdropslots\");\n },\n onDrop(event) {\n this.hover.component = null;\n this.hover.type = null;\n debug.info(event);\n const self = this;\n if (event.type.item) {\n let item = event.data;\n\n // To avoid weird visuals with the lines,\n // we add the item to the proper place in the front-end first\n item.layer = this.layer;\n item.slot = this.slotindex;\n self.value.push(item);\n self.$emit(\"input\", self.value);\n\n // Then on the next tick, we inform the back end\n // Since moving things around has never been unsuccessful, unless you have other problems,\n // it's better to have nice visuals.\n self.relocateStudyItem(item).then(() => {\n if (this.$refs.timingChecker) {\n this.$refs.timingChecker.validateCoursePeriod();\n }\n return;\n }).catch(notification.exception);\n } else if (event.type.component) {\n debug.info(\"Adding new component\");\n if (event.type.type == \"gradable\") {\n call([{\n methodname: 'local_treestudyplan_add_studyitem',\n args: {\n \"line_id\": self.line.id,\n \"slot\": self.slotindex,\n \"layer\": self.layer,\n \"type\": 'course',\n \"details\": {\n \"competency_id\": null,\n 'conditions': '',\n 'course_id': event.data.id,\n 'badge_id': null,\n 'continuation_id': null,\n }\n }\n }])[0].then((response) => {\n let item = response;\n self.relocateStudyItem(item).then(()=>{\n self.value.push(item);\n self.$emit(\"input\", self.value);\n\n // Call the validate period function on next tick,\n // since it paints the item in the slot first\n this.$nextTick(() => {\n if (this.$refs.timingChecker) {\n this.$refs.timingChecker.validateCoursePeriod();\n }\n });\n ItemEventBus.$emit('coursechange');\n return;\n }).catch(notification.exception);\n return;\n }).catch(notification.exception);\n } else if (event.type.type == \"filter\") {\n debug.info(\"Adding new filter compenent\");\n call([{\n methodname: 'local_treestudyplan_add_studyitem',\n args: {\n \"line_id\": self.line.id,\n \"slot\": self.slotindex,\n \"type\": event.data.type,\n \"details\": {\n \"badge_id\": event.data.badge ? event.data.badge.id : undefined,\n }\n }\n }])[0].then((response) => {\n let item = response;\n self.relocateStudyItem(item).then(() => {\n item.layer = this.layer;\n self.value.push(item);\n self.$emit(\"input\", self.value);\n return;\n }).catch(notification.exception);\n return;\n }).catch(notification.exception);\n }\n }\n },\n onCut(event) {\n const self = this;\n let id = event.data.id;\n for (let i = 0; i < self.value.length; i++) {\n if (self.value[i].id == id) {\n self.value.splice(i, 1); i--;\n break; // Just remove one\n }\n }\n // Do something to signal that this item has been removed\n this.$emit(\"input\", this.value);\n ItemEventBus.$emit('coursechange');\n },\n relocateStudyItem(item) {\n const iteminfo = {'id': item.id, 'layer': this.layer, 'slot': this.slotindex, 'line_id': this.line.id};\n return call([{\n methodname: 'local_treestudyplan_reorder_studyitems',\n args: {'items': [iteminfo]} // Function was designed to relocate multiple items at once, hence the array\n }])[0].catch(notification.exception);\n },\n onDragEnter(event) {\n this.hover.component = event.data;\n this.hover.type = event.type;\n },\n onDragLeave() {\n this.hover.component = null;\n this.hover.type = null;\n },\n maxSpan() {\n // Determine the maximum span for components in this slot\n return this.page.periods - this.slotindex + 1;\n },\n makeType(item) {\n return {\n item: true,\n component: false,\n span: item.span,\n type: this.type,\n };\n },\n checkType(type) {\n if (type.type == this.type) {\n if (settings(\"hivizdropslots\") && !type.item) {\n return false;\n } else {\n if (type == 'filter') {\n return true;\n } else if (type.span <= this.maxSpan()) {\n return true;\n } else {\n return false;\n }\n }\n } else {\n return false;\n }\n }\n },\n template: `\n <div :class=\" 't-studyline-slot '+type \n + ' t-studyline-slot-'+slotindex + ' ' \n + ((slotindex==0)?' t-studyline-firstcolumn ':' ')\n + 'periodcount-' + page.periods + ' '\"\n :data-studyline=\"line.id\" ref=\"main\"\n :style='spanCss'\n ><drag v-if=\"item\"\n :key=\"item.id\"\n class=\"t-slot-item\"\n :data=\"item\"\n :type=\"makeType(item)\"\n @cut=\"onCut\"\n ><t-item\n @deleted=\"onCut\"\n v-model=\"value[itemidx]\"\n :plan=\"plan\"\n :line='line'\n :page='page'\n :period='period'\n :maxspan='maxSpan()'\n ></t-item\n ></drag\n ><drop v-else\n :class=\"'t-slot-drop '+type + (layer > 0?' secondary':' primary') + (hivizdrop()?' hiviz':'')\"\n :accepts-type=\"checkType\"\n @drop=\"onDrop\"\n mode=\"cut\"\n @dragenter=\"onDragEnter\"\n @dragleave=\"onDragLeave\"\n ><template v-if=\"hover.component\">\n <div v-if=\"hover.type.item\"\n class=\"t-slot-item feedback\"\n :key=\"hover.component.id\"\n ><t-item v-model=\"hover.component\" dummy></t-item\n ></div\n ><div v-else-if=\"hover.type.type == 'gradable'\"\n class=\"t-slot-item feedback\"\n :key=\"'course-'+hover.component.id\"\n ><t-item-course v-model=\"courseHoverDummy\"></t-item-course></div\n ><div v-else-if=\"hover.type.type == 'filter'\"\n class=\"t-slot-item feedback\"\n key=\"tooldrop\"\n ><t-item-junction v-if=\"hover.component.type == 'junction'\" ></t-item-junction\n ><t-item-start v-else-if=\"hover.component.type == 'start'\" ></t-item-start\n ><t-item-finish v-else-if=\"hover.component.type == 'finish'\" ></t-item-finish\n ><t-item-badge v-else-if=\"hover.component.type == 'badge'\" ></t-item-badge\n ></div\n ><div v-else\n class=\"t-slot-item feedback\"\n :key=\"hover.type\">--{{ hover.type }}--</div\n ></template\n ><span v-else-if=\"hivizdrop()\">{{plantext.drophere}}</span></drop>\n <t-item-timing-checker hidden\n v-if=\"value && value[itemidx] && value[itemidx].course\"\n ref=\"timingChecker\"\n :maxspan=\"maxSpan()\"\n :page=\"page\"\n :line=\"line\"\n :period=\"period\"\n v-model=\"value[itemidx]\"\n ></t-item-timing-checker>\n </div>\n `,\n });\n\n\n Vue.component('t-item-timing-checker', {\n props: {\n value: {\n type: Object, // T-item model\n },\n page: {\n type: Object, // Studyplanpage\n },\n line: {\n type: Object, // Studyline\n },\n period: {\n type: Object, // Studyplan data\n },\n maxspan: {\n type: Number,\n },\n hidden: {\n type: Boolean,\n 'default': false,\n }\n },\n computed: {\n endperiod() {\n const endperiodnr = Math.min(this.page.periods, this.period.period + (this.value.span - 1));\n return this.page.perioddesc[endperiodnr - 1];\n },\n coursePeriodMatches() {\n const self = this;\n if (self.page.timeless) {\n // Always return true in timeless mode.\n return true;\n }\n if (self.value && self.value.type == 'course') {\n self.datechanger.coursespan = datespaninfo(self.value.course.startdate, self.value.course.enddate);\n self.datechanger.periodspan = datespaninfo(self.period.startdate, self.endperiod.enddate);\n if (self.datechanger.coursespan.first.getTime() == self.datechanger.periodspan.first.getTime()\n && self.datechanger.coursespan.last.getTime() == self.datechanger.periodspan.last.getTime()) {\n return true;\n } else {\n return false;\n }\n } else {\n debug.warn(\"Timing thing not properly configured\", self.value, self.period, self.maxspan);\n return false;\n }\n },\n },\n data() {\n return {\n // Create random id to avoid opening the wrong modals\n id: Math.floor(Math.random() * Date.now()).toString(16),\n text: strings.courseTiming,\n datechanger: {\n coursespan: null,\n periodspan: null,\n globals: {\n 'default': false,\n defaultchoice: false,\n hidewarn: false,\n },\n }\n };\n },\n methods: {\n validateCoursePeriod() {\n const self = this;\n\n if (!self.page.timeless) {\n debug.info(\"Validating course and period\");\n if (!(self.coursePeriodMatches)) {\n debug.info(\"Course timing does not match period timing\");\n\n if (self.value.course.canupdatecourse) {\n if (!self.hidden || !self.datechanger.globals.default) {\n // Periods do not match, pop up the date change request\n this.$bvModal.show('t-course-timing-matching-' + this.id);\n } else if (self.datechanger.globals.defaultvalue) {\n // G for it without asking\n self.changeCoursePeriod();\n }\n } else {\n // User is not able to change course timing - show a warning\n if (!self.hidden || !self.datechanger.globals.hidewarn) {\n this.$bvModal.show('t-course-timing-warning-' + this.id);\n }\n }\n } else {\n debug.info(\"Course timing matches period\", self.datechanger);\n }\n } else {\n debug.info(\"Skipping course timing check because of timeless mode\", self.datechanger);\n }\n },\n changeCoursePeriod() {\n const self = this;\n // Save the state\n if (self.datechanger.globals.default) {\n self.datechanger.globals.defaultvalue = true;\n }\n return call([{\n methodname: 'local_treestudyplan_course_period_timing',\n args: {\n 'period_id': self.period.id,\n 'course_id': this.value.course.id,\n span: this.value.span,\n }\n }])[0].catch(notification.exception).then((response) => {\n self.value.course.startdate = response.startdate;\n self.value.course.enddate = response.enddate;\n self.value.course.timing = response.timing;\n self.$emit(\"input\", self.value);\n return;\n });\n },\n checkFilterSlotBusy(slotindex) {\n debug.info(\"checking filter\", this.line.slots, slotindex, this.value.layer);\n if (this.line.slots[slotindex]) {\n const list = this.line.slots[slotindex].filters;\n for (const ix in list) {\n if (list[ix].layer == this.value.layer) {\n debug.info(\"Busy:\", list[ix]);\n return list[ix];\n }\n }\n }\n return null;\n },\n nextFreeFilterLayer(slotindex) {\n const layer = this.value.layer;\n const list = this.line.slots[slotindex].filters;\n const usedLayers = [];\n for (const ix in list) {\n usedLayers.push(list[ix].layer);\n }\n let nextlyr = layer + 1;\n while (usedLayers.includes(nextlyr)) {\n nextlyr++;\n }\n return nextlyr;\n },\n checkCourseSlotBusy(slotindex) {\n debug.info(\"checking \", this.line.slots, slotindex, this.value.layer);\n if (this.line.slots[slotindex]) {\n const list = this.line.slots[slotindex].courses;\n for (const ix in list) {\n if (list[ix].layer == this.value.layer) {\n debug.info(\"Busy:\", list[ix]);\n return list[ix];\n }\n }\n }\n return null;\n },\n nextFreeCourseLayer(slotindex) {\n const layer = this.value.layer;\n const list = this.line.slots[slotindex].courses;\n const usedLayers = [];\n for (const ix in list) {\n usedLayers.push(list[ix].layer);\n }\n let nextlyr = layer + 1;\n while (usedLayers.includes(nextlyr)) {\n nextlyr++;\n }\n return nextlyr;\n },\n shiftCollisions(span) {\n // Check all periods for collision\n const items = [];\n for (let i = this.value.slot; i < this.value.slot + span; i++) {\n const busyFilter = this.checkFilterSlotBusy(i);\n if (busyFilter) {\n const nextlyr = this.nextFreeFilterLayer(i);\n items.push({\n id: busyFilter.id,\n layer: nextlyr,\n 'line_id': this.line.id,\n slot: busyFilter.slot,\n });\n busyFilter.layer = nextlyr;\n }\n const busyCourse = this.checkCourseSlotBusy(i);\n if (busyCourse && busyCourse.id != this.value.id) {\n const nextlyr = this.nextFreeCourseLayer(i);\n items.push({\n id: busyCourse.id,\n layer: nextlyr,\n 'line_id': this.line.id,\n slot: busyCourse.slot,\n });\n busyCourse.layer = nextlyr;\n }\n }\n if (items.length > 0) {\n call([{\n methodname: 'local_treestudyplan_reorder_studyitems',\n args: {items: items}\n }])[0].catch(notification.exception);\n }\n },\n changeSpan(span) {\n const self = this;\n this.shiftCollisions(span);\n return call([{\n methodname: 'local_treestudyplan_set_studyitem_span',\n args: {\n id: self.value.id,\n span: span\n }\n }])[0].catch(notification.exception).then((response) => {\n self.value.span = response.span;\n self.$emit('input', self.value);\n self.$nextTick(() => {\n self.validateCoursePeriod();\n });\n return;\n });\n },\n formatDuration(dsi) {\n let s = \"\";\n if (dsi.years == 1) {\n s += `1 ${this.text.year}, `;\n } else if (dsi.years > 1) {\n s += `${dsi.years} ${this.text.years}, `;\n }\n if (dsi.weeks == 1) {\n s += `1 ${this.text.week}, `;\n } else if (dsi.weeks > 1) {\n s += `${dsi.weeks} ${this.text.weeks}, `;\n }\n if (dsi.days == 1) {\n s += `1 ${this.text.day}, `;\n } else if (dsi.days > 1) {\n s += `${dsi.days} ${this.text.days}, `;\n }\n\n return s.toLocaleLowerCase();\n },\n },\n // To avoid the span creeping in the dom where it shouldn't, set display to none if it is hidden\n // This does not affect the modals, which are rendered outside of this element when needed\n template: `\n <div :class=\"'t-item-timing-checker'\" :style=\"hidden?'display: none ':''\">\n <template v-if=\"!hidden\" >\n <span class=\"mr-1\" v-if=\"coursePeriodMatches\">\n <i class=\"text-success fa fa-calendar-check-o\"\n v-b-tooltip.hover.topright :title=\"text.timing_ok\"\n ></i>\n </span>\n <span class=\"mr-1\" v-else>\n <a href='#' @click.prevent=\"validateCoursePeriod()\" class=\"text-warning\"\n v-b-tooltip.hover.bottomleft :title=\"text.timing_off\"\n ><i class=\"fa fa-calendar-times-o\"\n ></i\n ><i class=\"fa fa-question-circle text-black-50\"\n style=\"font-size: 0.8em; top: -0.3em; position: relative;\"\n\n ></i\n ></a>\n </span>\n <span class=\"ml-1\" v-b-tooltip.hover.bottomleft :title=\"text.periodspan_desc\"\n >{{ text.periodspan\n }}&nbsp;<b-form-select v-if=\"maxspan > 1\"\n class=\"\"\n size=\"sm\" @change=\"changeSpan\" v-model=\"value.span\">\n <b-form-select-option v-for=\"(n,i) in maxspan\" :value='n' :key='i'\n >{{ n }}</b-form-select-option>\n </b-form-select\n ><span v-else>{{value.span}}</span>&nbsp;{{\n (value.span == 1)?text.period.toLowerCase():text.periods.toLowerCase()\n }}<i\n class=\"fa fa-question-circle text-black-50\"\n style=\"font-size: 0.8em; top: -0.3em; position: relative;\"\n ></i>\n </span>\n </template>\n <b-modal\n :id=\"'t-course-timing-matching-'+this.id\"\n size=\"lg\"\n :title=\"text.title\"\n @ok=\"changeCoursePeriod\"\n :ok-title=\"text.yes\"\n ok-variant=\"danger\"\n :cancel-title=\"text.no\"\n cancel-variant=\"primary\"\n >\n <b-container v-if=\"datechanger.coursespan && datechanger.periodspan && value && value.course\">\n <b-row><b-col cols=\"12\">{{ text.desc }}</b-col></b-row>\n <b-row><b-col cols=\"12\"><div class=\"generalbox alert alert-warning\">{{ text.question }}</div></b-col></b-row>\n <b-row>\n <b-col cols=\"6\">\n <h3> {{ text.course }} </h3>\n <p class=\"mb-0\"><b>{{ value.course.fullname }}</b></p>\n <p class=\"mb-1\"><b>{{ value.course.shortname }}</b></p>\n <p class=\"mb-1\">{{ datechanger.coursespan.formatted.first}} - {{ datechanger.coursespan.formatted.last}}</p>\n <p class=\"mb-0\"><b>{{ text.duration }}</b><br>\n {{ formatDuration(datechanger.coursespan)}}</p>\n </b-col>\n <b-col cols=\"6\">\n <h3> {{ text.period }} </h3>\n <p class=\"mb-0\"><b>{{ period.fullname }}</b><b v-if=\"value.span > 1\"> - {{ endperiod.fullname }}</b></p>\n <p class=\"mb-1\"><b>{{ period.shortname }}</b><b v-if=\"value.span > 1\"> - {{ endperiod.shortname }}</b></p>\n <p class=\"mb-1\">{{ datechanger.periodspan.formatted.first}} - {{ datechanger.periodspan.formatted.last}}</p>\n <p class=\"mb-0\"><b>{{ text.duration }}</b><br>\n {{ formatDuration(datechanger.periodspan)}}</p>\n </b-col>\n </b-row>\n <b-row v-if='hidden' class=\"pt-2\"><b-col cols=\"12\">\n <b-form-checkbox type=\"checkbox\" v-model=\"datechanger.globals.default\">{{ text.rememberchoice }}</b-form-checkbox>\n </b-col></b-row>\n </b-container>\n </b-modal>\n <b-modal\n :id=\"'t-course-timing-warning-'+this.id\"\n size=\"lg\"\n ok-variant=\"primary\"\n :title=\"text.title\"\n :ok-title=\"text.yes\"\n ok-only\n >\n <b-container v-if=\"datechanger.coursespan && datechanger.periodspan && value && value.course\">\n <b-row><b-col cols=\"12\">{{ text.desc }}</b-col></b-row>\n <b-row><b-col cols=\"12\"><div class=\"generalbox alert alert-warning\">{{ text.warning }}</div></b-col></b-row>\n <b-row>\n <b-col cols=\"6\">\n <h3> {{ text.course }} </h3>\n <p class=\"mb-0\"><b>{{ value.course.fullname }}</b></p>\n <p class=\"mb-1\"><b>{{ value.course.shortname }}</b></p>\n <p class=\"mb-1\">{{ datechanger.coursespan.formatted.first}} - {{ datechanger.coursespan.formatted.last}}</p>\n <p class=\"mb-0\"><b>{{ text.duration }}</b><br>\n {{ formatDuration(datechanger.coursespan)}}</p>\n </b-col>\n <b-col cols=>\"6\">\n <h3> {{ text.period }} </h3>\n <p class=\"mb-0\"><b>{{ period.fullname }}</b><b v-if=\"value.span > 1\"> - {{ endperiod.fullname }}</b></p>\n <p class=\"mb-1\"><b>{{ period.shortname }}</b><b v-if=\"value.span > 1\"> - {{ endperiod.shortname }}</b></p>\n <p class=\"mb-1\">{{ datechanger.periodspan.formatted.first}} - {{ datechanger.periodspan.formatted.last}}</p>\n <p class=\"mb-0\"><b>{{ text.duration }}</b><br>\n {{ formatDuration(datechanger.periodspan)}}</p>\n </b-col>\n </b-row>\n <b-row v-if='hidden' class=\"pt-2\"><b-col cols=\"12\">\n <b-form-checkbox type=\"checkbox\" v-model=\"datechanger.globals.hidewarn\">{{ text.hidewarning }}</b-form-checkbox>\n </b-col></b-row>\n </b-container>\n </b-modal>\n </div>\n `,\n });\n\n\n Vue.component('t-item', {\n props: {\n value: {\n type: Object,\n default() {\n return null;\n },\n },\n dummy: {\n type: Boolean,\n default() {\n return false;\n },\n },\n plan: {\n type: Object, // Studyplan page\n default() {\n return null;\n },\n },\n line: {\n type: Object, // Studyplan page\n default() {\n return null;\n },\n },\n page: {\n type: Object, // Studyplan page\n default() {\n return null;\n },\n },\n period: {\n type: Object, // Studyplan page\n default() {\n return null;\n },\n },\n maxspan: {\n type: Number,\n default() {\n return 0;\n },\n },\n },\n data() {\n return {\n dragLine: null,\n dragEventListener: null,\n deleteMode: false,\n conditionOptions: stringKeys.conditions,\n text: strings.itemText,\n showContext: false,\n lines: [],\n };\n },\n methods: {\n dragStart(event) {\n // Add line between start point and drag image\n this.deleteMode = false;\n let start = document.getElementById('studyitem-' + this.value.id);\n let dragelement = document.getElementById('t-item-cdrag-' + this.value.id);\n dragelement.style.position = 'fixed';\n dragelement.style.left = event.position.x + 'px';\n dragelement.style.top = event.position.y + 'px';\n this.dragLine = new SimpleLine(start, dragelement, {\n color: \"#777\",\n gravity: {\n start: LINE_GRAVITY,\n end: LINE_GRAVITY,\n },\n });\n // Add separate event listener to reposition mouse move\n document.addEventListener(\"mousemove\", this.onMouseMove);\n },\n dragEnd() {\n if (this.dragLine !== null) {\n this.dragLine.remove();\n }\n let dragelement = document.getElementById('t-item-cdrag-' + this.value.id);\n dragelement.style.removeProperty('left');\n dragelement.style.removeProperty('top');\n dragelement.style.removeProperty('position');\n document.removeEventListener(\"mousemove\", this.onMouseMove);\n },\n onMouseMove: function(event) {\n let dragelement = document.getElementById('t-item-cdrag-' + this.value.id);\n dragelement.style.position = 'fixed';\n dragelement.style.left = event.clientX + 'px';\n dragelement.style.top = event.clientY + 'px';\n // Line will follow automatically\n },\n onDrop(event) {\n let fromid = event.data.id;\n let toid = this.value.id;\n this.redrawLines();\n call([{\n methodname: 'local_treestudyplan_connect_studyitems',\n args: {'from_id': fromid, 'to_id': toid}\n }])[0].then((response)=>{\n let conn = {'id': response.id, 'from_id': response.from_id, 'to_id': response.to_id};\n ItemEventBus.$emit(\"createdConnection\", conn);\n this.value.connections.in.push(conn);\n return;\n }).catch(notification.exception);\n },\n redrawLine(conn) {\n const lineColor = \"var(--success)\";\n const start = document.getElementById(`studyitem-${conn.from_id}`);\n const end = document.getElementById(`studyitem-${conn.to_id}`);\n\n // Delete old line\n if (this.lines[conn.to_id]) {\n this.lines[conn.to_id].remove();\n delete this.lines[conn.to_id];\n }\n // Create a new line if the start and finish items are visible\n if (start !== null && end !== null && isVisible(start) && isVisible(end)) {\n this.lines[conn.to_id] = new SimpleLine(start, end, {\n color: lineColor,\n gravity: {\n start: LINE_GRAVITY,\n end: LINE_GRAVITY,\n },\n });\n }\n\n },\n deleteLine(conn) {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_disconnect_studyitems',\n args: {'from_id': conn.from_id, 'to_id': conn.to_id}\n }])[0].then((response)=>{\n if (response.success) {\n this.removeLine(conn);\n // Send disconnect event on message bus, so the connection on the other end can delete it too\n ItemEventBus.$emit(\"connectionDisconnected\", conn);\n // Remove connection from our outgoing list\n let index = self.value.connections.out.indexOf(conn);\n self.value.connections.out.splice(index, 1);\n }\n return;\n }).catch(notification.exception);\n },\n highlight(conn) {\n if (this.lines[conn.to_id]) {\n this.lines[conn.to_id].setConfig({color: \"var(--danger)\"});\n }\n },\n normalize(conn) {\n if (this.lines[conn.to_id]) {\n this.lines[conn.to_id].setConfig({color: \"var(--success)\"});\n }\n },\n updateItem() {\n call([{\n methodname: 'local_treestudyplan_edit_studyitem',\n args: {\n 'id': this.value.id,\n 'conditions': this.value.conditions,\n 'continuation_id': this.value.continuation_id,\n }\n }])[0].catch(notification.exception);\n },\n doShowContext(event) {\n if (this.hasContext) {\n this.showContext = true;\n event.preventDefault();\n }\n },\n redrawLines() {\n if (this.value.connections && this.value.connections.out) {\n for (let i in this.value.connections.out) {\n let conn = this.value.connections.out[i];\n this.redrawLine(conn);\n }\n }\n },\n\n // EVENT LISTENERS\n onCreatedConnection(conn) {\n if (conn.from_id == this.value.id) {\n this.value.connections.out.push(conn);\n this.redrawLine(conn);\n }\n },\n // Listener for the signal that a connection was removed by the outgoing item\n onRemovedConnection(conn) {\n if (this.value.connections && this.value.connections.out) {\n for (let i in this.value.connections.in) {\n let cin = this.value.connections.in[i];\n if (conn.id == cin.id) {\n self.value.connections.out.splice(i, 1);\n }\n }\n }\n },\n // Listener for reposition events\n // When an item in the list is repositioned, all lines need to be redrawn\n onRePositioned() {\n this.redrawLines();\n },\n // When an item is disPositioned - (temporarily) removed from the list,\n // all connections need to be deleted.\n onDisPositioned(reid) {\n if (this.value.connections && this.value.connections.out) {\n for (let i in this.value.connections.out) {\n let conn = this.value.connections.out[i];\n if (conn.to_id == reid) {\n this.removeLine(conn);\n }\n }\n }\n },\n\n // When an item is deleted\n // all connections to/from that item need to be cleaned up\n onItemDeleted(itemid) {\n const self = this;\n if (this.value.connections && this.value.connections.out) {\n for (const i in this.value.connections.out) {\n let conn = this.value.connections.out[i];\n if (conn.to_id == itemid) {\n self.removeLine(conn);\n self.value.connections.out.splice(i, 1);\n }\n }\n }\n if (this.value.connections && this.value.connections.in) {\n for (const i in this.value.connections.in) {\n let conn = this.value.connections.in[i];\n if (conn.from_id == itemid) {\n self.value.connections.out.splice(i, 1);\n }\n }\n }\n },\n\n onRedrawLines() {\n this.redrawLines();\n },\n\n removeLine(conn) {\n if (this.lines[conn.to_id]) {\n this.lines[conn.to_id].remove();\n delete this.lines[conn.to_id];\n }\n },\n deleteItem() {\n const self = this;\n const msgparams = {\n item: this.text['type_' + this.value.type].toLocaleLowerCase(),\n name: (this.value.type == 'course') ? this.value.course.displayname : \"\",\n line: (this.line) ? this.line.name : \"\",\n period: (this.period) ? this.period.fullname : this.plan.name,\n };\n\n this.$bvModal.msgBoxConfirm(strformat(this.text.item_delete_message, msgparams), {\n okVariant: 'danger',\n okTitle: this.text.ok,\n cancelTitle: this.text.cancel,\n }).then(value => {\n if (value) {\n // Confirmed to delete.\n call([{\n methodname: 'local_treestudyplan_delete_studyitem',\n args: {\n 'id': self.value.id,\n }\n }])[0].then((response) => {\n if (response.success == true) {\n self.$emit(\"deleted\", {data: self.value});\n }\n return;\n }).catch(notification.exception);\n }\n return;\n }).catch(err => {\n debug.console.error(err);\n });\n }\n },\n computed: {\n hasConnectionsOut() {\n return !([\"finish\"].includes(this.value.type));\n },\n hasConnectionsIn() {\n return !([\"start\"].includes(this.value.type));\n },\n hasContext() {\n return ['start', 'junction', 'finish'].includes(this.value.type);\n }\n },\n created() {\n // Add event listeners on the message bus\n // But only if not in \"dummy\" mode - mode which is used for droplist placeholders\n // Since an item is \"fully made\" with all references, not specifying dummy mode really messes things up\n if (!this.dummy) {\n // Listener for the signal that a new connection was made and needs to be drawn\n // Sent by the incoming item - By convention, outgoing items are responsible for drawing the lines\n ItemEventBus.$on('createdConnection', this.onCreatedConnection);\n // Listener for the signal that a connection was removed by the outgoing item\n ItemEventBus.$on('removedConnection', this.onRemovedConnection);\n // Listener for reposition events\n // When an item in the list is repositioned, all lines need to be redrawn\n ItemEventBus.$on('rePositioned', this.onRePositioned);\n // When an item is disPositioned - (temporarily) removed from the list,\n // all connections need to be deleted.\n ItemEventBus.$on('disPositioned', this.onDisPositioned);\n // When an item is deleted\n // all connections to/from that item need to be cleaned up\n ItemEventBus.$on('itemDeleted', this.onItemDeleted);\n ItemEventBus.$on('redrawLines', this.onRedrawLines);\n }\n },\n mounted() {\n // Initialize connection lines when mounting\n // But only if not in \"dummy\" mode - mode which is used for droplist placeholders\n // Since an item is \"fully made\" with all references, not specifying dummy mode really messes things up\n\n if (!this.dummy) {\n this.redrawLines();\n setTimeout(()=>{\n ItemEventBus.$emit(\"rePositioned\", this.value.id);\n }, 10);\n }\n },\n beforeDestroy() {\n if (!this.dummy) {\n for (let i in this.value.connections.out) {\n let conn = this.value.connections.out[i];\n this.removeLine(conn);\n }\n ItemEventBus.$emit(\"disPositioned\", this.value.id);\n\n // Remove event listeners\n ItemEventBus.$off('createdConnection', this.onCreatedConnection);\n ItemEventBus.$off('removedConnection', this.onRemovedConnection);\n ItemEventBus.$off('rePositioned', this.onRePositioned);\n ItemEventBus.$off('disPositioned', this.onDisPositioned);\n ItemEventBus.$off('itemDeleted', this.onItemDeleted);\n ItemEventBus.$off('redrawLines', this.onRedrawLines);\n }\n },\n updated() {\n if (!this.dummy) {\n this.redrawLines();\n }\n },\n template: `\n <div class=\"t-item-base\" :id=\"'studyitem-'+value.id\">\n <t-item-course\n v-if=\"value.type == 'course'\"\n @deleterq=\"deleteItem\"\n v-model=\"value\"\n :plan='plan'\n :line='line'\n :page='page'\n :period='period'\n :maxspan='maxspan'\n ></t-item-course>\n <t-item-junction\n v-if=\"value.type == 'junction'\"\n @deleterq=\"deleteItem\"\n v-model=\"value\"\n ></t-item-junction>\n <t-item-start\n v-if=\"value.type == 'start'\"\n @deleterq=\"deleteItem\"\n v-model=\"value\"\n ></t-item-start>\n <t-item-finish\n v-if=\"value.type == 'finish'\"\n @deleterq=\"deleteItem\"\n v-model=\"value\"\n ></t-item-finish>\n <t-item-badge\n v-if=\"value.type == 'badge'\"\n @deleterq=\"deleteItem\"\n v-model=\"value\"\n ></t-item-badge>\n <t-item-invalid\n v-if=\"value.type == 'invalid'\"\n @deleterq=\"deleteItem\"\n v-model=\"value\"\n ></t-item-invalid>\n <drop v-if='!dummy && hasConnectionsIn' accepts-type=\"linestart\"\n :id=\"'t-item-cend-'+value.id\"\n class=\"t-item-connector-end\"\n mode=\"copy\"\n @drop=\"onDrop\"\n ><svg width='5px' height='10px'><rect ry=\"1px\" rx=\"1px\" y=\"0px\" x=\"0px\" height=\"10px\" width=\"5px\"/></svg></drop>\n <drag v-if='!dummy && hasConnectionsOut' type=\"linestart\"\n :id=\"'t-item-cstart-'+value.id\"\n :class=\"'t-item-connector-start ' + ((deleteMode&&value.connections.out.length)?'deleteMode':'')\"\n :data=\"value\"\n @dragstart=\"dragStart\"\n @dragend=\"dragEnd\"\n @click.prevent=\"deleteMode = (value.connections.out.length)?(!deleteMode):false\"\n >\n <svg width='5px' height='10px'><rect ry=\"1px\" rx=\"1px\" y=\"0px\" x=\"0px\" height=\"10px\" width=\"5px\"/></svg>\n <template v-slot:drag-image=\"{data}\"> <i :id=\"'t-item-cdrag-'+value.id\" class=\"fa\"></i>\n </template>\n </drag>\n <div class=\"deletebox\" v-if=\"deleteMode && value.connections.out.length > 0\"\n >\n <a v-for=\"conn in value.connections.out\"\n @click.prevent=\"deleteLine(conn)\"\n @mouseenter=\"highlight(conn)\"\n @mouseleave=\"normalize(conn)\"\n class=\"t-connection-delete text-danger\"\n :title=\"conn.id\">\n <i class=\"fa fa-trash\"></i>\n </a>\n </div>\n <a v-if=\"hasContext\" class=\"t-item-config\"\n v-b-modal=\"'t-item-config-'+value.id\" href=\"#\" @click.prevent=\"\"><i class=\"fa fa-gear\"></i></a>\n <b-modal no-body class=\"\"\n :id=\"'t-item-config-'+value.id\"\n :title=\"text['item_configuration']\"\n scrollable\n ok-only\n class=\"t-item-contextview b-modal-justify-footer-between\"\n >\n <b-form-group\n v-if=\"value.type != 'start'\"\n :label=\"text.select_conditions\"\n >\n <b-form-select size=\"sm\"\n @input=\"updateItem\"\n v-model=\"value.conditions\"\n :options=\"conditionOptions\"\n ></b-form-select>\n </b-form-group>\n\n <template #modal-footer=\"{ ok, cancel, hide }\" >\n <a href='#' @click.prevent='deleteItem()' class=\"text-danger\"\n ><i class=\"fa fa-trash\"></i>\n {{ text.delete }}\n </a>\n <b-button size=\"sm\" variant=\"primary\" @click.prevent=\"ok()\">\n {{ text.ok }}\n </b-button>\n </template>\n\n </b-modal>\n </div>\n `,\n });\n\n Vue.component('t-item-invalid', {\n props: {\n 'value': {\n type: Object,\n default() {\n return null;\n },\n },\n },\n data() {\n return {\n text: strings.invalid,\n };\n },\n methods: {\n },\n template: `\n <div class=\"t-item-invalid\">\n <b-card no-body >\n <b-row no-gutters>\n <b-col md=\"1\">\n <span class=\"t-timing-indicator timing-invalid\"></span>\n </b-col>\n <b-col md=\"11\">\n <b-card-body class=\"align-items-center\">\n <i class=\"fa fa-exclamation\"></i> {{text.error}}\n <a href='#' @click.prevent='$emit(\"deleterq\")' class=\"text-danger\"\n ><i class=\"fa fa-trash\"></i></a>\n </b-card-body>\n </b-col>\n </b-row>\n </b-card>\n </div>\n `,\n });\n\n // TAG: Course item\n Vue.component('t-item-course', {\n props: {\n value: {\n type: Object,\n default() {\n return null;\n },\n },\n plan: {\n type: Object,\n default() {\n return null;\n },\n },\n line: {\n type: Object,\n default() {\n return null;\n },\n },\n page: {\n type: Object, // PAge data\n default() {\n return null;\n }\n },\n period: {\n type: Object, // Period data\n default() {\n return null;\n }\n },\n maxspan: {\n type: Number,\n default() {\n return 0;\n }\n },\n },\n data() {\n return {\n conditionOptions: stringKeys.conditions,\n text: strings.itemCourseText,\n };\n },\n computed: {\n useItemConditions() {\n if (this.plan && this.plan.aggregation_info && this.plan.aggregation_info.useItemConditions !== undefined) {\n return this.plan.aggregation_info.useItemConditions;\n } else {\n return false;\n }\n },\n\n configurationState() {\n if (this.hasGrades() || this.hasCompletions() || this.hasCompetencies()) {\n return \"t-configured-ok\";\n } else {\n return \"t-configured-alert\";\n }\n },\n\n configurationIcon() {\n if (this.hasGrades() || this.hasCompletions() || this.hasCompetencies()) {\n return \"check\";\n } else {\n return \"exclamation-circle\";\n }\n },\n startdate() {\n return formatDate(this.value.course.startdate);\n },\n enddate() {\n if (this.value.course.enddate > 0) {\n return formatDate(this.value.course.enddate);\n } else {\n return this.text.noenddate;\n }\n },\n wwwroot() {\n return Config.wwwroot;\n }\n\n },\n methods: {\n hasGrades() {\n if (this.value.course.grades && this.value.course.grades.length > 0) {\n for (const g of this.value.course.grades) {\n if (g.selected) {\n return true;\n }\n }\n }\n return false;\n },\n hasCompletions() {\n if (this.value.course.completion && this.value.course.completion.conditions) {\n for (const cgroup of this.value.course.completion.conditions) {\n if (cgroup.items && cgroup.items.length > 0) {\n return true;\n }\n }\n }\n return false;\n },\n hasCompetencies() {\n if (this.value.course.competency && this.value.course.competency.competencies) {\n return (this.value.course.competency.competencies.length > 0);\n }\n return false;\n },\n includeChanged(newValue, g) {\n call([{\n methodname: 'local_treestudyplan_include_grade',\n args: {\n 'grade_id': g.id,\n 'item_id': this.value.id,\n 'include': newValue,\n 'required': g.required,\n }\n }])[0].catch(notification.exception);\n },\n requiredChanged(newValue, g) {\n call([{\n methodname: 'local_treestudyplan_include_grade',\n args: {\n 'grade_id': g.id,\n 'item_id': this.value.id,\n 'include': g.selected,\n 'required': newValue,\n }\n }])[0].catch(notification.exception);\n },\n updateConditions() {\n call([{\n methodname: 'local_treestudyplan_edit_studyitem',\n args: {\n 'id': this.value.id,\n 'conditions': this.value.conditions,\n }\n }])[0].catch(notification.exception);\n },\n },\n template: `\n <div class=\"t-item-course card\">\n <div class='t-item-course-cardwrapper mr-0 ml-0 h-100 '>\n <div\n :title=\"text['coursetiming_'+value.course.timing]\"\n v-b-popover.hover.top=\"startdate+' - '+enddate\"\n :class=\"'h-100 t-timing-indicator timing-'+value.course.timing\"\n ></div>\n <div class=\"t-item-course-title card-body h-100\">\n <fittext maxsize=\"12pt\" minsize=\"9pt\">\n <a v-b-modal=\"'t-item-course-config-'+value.id\"\n :id=\"'t-item-course-details-'+value.id\"\n :href=\"wwwroot+'/course/view.php?id='+value.course.id\"\n @click.prevent.stop=\"\">{{ value.course.displayname }}</a>\n </fittext>\n </div>\n <div class=\"h-100 t-item-course-indicator \">\n <a class=\"t-item-course-config\"\n v-b-modal=\"'t-item-course-config-'+value.id\"\n href=\"#\" @click.prevent=\"\"\n ><i :class=\"'fa fa-'+configurationIcon+' ' + configurationState\"></i></a>\n </div>\n </div>\n <b-modal class=\"\"\n :id=\"'t-item-course-config-'+value.id\"\n :title=\"value.course.displayname + ' - ' + value.course.fullname\"\n ok-only\n size=\"lg\"\n scrollable\n class=\"b-modal-justify-footer-between\"\n >\n <template #modal-header>\n <div>\n <h1><a :href=\"wwwroot+'/course/view.php?id='+value.course.id\" target=\"_blank\"\n ><i class=\"fa fa-graduation-cap\"></i> {{ value.course.fullname }}</a>\n <a v-if='!!value.course.completion'\n :href=\"wwwroot+'/course/completion.php?id='+value.course.id\" target=\"_blank\"\n :title=\"text.configure_completion\"><i class=\"fa fa-gear\"></i></a>\n </h1>\n {{ value.course.context.path.join(\" / \")}} / {{value.course.shortname}}\n </div>\n <div class=\"r-course-detail-header-right\">\n <div :class=\"'r-timing-'+value.course.timing\">\n {{text['coursetiming_'+value.course.timing]}}<br>\n {{ startdate }} - {{ enddate }}\n </div>\n <t-item-timing-checker\n class=\"mt-1\"\n :maxspan=\"maxspan\"\n :page=\"page\"\n :line=\"line\"\n :period=\"period\"\n v-model=\"value\"\n ></t-item-timing-checker>\n </div>\n </template>\n\n <s-course-extrafields\n v-if=\"value.course.extrafields\"\n v-model=\"value.course.extrafields\"\n position=\"above\"\n ></s-course-extrafields>\n <t-item-course-grades\n v-if='!!value.course.grades && value.course.grades.length > 0'\n v-model='value' :plan=\"plan\"\n ></t-item-course-grades>\n <t-item-course-completion\n v-if='!!value.course.completion'\n v-model='value.course.completion'\n :course='value.course'\n ></t-item-course-completion>\n <t-item-course-competency\n v-if='!!value.course.competency'\n v-model='value.course.competency'\n :item='value'\n ></t-item-course-competency>\n <s-course-extrafields\n v-if=\"value.course.extrafields\"\n v-model=\"value.course.extrafields\"\n position=\"below\"\n ></s-course-extrafields>\n <template #modal-footer=\"{ ok, cancel, hide }\" >\n <a href='#' @click.prevent='$emit(\"deleterq\")' class=\"text-danger\"\n ><i class=\"fa fa-trash\"></i>\n {{ text.delete }}\n </a>\n <b-button size=\"sm\" variant=\"primary\" @click.prevent=\"ok()\">\n {{ text.ok }}\n </b-button>\n </template>\n </b-modal>\n </div>\n `,\n });\n\n\n Vue.component('t-item-course-grades', {\n props: {\n 'value': {\n type: Object,\n default() {\n return null;\n },\n },\n 'plan': {\n type: Object,\n default() {\n return null;\n },\n },\n },\n data() {\n return {\n conditionOptions: stringKeys.conditions,\n text: strings.itemCourseText,\n };\n },\n computed: {\n useRequiredGrades() {\n if (this.plan && this.plan.aggregation_info && this.plan.aggregation_info.useRequiredGrades !== undefined) {\n return this.plan.aggregation_info.useRequiredGrades;\n } else {\n return false;\n }\n },\n selectedgrades() {\n let list = [];\n for (let ix in this.value.course.grades) {\n let g = this.value.course.grades[ix];\n if (g.selected) {\n list.push(g);\n }\n }\n return list;\n },\n },\n methods: {\n includeChanged(newValue, g) {\n call([{\n methodname: 'local_treestudyplan_include_grade',\n args: {\n 'grade_id': g.id,\n 'item_id': this.value.id,\n 'include': newValue,\n 'required': g.required,\n }\n }])[0].catch(notification.exception);\n },\n requiredChanged(newValue, g) {\n call([{\n methodname: 'local_treestudyplan_include_grade',\n args: {\n 'grade_id': g.id,\n 'item_id': this.value.id,\n 'include': g.selected,\n 'required': newValue,\n }\n }])[0].catch(notification.exception);\n },\n },\n template: `\n <div>\n <b-form-group\n :label=\"text.select_grades\"\n ><ul class=\"t-item-module-children\">\n <li class=\"t-item-course-gradeinfo\">\n <span class='t-item-course-chk-lbl'>{{text.grade_include}}</span\n ><span v-if=\"useRequiredGrades\" class='t-item-course-chk-lbl'>{{text.grade_require}}</span>\n </li>\n <li class=\"t-item-course-gradeinfo\" v-for=\"g in value.course.grades\">\n <b-form-checkbox inline\n @change=\"includeChanged($event,g)\" v-model=\"g.selected\"\n ></b-form-checkbox>\n <b-form-checkbox v-if=\"useRequiredGrades\" inline :disabled=\"!g.selected\"\n @change=\"requiredChanged($event,g)\" v-model=\"g.required\"\n ></b-form-checkbox>\n <span :title=\"g.typename\" v-html=\"g.icon\"></span>\n <s-edit-mod\n :title=\"value.course.fullname\"\n @saved=\"(fd) => g.name = fd.get('name')\"\n v-if=\"g.cmid > 0\"\n :cmid=\"g.cmid\"\n :coursectxid=\"value.course.ctxid\"\n genericonly><span v-html=\"g.name\"></span></s-edit-mod>\n </li>\n </ul>\n </b-form-group>\n </div>\n `,\n });\n\n Vue.component('t-item-course-completion', {\n props: {\n value: {\n type: Object,\n default() {\n return {};\n },\n },\n guestmode: {\n type: Boolean,\n 'default': false,\n },\n course: {\n type: Object,\n default() {\n return {};\n },\n },\n },\n data() {\n return {\n text: strings.completion,\n };\n },\n computed: {\n hasCompletions() {\n if (this.value.conditions) {\n for (const cgroup of this.value.conditions) {\n if (cgroup.items && cgroup.items.length > 0) {\n return true;\n }\n }\n }\n return false;\n },\n wwwroot() {\n return Config.wwwroot;\n }\n },\n methods: {\n completionIcon(completion) {\n switch (completion) {\n case \"progress\":\n return \"exclamation-circle\";\n case \"complete\":\n return \"check-circle\";\n case \"complete-pass\":\n return \"check-circle\";\n case \"complete-fail\":\n return \"times-circle\";\n default: // Case \"incomplete\"\n return \"circle-o\";\n }\n },\n completionTag(cgroup) {\n return cgroup.completion ? 'completed' : 'incomplete';\n }\n },\n template: `\n <table class=\"r-item-course-grade-details\">\n <tr v-if=\"hasCompletions\">\n <td colspan='2'><span v-if=\"value.aggregation == 'all'\">{{ text.aggregation_overall_all}}</span\n ><span v-else>{{ text.aggregation_overall_any}}</span></td>\n </tr>\n <tr v-else>\n <td colspan='2'>{{text.completion_not_configured}}!\n <br/><a :href=\"wwwroot+'/course/completion.php?id='+course.id\" target='_blank'>{{text.configure_completion}}</a>\n </td>\n </tr>\n <template v-for='cgroup in value.conditions'>\n <tr>\n <th colspan='2'><span v-if=\"cgroup.items.length > 1\"\n ><span v-if=\"cgroup.aggregation == 'all'\">{{ text.aggregation_all}}</span\n ><span v-else>{{ text.aggregation_any}}</span></span>\n {{cgroup.title}}</th>\n </tr>\n <tr v-for='ci in cgroup.items'>\n <td><span v-html='ci.details.criteria'></span>\n </td>\n <td v-if=\"ci.details.requirement\" class=\"font-italic\">\n {{ci.details.requirement}}\n </td>\n </tr>\n </template>\n </table>\n `,\n });\n\n // TAG: Course competency\n Vue.component('t-item-course-competency', {\n props: {\n value: {\n type: Object,\n default() {\n return {};\n },\n },\n guestmode: {\n type: Boolean,\n 'default': false,\n },\n item: {\n type: Object,\n default() {\n return {id: null};\n },\n }\n },\n data() {\n return {\n text: strings.competency,\n };\n },\n computed: {\n hasCompletions() {\n if (this.value.conditions) {\n for (const cgroup of this.value.conditions) {\n if (cgroup.items && cgroup.items.length > 0) {\n return true;\n }\n }\n }\n return false;\n },\n wwwroot() {\n return Config.wwwroot;\n }\n },\n methods: {\n pathtags(competency) {\n const path = competency.path;\n let s = \"\";\n for (const ix in path) {\n const p = path[ix];\n if (ix > 0) {\n s += \" / \";\n }\n let url;\n if (p.type == 'competency') {\n url = `/admin/tool/lp/competencies.php?competencyid=${p.id}`;\n } else {\n url = `/admin/tool/lp/competencies.php?competencyframeworkid=${p.id}&pagecontextid=${p.contextid}`;\n }\n s += `<a href=\"${url}\">${p.title}</a>`;\n }\n return s;\n },\n requiredChanged(newValue, c) {\n call([{\n methodname: 'local_treestudyplan_require_competency',\n args: {\n 'competency_id': c.id,\n 'item_id': this.item.id,\n 'required': newValue,\n }\n }])[0].catch(notification.exception);\n },\n },\n template: `\n <table class=\"t-item-course-competency-list\">\n <tr v-if=\"value.competencies.length == 0\">\n <td colspan='2'>{{text.competency_not_configured}}\n <br><a :href=\"wwwroot+'/admin/tool/lp/coursecompetencies.php?courseid='+item.course.id\" target='_blank'>{{text.configure_competency}}</a>\n </td>\n </tr>\n <template v-else>\n <tr class='t-item-course-competency-headers'>\n <th>{{text.heading}}</th>\n <th></th>\n <th>{{text.required}}</th>\n </tr>\n <tr v-for='c in value.competencies'>\n <td :colspan=\"(c.details)?1:2\"><a href='#' v-b-modal=\"'modal-competency-id-'+c.id\"><span v-html='c.title'></span></a></td>\n <td class='details' v-if=\"c.details\">\n <a href='#' v-b-modal=\"'modal-competency-id-'+c.id\"><span v-html='c.details'></span></a>\n </td>\n <td>\n <b-form-checkbox inline\n @change=\"requiredChanged($event,c)\"\n v-model=\"c.required\"\n >{{ text.required }}</b-form-checkbox>\n </td>\n <b-modal :id=\"'modal-competency-id-'+c.id\"\n size=\"lg\"\n ok-only\n centered\n scrollable\n >\n <template #modal-header>\n <div>\n <h1><i class=\"fa fa-puzzle-piece\"></i>\n <a :href=\"wwwroot+'/admin/tool/lp/competencies.php?competencyid='+c.id\" target=\"_blank\"\n >{{c.title}} {{c.details}} </a\n ></h1>\n <div><span v-html=\"pathtags(c)\"></span></div>\n </div>\n </template>\n <div class=\"mb-2\" v-if=\"c.description\"><span v-html='c.description'></span></div>\n\n <template v-if=\"c.rule && c.children\">\n <div>{{ c.ruleoutcome }} {{ text.when}} <span v-html=\"c.rule.toLocaleLowerCase()\"></span></div>\n <table v-if=\"c.children\" class='t-item-course-competency-list'>\n <tr class='t-item-course-competency-headers'>\n <th>{{text.heading}}</th>\n <th></th>\n <th>{{text.required}}</th>\n </tr>\n <tr v-for=\"cc in c.children\">\n <td :colspan=\"(c.details)?1:2\" ><span v-html='cc.title'></span></td>\n <td class='details' v-if=\"cc.details\"><span v-html='cc.details'></span></td>\n <td><span class=\"text-info\">{{ cc.points }} {{ text.points }}</span></td>\n <td><span class=\"text-danger\" v-if='cc.required'>{{ text.required }}</span></td>\n </tr>\n </table>\n </template>\n </b-modal>\n </tr>\n </template>\n </table>\n `,\n });\n /* **********************************\n * *\n * Toolbox list components *\n * *\n ************************************/\n Vue.component('t-item-junction', {\n props: {\n value: {\n type: Object,\n default() {\n return {};\n },\n },\n },\n data() {\n return {\n conditionOptions: stringKeys.conditions,\n };\n },\n methods: {\n\n },\n template: `\n <div class='t-item-junction t-item-filter'>\n <i class=\"fa fa-check-circle\"></i>\n </div>\n `,\n });\n\n Vue.component('t-item-finish', {\n props: {\n value: {\n type: Object,\n default() {\n return {};\n },\n },\n },\n data() {\n return {\n };\n },\n methods: {\n },\n template: `\n <div class='t-item-finish t-item-filter'>\n <i class=\"fa fa-stop-circle\"></i>\n </div>\n `,\n });\n\n Vue.component('t-item-start', {\n props: {\n value: {\n type: Object,\n default() {\n return {};\n },\n },\n },\n data() {\n return {};\n },\n methods: {\n },\n template: `\n <div class='t-item-start t-item-filter'>\n <i class=\"fa fa-play-circle\"></i>\n </div>\n `,\n });\n\n Vue.component('t-item-badge', {\n props: {\n value: {\n type: Object,\n default() {\n return {\n badge: {}\n };\n },\n },\n },\n data() {\n return {\n txt: strings,\n text: strings.itemText,\n };\n },\n methods: {\n },\n template: `\n <div class='t-item-badge t-item-filter' v-b-tooltip.hover :title=\"value.badge.name\">\n <svg class=\"t-badge-backdrop \" width='50px' height='50px' viewBox=\"0 0 100 100\">\n <title>{{value.badge.name}}</title>\n <circle cx=\"50\" cy=\"50\" r=\"46\"\n style=\"stroke: currentcolor; stroke-width: 4; fill: currentcolor; fill-opacity: 0.5;\"/>\n <image class=\"badge-image\" clip-path=\"circle() fill-box\"\n :href=\"value.badge.imageurl\" x=\"12\" y=\"12\" width=\"76\" height=\"76\"/>\n </svg>\n <a class=\"t-item-config badge\"\n v-b-modal=\"'t-item-badge-details-'+value.id\" href=\"#\" @click.prevent=\"\"><i class=\"fa fa-gear\"></i></a>\n <b-modal class=\"\"\n :id=\"'t-item-badge-details-'+value.id\"\n :title=\"value.badge.name\"\n size=\"lg\"\n ok-only\n centered\n scrollable\n class=\"b-modal-justify-footer-between\"\n >\n <template #modal-header>\n <div>\n <h1><i class=\"fa fa-certificate\"></i>\n <a :href=\"value.badge.infolink\" target=\"_blank\"\n >{{ value.badge.name }}</a\n ></h1>\n </div>\n </template>\n <b-container fluid>\n <b-row><b-col cols=\"3\">\n <img :src=\"value.badge.imageurl\"/>\n </b-col><b-col cols=\"9\">\n <p>{{value.badge.description}}</p>\n <ul class=\"list-unstyled w-100 border-grey border-top border-bottom pt-1 pb-1 mb-1\"\n v-if=\"value.badge.criteria\"><li v-for=\"crit in value.badge.criteria\"\n ><span v-html='crit'></span></li></ul>\n <p><strong><i class=\"fa fa-link\"></i>\n <a :href=\"value.badge.infolink\">{{ txt.badge.badgeinfo }}</a></strong></p>\n </b-col></b-row>\n </b-container>\n <template #modal-footer=\"{ ok, cancel, hide }\" >\n <a href='#' @click.prevent='$emit(\"deleterq\")' class=\"text-danger\"\n ><i class=\"fa fa-trash\"></i>\n {{ text.delete }}\n </a>\n <b-button size=\"sm\" variant=\"primary\" @click.prevent=\"ok()\">\n {{ text.ok }}\n </b-button>\n </template>\n </b-modal>\n\n </div>\n `,\n });\n\n Vue.component('t-coursecat-list', {\n props: {\n value: {\n type: Array,\n default() {\n return {};\n },\n },\n },\n data() {\n return {\n };\n },\n methods: {\n },\n template: `\n <ul class=\"t-coursecat-list\">\n <t-coursecat-list-item\n v-for=\"coursecat,idx in value\"\n v-model=\"value[idx]\"\n :key=\"coursecat.id\"></t-coursecat-list-item>\n </ul>\n `,\n });\n\n Vue.component('t-coursecat-list-item', {\n props: {\n value: {\n type: Object,\n default() {\n return {};\n },\n },\n },\n data() {\n return {\n loading: false,\n\n };\n },\n computed: {\n showSpinner() {\n return this.canLoadMore();\n },\n hasDetails() {\n return (this.value.haschildren || this.value.hascourses);\n }\n\n },\n methods: {\n canLoadMore() {\n return (this.value.haschildren && (!this.value.children)) ||\n (this.value.hascourses && (!this.value.courses));\n },\n onShowDetails() {\n const self = this;\n if (this.canLoadMore()) {\n call([{\n methodname: 'local_treestudyplan_get_category',\n args: {\n \"id\": this.value.id,\n }\n }])[0].then((response) => {\n self.$emit('input', response);\n return;\n }).catch(notification.exception);\n }\n }\n },\n template: `\n <li class=\"t-coursecat-list-item\">\n <span v-if=\"hasDetails\" v-b-toggle=\"'coursecat-'+value.id\">\n <i class=\"when-closed fa fa-caret-right t-caret\"></i>\n <i class=\"when-open fa fa-caret-down t-caret\"></i>\n <span class=\"t-coursecat-heading\">\n <i class=\"t-coursecat-list-item fa fa-tasks\"></i>\n {{ value.category.name }}\n </span>\n </span>\n <span v-else>\n <i class=\"when-closed fa t-caret\" style=\"visibility: hidden\"></i>\n <span class=\"t-coursecat-heading\">\n <i class=\"t-coursecat-list-item fa fa-tasks\"></i>\n {{ value.category.name }}\n </span>\n </span>\n <b-collapse v-if=\"hasDetails\" :id=\"'coursecat-'+value.id\"\n @show=\"onShowDetails\" :visible=\"!!(value.children) || !!(value.courses)\">\n <b-spinner class=\"ml-4\" v-if=\"showSpinner\" small variant=\"primary\"></b-spinner>\n <t-coursecat-list v-if=\"value.children\" v-model=\"value.children\"></t-coursecat-list>\n <t-course-list v-if=\"value.courses\" v-model=\"value.courses\"></t-course-list>\n </b-collapse>\n </li>\n `,\n });\n\n Vue.component('t-course-list', {\n props: {\n value: {\n type: Array,\n default() {\n return {};\n },\n },\n },\n data() {\n return {\n };\n },\n methods: {\n makeType() {\n return {\n item: false,\n component: true,\n span: 1, // TODO: Detect longer courses and give them an appropriate span\n type: 'gradable',\n };\n },\n },\n template: `\n <ul class=\"t-course-list\">\n <li class=\"t-course-list-item\" v-for=\"course in value\" :key=\"course.id\">\n <span class='t-course-heading'>\n <drag\n class=\"draggable-course\"\n :data=\"course\"\n :type=\"makeType()\"\n @cut=\"\"\n >\n <i class=\"t-course-list-item fa fa-book\"></i> {{ course.shortname }} - {{ course.fullname }}\n </drag>\n </span>\n </li>\n </ul>\n `,\n });\n\n Vue.component('t-toolbox', {\n props: {\n value: {\n type: Boolean,\n 'default': true,\n },\n activepage: {\n type: Object,\n default() {\n return null;\n }\n },\n coaching: {\n type: Boolean,\n 'default': false,\n },\n studyplanid: {\n type: Number,\n 'default': 0,\n }\n },\n data() {\n return {\n toolboxright: !(settings(\"toolboxleft\")),\n toolboxcoursesonly: settings(\"toolboxcoursesonly\"),\n enablebadges: settings(\"enablebadges\"),\n allowcoursebadges: settings(\"badges_allowcoursebadges\"),\n text: strings.toolbox,\n relatedbadges: [],\n systembadges: [],\n courses: [],\n filters: {\n courses: \"\",\n systembadges: \"\",\n relatedbadges: \"\",\n },\n loadingcourses: false,\n loadingcategories: [],\n badgelistshown: {\n relatedbadges: true,\n systembadges: false,\n }\n };\n },\n watch: {\n // Whenever activepage changes, this function will run\n activepage(/* Params newVal, oldVal */) {\n this.filterRelatedbadges();\n }\n },\n mounted() {\n const self = this;\n this.initialize();\n\n this.$root.$on('bv::collapse::state', (collapseId, isJustShown) => {\n self.badgelistshown[collapseId] = !!isJustShown;\n });\n },\n computed: {\n filterComponentType() {\n return {\n item: false,\n component: true,\n span: 1,\n type: 'filter',\n };\n },\n filteredCourses() {\n const self = this;\n if (self.filters.courses) {\n return self.filterCategories(self.courses);\n } else {\n return self.courses;\n }\n }\n },\n methods: {\n hivizdrop() {\n return settings(\"hivizdropslots\");\n },\n filterCategories(catlist) {\n const self = this;\n const list = [];\n const search = new RegExp(`.*?${self.filters.courses}.*?`, \"ig\");\n for (const cat of catlist) {\n const clone = Object.assign({}, cat);\n clone.courses = [];\n\n if (cat.courses) {\n for (const course of cat.courses) {\n if (search.test(course.shortname) || search.test(course.fullname)) {\n clone.courses.push(course);\n }\n }\n } else if (cat.hascourses && !(self.loadingcategories.includes(cat.id))) {\n self.loadingcategories.push(cat.id);\n debug.info(`Loading from category ${cat.category.name}`, cat);\n call([{\n methodname: 'local_treestudyplan_get_category',\n args: {\n \"id\": cat.id\n }\n }])[0].then((response) => {\n // Add reactive array 'children' to cat\n self.$set(cat, \"children\", response.children);\n self.$set(cat, \"courses\", response.courses);\n self.loadingcategories.splice(self.loadingcategories.indexOf(cat.id), 1);\n return;\n }).catch(notification.exception);\n }\n\n if (cat.children) {\n clone.children = self.filterCategories(cat.children);\n } else if (cat.haschildren && !(self.loadingcategories.includes(cat.id))) {\n self.loadingcategories.push(cat.id);\n debug.info(`Loading from category ${cat.category.name}`, cat);\n call([{\n methodname: 'local_treestudyplan_get_category',\n args: {\n \"id\": cat.id,\n }\n }])[0].then((response) => {\n // Add reactive array 'children' to cat\n self.$set(cat, \"children\", response.children);\n self.loadingcategories.splice(self.loadingcategories.indexOf(cat.id), 1);\n return;\n }).catch(notification.exception);\n }\n\n if ((clone.children && clone.children.length) || clone.courses.length) {\n list.push(clone);\n }\n }\n\n return list;\n },\n\n initialize() {\n const self = this;\n self.loadingcourses = true;\n debug.info(\"Toolbox Loading courses and categories\");\n call([{\n methodname: 'local_treestudyplan_map_categories',\n args: {\n 'studyplan_id': self.studyplanid,\n }\n }])[0].then((response) => {\n debug.info(\"Toolbox got courses and categories\", response);\n self.courses = response;\n self.loadingcourses = false;\n return;\n }).catch(notification.exception);\n\n if (!this.toolboxcoursesonly && this.enablebadges) {\n this.filterSystembadges();\n if (this.allowcoursebadges) {\n this.filterRelatedbadges();\n }\n }\n },\n filterSystembadges() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_search_badges',\n args: {\n search: this.filters.systembadges || \"\",\n }\n }])[0].then((response) => {\n self.systembadges = response;\n return;\n }).catch(notification.exception);\n },\n filterRelatedbadges() {\n const self = this;\n if (this.activepage) {\n call([{\n methodname: 'local_treestudyplan_search_related_badges',\n args: {\n 'page_id': this.activepage.id,\n search: this.filters.relatedbadges || \"\"\n }\n }])[0].then((response) => {\n self.relatedbadges = response;\n return;\n }).catch(notification.exception);\n }\n },\n resetSystembadges() {\n this.filters.systembadges = \"\";\n this.filterSystembadges();\n },\n resetRelatedbadges() {\n this.filters.relatedbadges = \"\";\n this.filterRelatedbadges();\n },\n },\n template: `\n <div class=\"t-toolbox\">\n <p-sidebar\n class=\"t-toolbox-sidebar\"\n :right='toolboxright'\n shadow\n v-model=\"value\"\n offsetRef=\"#page\"\n >\n <div class=\"pt-3 pl-3 pr-3 border-bottom-1 border-primary\"><h3>{{text.toolbox}}</h3></div>\n <div class='t-toolbox-preface'>\n <b-form-checkbox v-model=\"toolboxright\" switch>{{text.toolbarRight}}</b-form-checkbox>\n </div>\n <b-tabs content-class='mt-3' class=\"t-toolbox-tabs\">\n <b-tab :title=\"text.courses\" class=\"t-toolbox-tab\">\n <div v-if=\"loadingcourses\"\n ><div class=\"spinner-border text-primary\" role=\"status\"></div\n ></div>\n <div v-else class=\"ml-2 t-toolbox-courses\">\n <div class=\"flex-grow-0\">\n <input v-model=\"filters.courses\" :placeholder=\"text.filter\"></input>\n &nbsp; <a @click=\"filters.courses = ''\" v-if=\"filters.courses\" href='#'\n ><i class='fa fa-times'></i></a\n ><b-spinner small v-if=\"loadingcategories.length > 0\" variant=\"primary\"></b-spinner>\n </div>\n <div class=\"t-toolbox-courselist\">\n <t-coursecat-list v-model=\"filteredCourses\"></t-coursecat-list>\n </div>\n </div>\n </b-tab>\n <b-tab :title=\"text.flow\" v-if=\"!toolboxcoursesonly\" class=\"t-toolbox-tab\">\n <ul class=\"t-flow\">\n <li><drag\n :type=\"filterComponentType\"\n :data=\"{type: 'junction'}\"\n @cut=\"\"\n ><t-item-junction></t-item-junction>{{ text.toolJunction }}\n <template v-slot:drag-image=\"{data}\"><t-item-junction></t-item-junction></template>\n </drag></li>\n <li><drag\n :type=\"filterComponentType\"\n :data=\"{type: 'finish'}\"\n @cut=\"\"\n ><t-item-finish></t-item-finish>{{ text.toolFinish }}\n <template v-slot:drag-image=\"{data}\"><t-item-finish></t-item-finish></template>\n </drag></li>\n <li><drag\n :type=\"filterComponentType\"\n :data=\"{type: 'start'}\"\n @cut=\"\"\n ><t-item-start></t-item-start>{{ text.toolStart }}\n <template v-slot:drag-image=\"{data}\"><t-item-start></t-item-start></template>\n </drag></li>\n </ul>\n </b-tab>\n <b-tab :title=\"text.badges\" v-if=\"!toolboxcoursesonly && enablebadges\" class=\"t-toolbox-tab\">\n\n <b-tabs content-class='mt-2 ml-2' class=\"t-toolbox-badges\">\n <b-tab :title=\"text.relatedbadges\" v-if=\"allowcoursebadges\">\n <div class=\"t-toolbox-badges-filter\">\n <input v-model=\"filters.relatedbadges\" @input=\"filterRelatedbadges\" :placeholder=\"text.filter\"></input>\n &nbsp;<a @click=\"resetRelatedbadges\" v-if=\"filters.relatedbadges\" href='#'\n ><i class='fa fa-times'></i></a>\n </div>\n <div class=\"t-toolbox-badges-list\">\n <ul class=\"t-badges\">\n <li v-for=\"b in relatedbadges\"><drag\n class=\"t-badge-drag\"\n :type=\"filterComponentType\"\n :data=\"{type: 'badge', badge: b}\"\n @cut=\"\"\n ><img :class=\"(!b.active)?'disabled':''\" :src=\"b.imageurl\" :alt=\"b.name\">\n <span :class=\"(!b.active)?'disabled':''\">{{b.name}}</span>\n <template v-slot:drag-image=\"{data}\"\n ><img :class=\"(!b.active)?'disabled':''\" :src=\"b.imageurl\" :alt=\"b.name\"\n ></template>\n </drag></li>\n </ul>\n </div>\n </b-tab>\n <b-tab :title=\"text.sitebadges\">\n <div class=\"t-toolbox-badges-filter\">\n <input v-model=\"filters.systembadges\" @input=\"filterSystembadges\" :placeholder=\"text.filter\"></input>\n &nbsp; <a @click=\"resetSystembadges\" v-if=\"filters.systembadges\" href='#'\n ><i class='fa fa-times'></i></a>\n </div>\n <div class=\"t-toolbox-badges-list\">\n <ul class=\"t-badges\">\n <li v-for=\"b in systembadges\"><drag\n class=\"t-badge-drag\"\n :type=\"filterComponentType\"\n :data=\"{type: 'badge', badge: b}\"\n @cut=\"\"\n ><img :class=\"(!b.active)?'disabled':''\" :src=\"b.imageurl\" :alt=\"b.name\">\n <span :class=\"(!b.active)?'disabled':''\">{{b.name}}</span>\n <template v-slot:drag-image=\"{data}\"\n ><img :class=\"(!b.active)?'disabled':''\" :src=\"b.imageurl\" :alt=\"b.name\"\n ></template>\n </drag></li>\n </ul>\n </div>\n </b-tab>\n </b-tabs>\n </b-tab>\n </b-tabs>\n </p-sidebar>\n </div>\n `,\n });\n\n },\n\n};\n"],"names":["STUDYPLAN_EDITOR_FIELDS","PERIOD_EDITOR_FIELDS","install","Vue","component","Drag","Drop","DropList","use","TSComponents","mFormComponents","pSideBarComponents","FitTextVue","debug","Debugger","isVisible","elem","offsetWidth","offsetHeight","getClientRects","length","ItemEventBus","stringKeys","conditions","value","textkey","strings","studyplanText","add","edit","associations","drophere","studylineConfirmRemove","studyplanConfirmRemove","studyplanAdvanced","success","error","currentpage","studyplanEdit","warning","periodEdit","fullname","shortname","startdate","enddate","courseTiming","title","desc","question","course","period","yes","no","duration","years","year","weeks","week","days","day","rememberchoice","hidewarning","periodspan","periods","studyplanAssociate","cohorts","users","coaches","selected","name","context","search","itemText","ok","itemCourseText","cancel","noenddate","invalid","completion","competency","when","required","points","heading","details","badge","dateissued","dateexpire","badgeinfo","toolbox","toolbarRight","courses","flow","toolJunction","toolFinish","toolStart","badges","relatedbadges","filter","sitebadges","props","type","Object","default","selectedpage","data","forceScales","selectedScale","result","text","computed","scales","id","disabled","this","advanced_pick_scale","concat","advanced","force_scales","methods","forceScalesStart","self","$bvModal","msgBoxConfirm","advanced_force_scale_confirm","okVariant","okTitle","confirm_ok","cancelTitle","confirm_cancel","then","methodname","args","response","catch","notification","exception","exportPage","format","undefined","includes","content","exportPlan","bulkCourseTiming","location","reload","msgBoxOk","msg","importStudylines","filename","importPages","purgeStudyplan","force","purgeStudyplanpage","cascadeCohortsync","advanced_cascade_cohortsync","modalClose","template","String","Number","planSaved","updatedplan","info","mode","$emit","movedFrom","context_id","movedTo","moved","pages","updatedpage","page","info_periodsextended","centered","show","config","userfields","key","cohortfields","association","loading","associated","showModal","loadAssociations","cohortOptionModel","c","path","join","userOptionModel","u","firstname","lastname","map","searchCohorts","searchtext","like","cohortAssociate","searchselected","i","r","cohortDisassociate","associatedselected","searchUsers","userAssociate","userDisassociate","searchCoaches","coachAssociate","coachDisassociate","editdata","Date","getFullYear","editStart","editFinish","refresh","addDay","date","subDay","Boolean","create","studyline","color","enrol","enrollable","enrolroles","toolboxShown","editmode","original","availableroles","studyplan","description","slots","aggregation","useRequiredGrades","useItemCondition","cache","linelayers","selectedpageindex","emptyline","filterslots","courseslots","created","$on","mounted","studylines","coaching","$root","beforeUnmount","deactivated","activated","updated","hivizdrop","columns","columnsStylerule","s","trashbinAccepts","item","countLineLayers","line","timestamp","maxLayer","ix","layer","filters","slotsempty","Array","isArray","count","movedStudyplan","plan","from","to","addStudyLine","newlineinfo","push","editLineStart","assign","editLineFinish","editedline","originalline","deleteLine","replace","delete","modalresponse","index","indexOf","splice","reorderLines","event","lines","apply","sequence","idx","deletePlan","studyplabConfirmRemove","deleteStudyItem","source","showslot","layeridx","forGradable","list","span","periodEdited","pi","prev","$refs","next","toolboxSwitched","pagecreated","selectedpageChanged","newTabIndex","sumLineLayers","sum","slot","onDrop","lineslot","nextlayer","itm","$nextTick","timingChecker","validateCoursePeriod","checkTypeCourse","checkTypeFilter","layers","layerHeights","onLineHeightChange","lineid","main","items","document","querySelectorAll","heightSum","forEach","el","height","getBoundingClientRect","heightStyle","style","deletable","editable","onEdit","onDelete","slotindex","resizeListener","ResizeObserver","size","observe","unmounted","disconnect","slotkey","itemidx","listtype","courseHoverDummy","hover","spanCss","plantext","datechanger","coursespan","defaultchoice","hidewarn","relocateStudyItem","onCut","iteminfo","onDragEnter","onDragLeave","maxSpan","makeType","checkType","maxspan","hidden","endperiod","endperiodnr","Math","min","perioddesc","coursePeriodMatches","timeless","first","getTime","last","warn","floor","random","now","toString","globals","canupdatecourse","defaultvalue","changeCoursePeriod","timing","checkFilterSlotBusy","nextFreeFilterLayer","usedLayers","nextlyr","checkCourseSlotBusy","nextFreeCourseLayer","shiftCollisions","busyFilter","busyCourse","changeSpan","formatDuration","dsi","toLocaleLowerCase","dummy","dragLine","dragEventListener","deleteMode","conditionOptions","showContext","dragStart","start","getElementById","dragelement","position","left","x","top","y","SimpleLine","gravity","end","addEventListener","onMouseMove","dragEnd","remove","removeProperty","removeEventListener","clientX","clientY","fromid","toid","redrawLines","conn","from_id","to_id","connections","in","redrawLine","removeLine","out","highlight","setConfig","normalize","updateItem","continuation_id","doShowContext","hasContext","preventDefault","onCreatedConnection","onRemovedConnection","cin","onRePositioned","onDisPositioned","reid","onItemDeleted","itemid","onRedrawLines","deleteItem","msgparams","displayname","item_delete_message","err","console","hasConnectionsOut","hasConnectionsIn","setTimeout","beforeDestroy","$off","useItemConditions","aggregation_info","configurationState","hasGrades","hasCompletions","hasCompetencies","configurationIcon","wwwroot","Config","grades","g","cgroup","competencies","includeChanged","newValue","requiredChanged","updateConditions","selectedgrades","guestmode","completionIcon","completionTag","pathtags","p","url","contextid","txt","showSpinner","canLoadMore","hasDetails","haschildren","hascourses","children","onShowDetails","activepage","studyplanid","toolboxright","toolboxcoursesonly","enablebadges","allowcoursebadges","systembadges","loadingcourses","loadingcategories","badgelistshown","watch","filterRelatedbadges","initialize","collapseId","isJustShown","filterComponentType","filteredCourses","filterCategories","catlist","RegExp","cat","clone","test","category","$set","filterSystembadges","resetSystembadges","resetRelatedbadges"],"mappings":"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"}