1 line
266 KiB
Plaintext
1 line
266 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-disable no-trailing-spaces */\n/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n\nimport {SimpleLine} from \"./simpleline/simpleline\";\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\nimport {get_strings} from 'core/str';\nimport {load_stringkeys, load_strings, strformat } from './util/string-helper';\nimport {format_date, add_days, 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';\n/* import {eventTypes as editSwEventTypes} from 'core/edit_switch'; */\nimport { premiumenabled } from \"./util/premium\";\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\n\n\nconst STUDYPLAN_EDITOR_FIELDS =\n['name','shortname','description','idnumber','context_id', 'aggregation','aggregation_config'];\nconst STUDYPLAN_EDITOR_PAGE_FIELDS = // TODO: Add 'fullname', 'shortname' and 'description' when implementing proper page management\n['context_id', 'periods','startdate','enddate'];\nconst PERIOD_EDITOR_FIELDS =\n['fullname','shortname','startdate','enddate'];\n\nconst LINE_GRAVITY = 1.3;\n\nconst datechanger_globals = {\n default: false,\n defaultchoice: false,\n hidewarn: false,\n};\nexport default {\n STUDYPLAN_EDITOR_FIELDS: STUDYPLAN_EDITOR_FIELDS, // make copy available in plugin\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 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 string_keys = load_stringkeys({\n conditions: [\n { value: 'ALL', textkey: 'condition_all'},\n { value: 'ANY', textkey: 'condition_any'},\n ],\n });\n\n let strings = load_strings({\n studyplan_text: {\n studyline_editmode: 'studyline_editmode',\n toolbox_toggle: 'toolbox_toggle',\n editmode_modules_hidden:'editmode_modules_hidden',\n studyline_add: 'studyline_add',\n add$core: 'add$core',\n edit$core: 'edit$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 },\n studyplan_advanced: {\n advanced_tools: 'advanced_tools',\n confirm_cancel: 'confirm_cancel',\n confirm_ok: 'confirm_ok',\n success$core: 'success$core',\n error$core: 'failed$core',\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 studyplan_edit: {\n studyplan_edit: '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 period_edit: {\n edit: 'period_edit',\n fullname: 'studyplan_name',\n shortname: 'studyplan_shortname',\n startdate: 'studyplan_startdate',\n enddate: 'studyplan_enddate',\n },\n course_timing: {\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 studyplan_associate: {\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 item_text: {\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 item_course_text: {\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 relatedbages: 'relatedbages@badges',\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(){ return null;},\n },\n selectedpage: {\n type: Object,\n default(){ return null;},\n }\n\n },\n data() {\n return {\n force_scales: {\n selected_scale: null,\n result: [],\n },\n text: strings.studyplan_advanced,\n };\n },\n created() {\n },\n mounted() {\n },\n updated() {\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 force_scales_start(){\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.force_scales.selected_scale,\n }\n }])[0].then(function(response){\n self.force_scales.result = response;\n }).catch(notification.exception);\n }\n });\n },\n export_page(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(function(response){\n\n download(self.value.shortname+\".page.\"+format,response.content,response.format);\n }).catch(notification.exception);\n },\n export_plan(){\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(function(response){\n download(self.value.shortname+\".plan.json\",response.content,response.format);\n }).catch(notification.exception);\n },\n bulk_course_timing() {\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(function(response){\n if(response.success){\n // Reloading the webpage saves trouble reloading the specific page updated.\n location.reload();\n } else {\n this.$bvModal.msgBoxOk(response.msg, {title: \"Could not set bulk course timing\"} );\n debug.error(\"Could not set bulk course timing: \",response.msg);\n }\n }).catch(notification.exception);\n },\n import_studylines(){\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(function(response){\n if(response.success){\n location.reload();\n } else {\n this.$bvModal.msgBoxOk(response.msg, {title: \"Import failed\"} );\n debug.error(\"Import failed: \",response.msg);\n }\n }).catch(notification.exception);\n }, \"application/json\");\n },\n import_pages(){\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(function(response){\n if(response.success){\n location.reload();\n } else {\n this.$bvModal.msgBoxOk(response.msg, {title: \"Import failed\"} );\n debug.error(\"Import failed: \",response.msg);\n }\n }).catch(notification.exception);\n }, \"application/json\");\n },\n purge_studyplan(){\n call([{\n methodname: 'local_treestudyplan_delete_studyplan',\n args: {\n id: this.value.id,\n force: true,\n },\n }])[0].then(function(response){\n if(response.success){\n location.reload();\n } else {\n this.$bvModal.msgBoxOk(response.msg, {title: \"Could not delete plan \"} );\n debug.error(\"Could not delete plan: \",response.msg);\n }\n }).catch(notification.exception);\n },\n purge_studyplanpage(){\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(function(response){\n if(response.success){\n location.reload();\n } else {\n this.$bvModal.msgBoxOk(response.msg, {title: \"Could not delete page\"} );\n debug.error(\"Could not delete page: \",response.msg);\n }\n }).catch(notification.exception);\n }\n },\n cascade_cohortsync(){\n const self = this;\n call([{\n methodname: 'local_treestudyplan_cascade_cohortsync',\n args: {\n studyplan_id: this.value.id,\n },\n }])[0].then(function(response){\n self.$bvModal.msgBoxOk(response.success?self.text.success$core:self.text.error$core,\n { title: self.text.advanced_cascade_cohortsync});\n }).catch(notification.exception);\n },\n modal_close(){\n this.force_scales.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=\"modal_close\"\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=\"cascade_cohortsync\"\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=\"bulk_course_timing\"\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=\"force_scales.selected_scale\"\n :options=\"scales\" text-field=\"name\" value-field=\"id\"\n ></b-form-select>\n <b-button\n variant=\"danger\"\n :disabled=\"force_scales.selected_scale == null\"\n @click.prevent=\"force_scales_start\"\n >{{ text.advanced_force_scale_button}}</b-button>\n </p>\n <p class=\"mt-2\">\n <ul class='t-advanced-scrollable' v-if=\"force_scales.result.length > 0\">\n <li v-for=\"c in force_scales.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=\"export_page('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=\"export_plan('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=\"import_studylines\"\n >{{ text.advanced_restore_lines}}</b-button></p>\n <p><b-button\n variant=\"danger\"\n @click.prevent=\"import_pages\"\n >{{ text.advanced_restore_pages }}</b-button></p>\n <h3>{{ text.advanced_export }}</h3>\n <p><b-button\n variant=\"primary\"\n @click.prevent=\"export_page('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=\"purge_studyplanpage\"\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=\"purge_studyplan\"\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(){ return null;},\n },\n 'mode' :{\n type: String,\n default() { return \"edit\";},\n },\n 'type' :{\n type: String,\n default() { return \"link\";},\n },\n 'variant' : {\n type: String,\n default() { return \"\";},\n },\n 'contextid': {\n type: Number,\n default: 1\n },\n },\n data() {\n return {\n text: strings.studyplan_edit,\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 }\n else {\n // determine if the plan moved context...\n const moved_from = self.value.context_id;\n const moved_to = updatedplan.context_id;\n const moved = (moved_from != moved_to);\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(function(response){\n self.value = ProcessStudyplan(response,true);\n debug.info('studyplan processed');\n self.$emit('input',self.value);\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, moved_from, moved_to);\n }\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.studyplan_edit\"\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(){ return null;},\n },\n 'mode' :{\n type: String,\n default() { return \"edit\";},\n },\n 'type' :{\n type: String,\n default() { return \"link\";},\n },\n 'variant' : {\n type: String,\n default() { return \"\";},\n },\n 'studyplan': {\n type: Object,\n },\n },\n data() {\n return {\n text: strings.studyplan_edit,\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 }\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 ,\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.studyplan_associate,\n };\n },\n created() {\n\n },\n mounted() {\n },\n updated() {\n\n },\n methods: {\n premiumenabled,\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: { studyplan_id: self.value.id,}\n }])[0].then(function(response){\n self.association.users = response.map(self.userOptionModel);\n self.loading.users = false;\n }).catch(notification.exception);\n\n call([{\n methodname: 'local_treestudyplan_associated_cohorts',\n args: { studyplan_id: self.value.id,}\n }])[0].then(function(response){\n self.association.cohorts = response.map(self.cohortOptionModel);\n self.loading.cohorts = false;\n }).catch(notification.exception);\n\n if(premiumenabled()) {\n self.loading.coaches = true;\n call([{\n methodname: 'local_treestudyplan_associated_coaches',\n args: { studyplan_id: self.value.id,}\n }])[0].then(function(response){\n self.association.coaches = response.map(self.userOptionModel);\n self.loading.coaches = false;\n }).catch(notification.exception);\n }\n },\n searchCohorts(searchtext){\n const self = this;\n\n if(searchtext.length > 0)\n {\n call([{\n methodname: 'local_treestudyplan_list_cohort',\n args: { like: searchtext, studyplan_id: self.value.id}\n }])[0].then(function(response){\n self.search.cohorts = response.map(self.cohortOptionModel);\n }).catch(notification.exception);\n }\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 requests.push({\n methodname: 'local_treestudyplan_connect_cohort',\n args: {studyplan_id: self.value.id, cohort_id: r},\n fail: notification.exception,\n done: function(response){\n if(response.success){\n transportItem(associated,search,r);\n }\n }\n });\n }\n call(requests);\n },\n cohortDisassociate(){\n const self = this;\n let requests = [];\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 requests.push({\n methodname: 'local_treestudyplan_disconnect_cohort',\n args: {studyplan_id: self.value.id, cohort_id: r},\n fail: notification.exception,\n done: function(response){\n if(response.success){\n transportItem(search,associated,r);\n }\n }\n });\n }\n call(requests);\n },\n searchUsers(searchtext){\n const self = this;\n if(searchtext.length > 0)\n {\n call([{\n methodname: 'local_treestudyplan_find_user',\n args: { like: searchtext, studyplan_id: self.value.id}\n }])[0].then(function(response){\n self.search.users = response.map(self.userOptionModel);\n }).catch(notification.exception);\n }\n else {\n self.search.users = [];\n }\n },\n userAssociate(){\n const self = this;\n let requests = [];\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\n requests.push({\n methodname: 'local_treestudyplan_connect_user',\n args: {studyplan_id: self.value.id, user_id: r},\n fail: notification.exception,\n done: function(response){\n if(response.success){\n transportItem(associated,search,r);\n }\n }\n });\n }\n call(requests);\n },\n userDisassociate(){\n const self = this;\n let requests = [];\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\n requests.push({\n methodname: 'local_treestudyplan_disconnect_user',\n args: {studyplan_id: self.value.id, user_id: r},\n fail: notification.exception,\n done: function(response){\n if(response.success){\n transportItem(search,associated,r);\n }\n }\n });\n }\n call(requests);\n },\n searchCoaches(searchtext){\n if(premiumenabled()){\n const self = this;\n if(searchtext.length > 0)\n {\n call([{\n methodname: 'local_treestudyplan_find_coach',\n args: { like: searchtext, studyplan_id: self.value.id}\n }])[0].then(function(response){\n self.search.coaches = response.map(self.userOptionModel);\n }).catch(notification.exception);\n }\n else {\n self.search.coaches = [];\n }\n }\n },\n coachAssociate(){\n if(premiumenabled()){\n const self = this;\n let requests = [];\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 requests.push({\n methodname: 'local_treestudyplan_connect_coach',\n args: {studyplan_id: self.value.id, user_id: r},\n fail: notification.exception,\n done: function(response){\n if(response.success){\n transportItem(associated,search,r);\n }\n }\n });\n }\n call(requests);\n }\n },\n coachDisassociate(){\n if(premiumenabled()){\n const self = this;\n let requests = [];\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 requests.push({\n methodname: 'local_treestudyplan_disconnect_coach',\n args: {studyplan_id: self.value.id, user_id: r},\n fail: notification.exception,\n done: function(response){\n if(response.success){\n transportItem(search,associated,r);\n }\n }\n });\n }\n call(requests);\n }\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> {{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> {{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> {{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> {{text.add_association}}</b-button>\n </b-col>\n </b-row>\n </b-container>\n </b-tab>\n <b-tab :title=\"text.coaches\" v-if=\"premiumenabled()\">\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> {{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> {{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(){ return null;},\n },\n 'type' :{\n type: String,\n default() { return \"link\";},\n },\n 'variant' : {\n type: String,\n default() { return \"\";},\n },\n 'minstart' : {\n type: String,\n default() { return null;},\n },\n 'maxend' : {\n type: String,\n default() { return null;},\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.period_edit,\n };\n },\n created() {\n },\n mounted() {\n },\n updated() {\n\n },\n computed: {\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(function(response){\n objCopy(self.value,response,PERIOD_EDITOR_FIELDS);\n self.$emit('input',self.value);\n self.$emit('edited',self.value);\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(function(response){\n objCopy(self.value,response,PERIOD_EDITOR_FIELDS);\n self.$emit('input',self.value);\n }).catch(notification.exception);\n },\n add_day(date,days) {\n if( days === undefined ){\n days = 1;\n }\n return add_days(date,days);\n },\n sub_day(date,days) {\n if( days === undefined ){\n days = 1;\n }\n return add_days(date,0 - days);\n },\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=\"sub_day(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=\"add_day(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 toolbox_shown: 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.studyplan_text,\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(function(response){\n self.availableroles = response;\n }).catch(notification.exception);\n }\n this.$root.$emit('redrawLines');\n this.$emit('pagechanged',this.selectedpage);\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 premiumenabled,\n columns(page) {\n return 1+ (page.periods * 2);\n },\n columns_stylerule(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 trashbin_accepts(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 }\n else\n {\n let maxLayer = -1;\n for(let i = 0; i <= page.periods; i++){\n if(line.slots[i]){\n const slot = 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(function(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 }).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(function(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 }).catch(notification.exception);\n },\n deleteLine(page,line) {\n const self=this;\n get_strings([\n {key: 'studyline_confirm_remove', param: line.name, component: 'local_treestudyplan' },\n {key: 'delete', component: 'core' },\n ]).then(function(s){\n self.$bvModal.msgBoxConfirm(s[0], {\n okTitle: s[1],\n okVariant: 'danger',\n }).then(function(modalresponse){\n if(modalresponse){\n call([{\n methodname: 'local_treestudyplan_delete_studyline',\n args: { 'id': line.id, }\n }])[0].then(function(response){\n if(response.success == true){\n let index = page.studylines.indexOf(line);\n page.studylines.splice(index, 1);\n }\n }).catch(notification.exception);\n }\n });\n });\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 {\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(function(response){\n }).catch(notification.exception);\n },\n deletePlan(studyplan){\n const self=this;\n get_strings([\n {key: 'studyplan_confirm_remove', param: studyplan.name, component: 'local_treestudyplan' },\n {key: 'delete', component: 'core' },\n ]).then(function(s){\n self.$bvModal.msgBoxConfirm(s[0], {\n okTitle: s[1],\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(function(response){\n if(response.success == true){\n self.$root.$emit(\"studyplanRemoved\",studyplan);\n }\n }).catch(notification.exception);\n }\n });\n });\n },\n deleteStudyItem(event){\n //const self = this;\n let item = event.data;\n call([{\n methodname: 'local_treestudyplan_delete_studyitem',\n args: { 'id': item.id, }\n }])[0].then(function(response){\n if(response.success == true){\n event.source.$emit('cut',event);\n }\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){ // Really wish that 'for of' would work with the minifier moodle uses\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 add_day(date,days) {\n if( days === undefined ){\n days = 1;\n }\n return add_days(date,days);\n },\n sub_day(date,days) {\n if( days === undefined ){\n days = 1;\n }\n return add_days(date,0 - days);\n },\n toolbox_switched(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.validate_course_period();\n }\n });\n ItemEventBus.$emit('coursechange');\n }).catch(notification.exception);\n }\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 }).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 ,\n template:\n `\n <div>\n <t-toolbox v-model=\"edit.toolbox_shown\"\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=\"toolbox_switched(edit.toolbox_shown && !edit.studyline.editmode); \"\n >{{ text.studyline_editmode }}</b-form-checkbox>\n <b-form-checkbox \n v-if=\"!edit.studyline.editmode\" v-model=\"edit.toolbox_shown\" class=\"sw-studyplan-toolbar\" switch\n @change=\"toolbox_switched\"\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=\"trashbin_accepts\"\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> {{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> {{text.edit$core}}</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=\"columns_stylerule(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) ? add_day(page.perioddesc[index-2].startdate,2) : null\"\n :maxend=\"(index < page.periods) ? sub_day(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$core\"\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 <template v-if=\"premiumenabled()\">\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 </template> \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 <template v-if=\"premiumenabled()\">\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 </template>\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: function(){ return {};},\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,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 // 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: function(){ return {};},\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(){ return null;},\n },\n layer : {\n type: Number,\n },\n value: {\n type: Array, // dict with layer as index\n default(){ return [];},\n },\n plan: {\n type: Object, // Studyplan data\n default(){ return null;},\n },\n page: {\n type: Object, // Studyplan data\n default(){ return null;},\n },\n period: {\n type: Object, // Studyplan data\n default(){ return null;},\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 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.course_timing,\n plantext: strings.studyplan_text,\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).done(()=>{\n if(this.$refs.timingChecker){\n this.$refs.timingChecker.validate_course_period();\n }\n });\n }\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).done(()=>{\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.validate_course_period();\n }\n });\n ItemEventBus.$emit('coursechange');\n });\n }).catch(notification.exception);\n }\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).done(()=>{\n item.layer = this.layer;\n self.value.push(item);\n self.$emit(\"input\",self.value);\n });\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 + ' t-studyline-slot-'+slotindex + ' ' + ((slotindex==0)?' t-studyline-firstcolumn ':' ')\"\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 course_period_matches() {\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 }\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.course_timing,\n datechanger: {\n coursespan: null,\n periodspan: null,\n globals: datechanger_globals,\n }\n };\n },\n methods: {\n validate_course_period() {\n const self = this;\n\n if (! self.page.timeless) {\n debug.info(\"Validating course and period\");\n if(!(self.course_period_matches)){\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 // go for it without asking\n self.change_course_period();\n }\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 }\n else {\n debug.info(\"Course timing matches period\",self.datechanger);\n }\n }\n else {\n debug.info(\"Skipping course timing check because of timeless mode\",self.datechanger);\n }\n },\n has_filter() {\n const slots = this.page.slots;\n },\n change_course_period() {\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: { period_id: self.period.id,\n course_id: this.value.course.id,\n span: this.value.span,\n }\n }])[0].catch(notification.exception).done((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 });\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 shift_collisions(span) {\n // Check all periods for collision\n const shiftfilters = [];\n const shiftcourses = [];\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).done((response) => {\n \n });\n }\n },\n change_span(span) {\n const self=this;\n this.shift_collisions(span);\n return call([{\n methodname: 'local_treestudyplan_set_studyitem_span',\n args: { id: self.value.id,\n span: span\n }\n }])[0].catch(notification.exception).done((response) => {\n self.value.span = response.span;\n self.$emit('input',self.value);\n self.$nextTick(() => {\n self.validate_course_period();\n });\n } );\n },\n format_duration(dsi){\n let s = \"\";\n if(dsi.years == 1){ s += `1 ${this.text.year}, `;}\n else if(dsi.years > 1){ s += `${dsi.years} ${this.text.years}, `;}\n if(dsi.weeks == 1){ s += `1 ${this.text.week}, `;}\n else if(dsi.weeks > 1){ s += `${dsi.weeks} ${this.text.weeks}, `;}\n if(dsi.days == 1){ s += `1 ${this.text.day}, `;}\n else if(dsi.days > 1){ s += `${dsi.days} ${this.text.days}, `;}\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=\"course_period_matches\">\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=\"validate_course_period()\" 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 }} <b-form-select v-if=\"maxspan > 1\"\n class=\"\"\n size=\"sm\" @change=\"change_span\" 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> {{\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=\"change_course_period\"\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 {{ format_duration(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 {{ format_duration(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 {{ format_duration(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 {{ format_duration(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(){ return null;},\n },\n dummy :{\n type: Boolean,\n default() { return false;},\n },\n plan: {\n type: Object, // Studyplan page\n default() { return null;},\n },\n line: {\n type: Object, // Studyplan page\n default() { return null;},\n },\n page: {\n type: Object, // Studyplan page\n default() { return null;},\n },\n period: {\n type: Object, // Studyplan page\n default() { return null;},\n },\n maxspan: {\n type: Number,\n default() { return 0;},\n },\n },\n data() {\n return {\n dragLine: null,\n dragEventListener: null,\n deleteMode: false,\n condition_options: string_keys.conditions,\n text: strings.item_text,\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 from_id = event.data.id;\n let to_id = this.value.id;\n this.redrawLines();\n call([{\n methodname: 'local_treestudyplan_connect_studyitems',\n args: { 'from_id': from_id, 'to_id': to_id }\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 }).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 }).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: { 'id': this.value.id,\n 'conditions': this.value.conditions,\n 'continuation_id': this.value.continuation_id,}\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 c_in = this.value.connections.in[i];\n if(conn.id == c_in.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(re_id){\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 == re_id){\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(item_id){\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 == item_id){\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 == item_id){\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: { 'id': self.value.id, }\n }])[0].then(function(response){\n if(response.success == true){\n self.$emit(\"deleted\",{ data: self.value });\n }\n }).catch(notification.exception);\n }\n }).catch(err => {\n debug.console.error(err);\n });\n }\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\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 }\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 {\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 beforeUpdate(){\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=\"condition_options\"\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: function(){ return null;},\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(){ return null;},\n },\n plan:{\n type: Object,\n default(){ return null;},\n },\n line:{\n type: Object,\n default(){ return null;},\n },\n page: {\n type: Object, // PAge data\n default() { return null;}\n },\n period: {\n type: Object, // Period data\n default() { return null;}\n },\n maxspan: {\n type: Number,\n default() { return 0;}\n },\n },\n data() {\n return {\n condition_options: string_keys.conditions,\n text: strings.item_course_text,\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 }\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 format_date(this.value.course.startdate);\n },\n enddate(){\n if(this.value.course.enddate > 0){\n return format_date(this.value.course.enddate);\n }\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: { '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: { '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: { 'id': this.value.id,\n 'conditions': this.value.conditions,\n }\n }])[0].catch(notification.exception);\n },\n },\n created() {\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(){ return null;},\n },\n 'plan' :{\n type: Object,\n default(){ return null;},\n },\n },\n data() {\n return {\n condition_options: string_keys.conditions,\n text: strings.item_course_text,\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 }\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: { '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: { '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 created() {\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: function(){ return {};},\n },\n guestmode: {\n type: Boolean,\n default: false,\n },\n course: {\n type: Object,\n default: function(){ return {};},\n },\n },\n data() {\n return {\n text: strings.completion,\n };\n },\n created(){\n const self = this;\n // Get text strings for condition settings\n let stringkeys = [];\n for(const key in this.text){\n stringkeys.push({ key: key, component: 'local_treestudyplan'});\n }\n get_strings(stringkeys).then(function(strings){\n let i = 0;\n for(const key in self.text){\n self.text[key] = strings[i];\n i++;\n }\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 completion_icon(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\n completion_tag(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: function(){ return {};},\n },\n guestmode: {\n type: Boolean,\n default: false,\n },\n item: {\n type: Object,\n default: function(){ return { id: null};},\n }\n },\n data() {\n return {\n text: strings.competency,\n };\n },\n created(){\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 \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: { '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: function(){ return {};},\n },\n },\n data() {\n return {\n condition_options: string_keys.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: function(){ return {};},\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: function(){ return {};},\n },\n },\n data() {\n return {\n };\n },\n created(){\n\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: function(){ return { badge: {}};},\n },\n },\n data() {\n return {\n txt: strings,\n text: strings.item_text,\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: function(){ return {};},\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: function(){ return {};},\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: { \"id\": this.value.id}\n }])[0].then(function(response){\n self.$emit('input', response);\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: function(){ return {};},\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() { return null;}\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 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: function (newVal, oldVal) {\n this.filter_relatedbadges();\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: { \"id\": cat.id}\n }])[0].then(function(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 }).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: { \"id\": cat.id}\n }])[0].then(function(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 }).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 call([{\n methodname: 'local_treestudyplan_map_categories',\n args: { studyplan_id: self.studyplanid}\n }])[0].then(function(response){\n self.courses = response;\n self.loadingcourses = false;\n }).catch(notification.exception);\n this.filter_systembadges();\n this.filter_relatedbadges();\n },\n filter_systembadges() {\n const self = this;\n call([{\n methodname: 'local_treestudyplan_search_badges',\n args: { \n search: this.filters.systembadges || \"\"\n }\n }])[0].then(function(response){\n self.systembadges = response;\n }).catch(notification.exception);\n },\n filter_relatedbadges() {\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(function(response){\n self.relatedbadges = response;\n }).catch(notification.exception);\n }\n },\n reset_systembadges() {\n this.filters.systembadges = \"\";\n this.filter_systembadges();\n },\n reset_relatedbadges() {\n this.filters.relatedbadges = \"\";\n this.filter_relatedbadges();\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=\"m-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 <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\" 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\" class=\"t-toolbox-tab\">\n \n <b-tabs content-class='mt-2 ml-2' class=\"t-toolbox-badges\">\n <b-tab :title=\"text.relatedbages\">\n <div class=\"t-toolbox-badges-filter\">\n <input v-model=\"filters.relatedbadges\" @input=\"filter_relatedbadges\" :placeholder=\"text.filter\"></input>\n <a @click=\"reset_relatedbadges\" 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\" v-if=\"!coaching\">\n <div class=\"t-toolbox-badges-filter\">\n <input v-model=\"filters.systembadges\" @input=\"filter_systembadges\" :placeholder=\"text.filter\"></input>\n <a @click=\"reset_systembadges\" 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","datechanger_globals","default","defaultchoice","hidewarn","install","Vue","component","Drag","Drop","DropList","use","TSComponents","mFormComponents","pSideBarComponents","debug","Debugger","isVisible","elem","offsetWidth","offsetHeight","getClientRects","length","ItemEventBus","string_keys","conditions","value","textkey","strings","studyplan_text","studyline_editmode","toolbox_toggle","editmode_modules_hidden","studyline_add","add$core","edit$core","studyline_name","studyline_name_ph","studyline_shortname","studyline_shortname_ph","studyline_enrollable","studyline_enrolroles","studyline_color","associations","associated_cohorts","associated_users","studyline_edit","studyplan_name","studyplan_name_ph","studyplan_shortname","studyplan_shortname_ph","studyplan_description","studyplan_description_ph","studyplan_idnumber","studyplan_idnumber_ph","studyplan_slots","studyplan_startdate","studyplan_enddate","line_enrollable_0","line_enrollable_1","line_enrollable_2","line_enrollable_3","drophere","studyplan_advanced","advanced_tools","confirm_cancel","confirm_ok","success$core","error$core","advanced_converted","advanced_skipped","advanced_failed","advanced_locked","advanced_multiple","advanced_error","advanced_tools_heading","advanced_warning_title","advanced_warning","advanced_pick_scale","advanced_course_manipulation_title","advanced_bulk_course_timing","advanced_bulk_course_timing_desc","advanced_force_scale_title","advanced_force_scale_desc","advanced_force_scale_button","advanced_confirm_header","advanced_force_scale_confirm","advanced_backup_restore","advanced_restore","advanced_backup","advanced_restore_pages","advanced_restore_lines","advanced_backup_plan","advanced_backup_page","advanced_export","advanced_export_csv_plan","advanced_export_csv_page","advanced_import_from_file","advanced_purge","advanced_purge_plan","advanced_purge_plan_expl","advanced_purge_page","advanced_purge_page_expl","advanced_cascade_cohortsync_title","advanced_cascade_cohortsync_desc","advanced_cascade_cohortsync","currentpage","studyplan_edit","studyplan_add","studyplanpage_add","studyplanpage_edit","info_periodsextended","warning","period_edit","edit","fullname","shortname","startdate","enddate","course_timing","title","desc","question","timing_ok","timing_off","course","period","yes","no","duration","years","year","weeks","week","days","day","rememberchoice","hidewarning","periodspan","periods","periodspan_desc","studyplan_associate","associated_coaches","associate_cohorts","associate_users","associate_coached","add_association","delete_association","associations_empty","associations_search","cohorts","users","coaches","selected","name","context","search","item_text","select_conditions","item_configuration","ok","delete","item_delete_message","type_course","type_junction","type_start","type_finish","type_badge","type_invalid","item_course_text","select_grades","coursetiming_past","coursetiming_present","coursetiming_future","grade_include","grade_require","cancel","noenddate","invalid","error","completion","completion_completed","completion_incomplete","aggregation_all","aggregation_any","aggregation_overall_all","aggregation_overall_any","completion_not_configured","configure_completion","competency","competency_not_configured","configure_competency","when","required","points","heading","details","badge","share_badge","dateissued","dateexpire","badgeinfo","toolbox","toolbarRight","courses","flow","toolJunction","toolFinish","toolStart","badges","relatedbages","filter","sitebadges","props","type","Object","selectedpage","data","force_scales","selected_scale","result","text","created","mounted","updated","computed","scales","id","disabled","this","concat","advanced","methods","force_scales_start","self","$bvModal","msgBoxConfirm","okVariant","okTitle","cancelTitle","then","methodname","args","studyplan_id","scale_id","response","catch","notification","exception","export_page","format","undefined","includes","page_id","content","export_plan","bulk_course_timing","success","location","reload","msgBoxOk","msg","import_studylines","filename","import_pages","purge_studyplan","force","purge_studyplanpage","cascade_cohortsync","modal_close","template","String","Number","planSaved","updatedplan","info","mode","$emit","moved_from","context_id","moved_to","moved","pages","updatedpage","page","centered","show","config","userfields","key","cohortfields","association","loading","associated","premiumenabled","showModal","loadAssociations","cohortOptionModel","c","path","join","userOptionModel","u","firstname","lastname","map","searchCohorts","searchtext","like","cohortAssociate","requests","searchselected","i","r","push","cohort_id","fail","done","cohortDisassociate","associatedselected","searchUsers","userAssociate","user_id","userDisassociate","searchCoaches","coachAssociate","coachDisassociate","editdata","Date","getFullYear","editStart","editFinish","refresh","add_day","date","sub_day","Boolean","create","studyline","color","enrol","enrollable","enrolroles","toolbox_shown","editmode","original","availableroles","studyplan","description","slots","aggregation","aggregation_config","aggregation_info","useRequiredGrades","useItemCondition","cache","linelayers","selectedpageindex","emptyline","filterslots","courseslots","$on","studylines","coaching","$root","hivizdrop","columns","columns_stylerule","s","trashbin_accepts","item","countLineLayers","line","timestamp","maxLayer","ix","layer","filters","slotsempty","Array","isArray","count","movedStudyplan","plan","from","to","addStudyLine","newlineinfo","editLineStart","assign","editLineFinish","editedline","originalline","deleteLine","param","modalresponse","index","indexOf","splice","reorderLines","event","lines","apply","sequence","idx","deletePlan","deleteStudyItem","source","showslot","layeridx","forGradable","list","span","periodEdited","pi","prev","$refs","next","toolbox_switched","pagecreated","selectedpageChanged","newTabIndex","prevTabIndex","sumLineLayers","sum","slot","onDrop","lineslot","nextlayer","itm","$nextTick","timingChecker","validate_course_period","checkTypeCourse","checkTypeFilter","layers","layerHeights","onLineHeightChange","lineid","layerid","newheight","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","relocateStudyItem","onCut","iteminfo","onDragEnter","onDragLeave","maxSpan","makeType","checkType","maxspan","hidden","endperiod","endperiodnr","Math","min","perioddesc","course_period_matches","timeless","first","getTime","last","warn","floor","random","now","toString","globals","canupdatecourse","defaultvalue","change_course_period","has_filter","period_id","course_id","timing","checkFilterSlotBusy","nextFreeFilterLayer","usedLayers","nextlyr","checkCourseSlotBusy","nextFreeCourseLayer","shift_collisions","busyFilter","line_id","busyCourse","change_span","format_duration","dsi","toLocaleLowerCase","dummy","dragLine","dragEventListener","deleteMode","condition_options","showContext","dragStart","start","getElementById","dragelement","position","left","x","top","y","SimpleLine","gravity","end","addEventListener","onMouseMove","dragEnd","remove","removeProperty","removeEventListener","clientX","clientY","from_id","to_id","redrawLines","conn","connections","in","redrawLine","removeLine","out","highlight","setConfig","normalize","updateItem","continuation_id","doShowContext","hasContext","preventDefault","onCreatedConnection","onRemovedConnection","c_in","onRePositioned","onDisPositioned","re_id","onItemDeleted","item_id","onRedrawLines","deleteItem","msgparams","displayname","err","console","hasConnectionsOut","hasConnectionsIn","setTimeout","beforeDestroy","$off","beforeUpdate","useItemConditions","configurationState","hasGrades","hasCompletions","hasCompetencies","configurationIcon","wwwroot","Config","grades","g","cgroup","competencies","includeChanged","newValue","requiredChanged","updateConditions","selectedgrades","guestmode","stringkeys","completion_icon","completion_tag","pathtags","p","url","contextid","txt","showSpinner","canLoadMore","hasDetails","haschildren","hascourses","children","onShowDetails","activepage","studyplanid","toolboxright","relatedbadges","systembadges","loadingcourses","loadingcategories","badgelistshown","watch","newVal","oldVal","filter_relatedbadges","initialize","collapseId","isJustShown","filterComponentType","filteredCourses","filterCategories","catlist","RegExp","cat","clone","test","category","$set","filter_systembadges","reset_systembadges","reset_relatedbadges"],"mappings":"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"} |