moodle_local_treestudyplan/amd/build/studyplan-editor-components.min.js.map
2023-08-04 22:54:32 +02:00

1 line
185 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\";\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\nimport {get_strings} from 'core/str';\nimport {load_stringkeys, load_strings, format_date, datespaninfo} from './string-helper';\nimport {objCopy,transportItem} from './studyplan-processor';\nimport Debugger from './debugger';\nimport {download,upload} from './downloader';\n\nconst STUDYPLAN_EDITOR_FIELDS = \n['name','shortname','description','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\nexport default {\n STUDYPLAN_EDITOR_FIELDS: STUDYPLAN_EDITOR_FIELDS, // make copy available in plugin\n install(Vue/*,options*/){\n\n let debug = new Debugger(\"treestudyplan-editor\");\n debug.enable();\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\n // Create new eventbus for interaction between item components\n const ItemEventBus = new Vue();\n\n let string_keys = load_stringkeys({\n conditions: [\n { value: null, textkey: 'condition_default'},\n { value: 'ALL', textkey: 'condition_all'},\n { value: '67', textkey: 'condition_67'},\n { value: '50', textkey: 'condition_50'},\n { value: 'ANY', textkey: 'condition_any'},\n ],\n });\n\n let strings = load_strings({\n studyplan_text: {\n studyline_editmode: 'studyline_editmode',\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_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_slots: 'studyplan_slots',\n studyplan_startdate: 'studyplan_startdate',\n studyplan_enddate: 'studyplan_enddate',\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_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_disable_autoenddate_title: 'advanced_disable_autoenddate_title',\n advanced_disable_autoenddate_desc: 'advanced_disable_autoenddate_desc',\n advanced_disable_autoenddate_button: 'advanced_disable_autoenddate_button',\n advanced_confirm_header: 'advanced_confirm_header',\n advanced_force_scale_confirm: 'advanced_force_scale_confirm',\n advanced_import: 'advanced_import',\n advanced_export: 'advanced_export',\n advanced_export_csv: 'advanced_export_csv',\n advanced_import_from_file: 'advanced_import_from_file',\n advanced_purge: \"advanced_purge\",\n advanced_purge_expl: \"advanced_purge_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 },\n studyplan_edit: {\n studyplan_edit: 'studyplan_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_context: 'studyplan_context',\n studyplan_slots: 'studyplan_slots',\n studyplan_startdate: 'studyplan_startdate',\n studyplan_enddate: 'studyplan_enddate',\n choose_aggregation_style: 'choose_aggregation_style',\n setting_bistate_thresh_excellent: 'setting_bistate_thresh_excellent',\n settingdesc_bistate_thresh_excellent: 'settingdesc_bistate_thresh_excellent',\n setting_bistate_thresh_good: 'setting_bistate_thresh_good',\n settingdesc_bistate_thresh_good: 'settingdesc_bistate_thresh_good',\n setting_bistate_thresh_completed: 'setting_bistate_thresh_completed',\n settingdesc_bistate_thresh_completed: 'settingdesc_bistate_thresh_completed',\n setting_bistate_support_failed: 'setting_bistate_support_failed',\n settingdesc_bistate_support_failed: 'settingdesc_bistate_support_failed',\n setting_bistate_thresh_progress: 'setting_bistate_thresh_progress',\n settingdesc_bistate_thresh_progress: 'settingdesc_bistate_thresh_progress',\n setting_bistate_accept_pending_submitted: 'setting_bistate_accept_pending_submitted',\n settingdesc_bistate_accept_pending_submitted: 'settingdesc_bistate_accept_pending_submitted',\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 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 },\n studyplan_associate: {\n associations: 'associations',\n associated_cohorts: 'associated_cohorts',\n associated_users: 'associated_users',\n associate_cohorts: 'associate_cohorts',\n associate_users: 'associate_users',\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 selected: 'selected',\n name: 'name',\n context: 'context',\n },\n item_text: {\n select_conditions: \"select_conditions\",\n item_configuration: \"item_configuration\",\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 },\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 badge: {\n share_badge: \"share_badge\",\n dateissued: \"dateissued\",\n dateexpire: \"dateexpire\",\n badgeinfo: \"badgeinfo\",\n },\n\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 },\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 },\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 disable_autoenddate(){\n const self=this;\n call([{\n methodname: 'local_treestudyplan_disable_autoenddate',\n args: {\n studyplan_id: this.value.id,\n }\n }])[0].done(function(response){\n self.$bvModal.msgBoxConfirm((response.success?self.text.success$core:self.text.error$core)\n + \"\\n\" + response.msg);\n }).fail(notification.exception);\n },\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].done(function(response){\n self.force_scales.result = response;\n }).fail(notification.exception);\n }\n });\n },\n export_plan(format){\n const self = this;\n if(format == undefined || ![\"json\",\"csv\"].includes(format)){\n format = \"json\";\n }\n call([{\n methodname: 'local_treestudyplan_export_plan',\n args: {\n studyplan_id: this.value.id,\n format: format,\n },\n }])[0].done(function(response){\n \n download(self.value.shortname+\".\"+format,response.content,response.format);\n }).fail(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 studyplan_id: this.value.id,\n content: content,\n format: \"application/json\",\n },\n }])[0].done(function(response){\n if(response.success){\n location.reload();\n } else {\n debug.error(\"Import failed: \",response.msg);\n }\n \n }).fail(notification.exception); \n }, \"application/json\");\n },\n purge_studyline(){\n call([{\n methodname: 'local_treestudyplan_delete_studyplan',\n args: {\n id: this.value.id,\n force: true,\n },\n }])[0].done(function(response){\n if(response.success){\n location.reload();\n } else {\n debug.error(\"Could not delete plan: \",response.msg);\n }\n \n }).fail(notification.exception); \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].done(function(response){\n self.$bvModal.msgBoxOk(response.success?self.text.success$core:self.text.error$core,\n { title: self.text.advanced_cascade_cohortsync});\n }).fail(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-cog'></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 >\n <b-card no-body>\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 <b-container>\n <b-row><b-col cols=\"*\">\n <h3>{{ text.advanced_cascade_cohortsync_title}}</h3>\n {{ text.advanced_cascade_cohortsync_desc}}\n </b-col></b-row>\n <b-row><b-col cols=\"*\">\n <b-button \n variant=\"info\"\n @click=\"cascade_cohortsync\"\n >{{ text.advanced_cascade_cohortsync}}</b-button>\n </b-col></b-row>\n <b-row class=\"mt-3\"><b-col cols=\"*\">\n <h3>{{ text.advanced_force_scale_title}}</h3>\n {{ text.advanced_force_scale_desc}}\n </b-col></b-row>\n <b-row>\n <b-col>\n <b-form-select v-model=\"force_scales.selected_scale\" \n :options=\"scales\" text-field=\"name\" value-field=\"id\"\n ></b-form-select>\n </b-col>\n <b-col cols=\"4\">\n <b-button \n variant=\"danger\"\n :disabled=\"force_scales.selected_scale == null\"\n @click=\"force_scales_start\"\n >{{ text.advanced_force_scale_button}}</b-button>\n </b-col>\n\n </b-row>\n <b-row class=\"mt-3\"><b-col cols=\"*\">\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'>{{g.name}}</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 >\n <span v-else class='t-advanced-status skipped'\n >{{text.advanced_error}}</span\n >\n </li>\n </ul>\n </li>\n </ul>\n </b-col></b-row>\n <b-row><b-col cols=\"*\">\n <h3>{{ text.advanced_disable_autoenddate_title}}</h3>\n {{ text.advanced_disable_autoenddate_desc}}\n </b-col></b-row>\n <b-row><b-col cols=\"*\">\n <b-button \n variant=\"danger\"\n @click=\"disable_autoenddate\"\n >{{ text.advanced_disable_autoenddate_button}}</b-button>\n </b-col></b-row>\n </b-container>\n </b-tab>\n <b-tab :title='text.advanced_export'>\n <b-button \n variant=\"primary\"\n @click=\"export_plan\"\n >{{ text.advanced_export}}</b-button>\n <b-button\n variant=\"danger\"\n @click=\"import_studylines\"\n >{{ text.advanced_import}}</b-button>\n <b-button \n variant=\"primary\"\n @click=\"export_plan('csv')\"\n >{{ text.advanced_export_csv}}</b-button>\n </b-tab>\n <b-tab :title='text.advanced_purge'>\n <p>{{text.advanced_purge_expl}}</p>\n <p><b-button\n variant=\"danger\"\n @click=\"purge_studyline\"\n >{{ text.advanced_purge}}</b-button></p>\n </b-tab> </b-tabs>\n </b-card>\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 },\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 editdata: { \n name: '',\n shortname: '',\n description: '',\n context_id: 1,\n periods : 4,\n startdate: (new Date()).getFullYear() + '-08-01',\n enddate: ((new Date()).getFullYear()+1) + '-08-01',\n aggregation: 'bistate',\n aggregation_config: '',\n },\n aggregation_parsed: {\n\n },\n aggregators: [],\n categories: [ { context_id: 1, category: { path: \"System\"}}], // overwritten during load...\n text: strings.studyplan_edit,\n };\n },\n created() {\n // retrieve aggregator info\n const self = this;\n call([{\n methodname: 'local_treestudyplan_list_aggregators',\n args: [],\n }])[0].done(function(response){\n self.aggregators = response;\n for(const ix in self.aggregators){\n const ag = self.aggregators[ix];\n \n try{\n if(ag.defaultconfig && ag.defaultconfig.length > 0){\n self.aggregation_parsed[ag.id] = JSON.parse(ag.defaultconfig);\n }\n }\n catch(e){\n debug.warn(e);\n }\n }\n }).fail(notification.exception);\n call([{\n methodname: 'local_treestudyplan_list_accessible_categories',\n args: {operation: \"edit\",}\n }])[0].done(function(response){\n for(const ix in response){\n const cat = response[ix];\n cat.category.pathname = cat.category.path.join(\" / \");\n }\n self.categories = response;\n }).fail(notification.exception);\n },\n mounted() {\n },\n updated() {\n\n },\n computed: {\n },\n methods: {\n editPlanStart(){\n if(this.mode != 'create'){\n objCopy(this.editdata,this.value.pages[0],STUDYPLAN_EDITOR_PAGE_FIELDS);\n objCopy(this.editdata,this.value,STUDYPLAN_EDITOR_FIELDS);\n\n }\n // decode the aggregation config data that is stored\n if(this.editdata.aggregation_config && this.editdata.aggregation_config.length > 0){\n try{\n this.aggregation_parsed[this.editdata.aggregation] = JSON.parse(this.editdata.aggregation_config);\n }\n catch(e){\n debug.warn(e);\n }\n }\n this.show = true;\n },\n editPlanFinish(){\n const self = this;\n let args = { };\n let method = 'local_treestudyplan_edit_studyplan';\n if(this.mode == 'create'){\n method = 'local_treestudyplan_add_studyplan';\n } else {\n args['id'] = this.value.id;\n }\n\n // store the configuration for this aggregation type if it is relevant\n if(this.aggregation_parsed[this.editdata.aggregation]){\n this.editdata.aggregation_config = JSON.stringify(this.aggregation_parsed[this.editdata.aggregation]);\n }\n objCopy(args,this.editdata,STUDYPLAN_EDITOR_FIELDS);\n objCopy(args,this.editdata,STUDYPLAN_EDITOR_PAGE_FIELDS);\n\n call([{\n methodname: method,\n args: args\n }])[0].done(function(response){\n if(self.mode == 'create'){\n self.$emit(\"created\", response);\n // And reset the edit fields to default\n self.editdata = { \n name: '',\n shortname: '',\n description: '',\n context_id: 1,\n periods : 4,\n startdate: (new Date()).getFullYear() + '-08-01',\n enddate: ((new Date()).getFullYear()+1) + '-08-01',\n aggregation: 'bistate',\n aggregation_config: '',\n };\n }\n else {\n // determine if the plan moved context...\n const moved_from = self.value.context_id;\n const moved_to = response.context_id;\n const moved = (moved_from != moved_to);\n\n objCopy(self.value,response,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 }).fail(notification.exception);\n },\n numberFilter(value){\n return value;\n }\n }\n ,\n template: \n `\n <span class='s-studyplan-edit'>\n <b-button :variant=\"variant\" v-if='type == \"button\"' @click.prevent='editPlanStart()'\n ><slot><i class='fa fa-pencil'></i></slot></b-button>\n <a variant=\"variant\" v-else href='#' @click.prevent='editPlanStart()'\n ><slot><i class='fa fa-pencil'></i></slot></a>\n <b-modal \n v-model=\"show\"\n size=\"lg\"\n ok-variant=\"primary\"\n :title=\"text.studyplan_edit\"\n @ok=\"editPlanFinish()\"\n :ok-disabled=\"Math.min(editdata.name.length,editdata.shortname.length) == 0\"\n >\n <b-container>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_name}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"editdata.name\" \n :state='editdata.name.length>0'\n :placeholder=\"text.studyplan_name_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_shortname}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"editdata.shortname\" \n :state='editdata.shortname.length>0'\n :placeholder=\"text.studyplan_shortname_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_description}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"editdata.description\" \n :placeholder=\"text.studyplan_description_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_context}}</b-col>\n <b-col cols=\"8\">\n <b-form-select v-model=\"editdata.context_id\" \n :options=\"categories\" text-field=\"category.pathname\" value-field=\"context_id\"\n ></b-form-select>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_slots}}</b-col>\n <b-col cols=\"8\">\n <b-form-input type=number v-model=\"editdata.periods\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_startdate}}</b-col>\n <b-col cols=\"8\">\n <b-form-datepicker v-model=\"editdata.startdate\"></b-form-datepicker>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_enddate}}</b-col>\n <b-col cols=\"8\">\n <b-form-datepicker v-model=\"editdata.enddate\" ></b-form-datepicker>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.choose_aggregation_style}}</b-col>\n <b-col cols=\"8\">\n <b-form-select v-model=\"editdata.aggregation\" \n :options=\"aggregators\" text-field=\"name\" value-field=\"id\"\n ></b-form-select>\n </b-col>\n </b-row>\n <template v-if=\"aggregation_parsed.bistate && editdata.aggregation == 'bistate'\">\n <b-row >\n <b-col cols=\"4\">{{ text.setting_bistate_thresh_excellent}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"aggregation_parsed.bistate.thresh_excellent\" \n type=\"number\" number :formatter=\"numberFilter\"\n ></b-form-input>\n </b-col>\n </b-row>\n <b-row >\n <b-col cols=\"4\">{{ text.setting_bistate_thresh_good}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"aggregation_parsed.bistate.thresh_good\" \n type=\"number\" number :formatter=\"numberFilter\"\n ></b-form-input>\n </b-col>\n </b-row>\n <b-row >\n <b-col cols=\"4\">{{ text.setting_bistate_thresh_completed}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"aggregation_parsed.bistate.thresh_completed\" \n type=\"number\" number :formatter=\"numberFilter\"\n ></b-form-input>\n </b-col>\n </b-row> \n <b-row>\n <b-col cols=\"4\">{{ text.setting_bistate_thresh_progress}}</b-col>\n <b-col cols=\"8\">\n <b-form-input v-model=\"aggregation_parsed.bistate.thresh_progress\" \n type=\"number\" number :formatter=\"numberFilter\"\n ></b-form-input>\n </b-col>\n </b-row> \n <b-row><b-col cols=\"*\">&nbsp;</b-col></b-row>\n <b-row>\n <b-col cols=\"7\">{{ text.setting_bistate_support_failed}}</b-col>\n <b-col cols=\"3\">\n <b-form-checkbox v-model=\"aggregation_parsed.bistate.use_failed\" \n ></b-form-checkbox>\n </b-col>\n </b-row>\n <b-row><b-col cols=\"*\">&nbsp;</b-col></b-row>\n <b-row >\n <b-col cols=\"7\">{{ text.setting_bistate_accept_pending_submitted}}</b-col>\n <b-col cols=\"3\">\n <b-form-checkbox v-model=\"aggregation_parsed.bistate.accept_pending_as_submitted\" \n ></b-form-checkbox>\n </b-col>\n </b-row> \n </template> \n </b-container>\n </b-modal> \n </span> \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 },\n loading: {\n cohorts: false,\n users: false,\n },\n search: {users: [], cohorts:[]},\n selected: {\n search: {users: [] , cohorts:[]}, \n associated: {users: [] , cohorts:[]}\n }, \n text: strings.studyplan_associate,\n };\n },\n created() {\n \n },\n mounted() {\n },\n updated() {\n\n },\n methods: {\n showModal(){\n this.show = true;\n this.loadAssociations();\n },\n cohortOptionModel(c){\n return {\n value: c.id,\n text: c.name + ' (' + c.context.path.join(' / ') + ')',\n };\n },\n userOptionModel(u){\n return {\n value: u.id,\n text: u.firstname + ' ' + u.lastname,\n };\n },\n loadAssociations(){\n const self = this;\n self.loading.cohorts = true;\n self.loading.users = true;\n call([{\n methodname: 'local_treestudyplan_associated_users',\n args: { studyplan_id: self.value.id,}\n }])[0].done(function(response){\n self.association.users = response.map(self.userOptionModel);\n self.loading.users = false;\n }).fail(notification.exception); \n\n call([{\n methodname: 'local_treestudyplan_associated_cohorts',\n args: { studyplan_id: self.value.id,}\n }])[0].done(function(response){\n self.association.cohorts = response.map(self.cohortOptionModel);\n self.loading.cohorts = false;\n }).fail(notification.exception); \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, exclude_id: self.value.id}\n }])[0].done(function(response){\n self.search.cohorts = response.map(self.cohortOptionModel);\n }).fail(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, exclude_id: self.value.id}\n }])[0].done(function(response){\n self.search.users = response.map(self.userOptionModel);\n }).fail(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 }\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=\"cohortDisassociate()\"\n ><i class='fa fa-chain-broken'></i>&nbsp;{{text.delete_association}}</b-button>\n </b-col>\n <b-col>\n <b-button variant='success' @click=\"cohortAssociate()\"\n ><i class='fa fa-link'></i>&nbsp;{{text.add_association}}</b-button> \n </b-col>\n </b-row>\n </b-container>\n </b-tab>\n <b-tab :title=\"text.users\">\n <b-container>\n <b-row class='mb-2 mt-2'>\n <b-col>{{text.associated_users}}</b-col>\n <b-col>{{text.associate_users}}</b-col>\n </b-row>\n <b-row class='mb-2'>\n <b-col>\n </b-col>\n <b-col>\n <b-form-input \n type=\"text\" \n @input=\"searchUsers($event)\" \n placeholder=\"Search 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=\"userDisassociate()\"\n ><i class='fa fa-chain-broken'></i>&nbsp;{{text.delete_association}}</b-button>\n </b-col>\n <b-col>\n <b-button variant='success' @click=\"userAssociate()\"\n ><i class='fa fa-link'></i>&nbsp;{{text.add_association}}</b-button> \n </b-col>\n </b-row> \n </b-container> \n </b-tab>\n </b-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 },\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 let method = 'local_treestudyplan_edit_period';\n\n objCopy(args,this.editdata,PERIOD_EDITOR_FIELDS);\n\n call([{\n methodname: method,\n args: args\n }])[0].done(function(response){\n objCopy(self.value,response,PERIOD_EDITOR_FIELDS);\n self.$emit('input',self.value);\n }).fail(notification.exception);\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-pencil'></i></slot></b-button>\n <a variant=\"variant\" v-else href='#' @click.prevent='editStart()'\n ><slot><i class='fa fa-pencil'></i></slot></a>\n <b-modal \n v-model=\"show\"\n size=\"lg\"\n ok-variant=\"primary\"\n :title=\"text.period_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>\n <b-col cols=\"4\">{{ text.studyplan_startdate}}</b-col>\n <b-col cols=\"8\">\n <b-form-datepicker v-model=\"editdata.startdate\"></b-form-datepicker>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"4\">{{ text.studyplan_enddate}}</b-col>\n <b-col cols=\"8\">\n <b-form-datepicker v-model=\"editdata.enddate\" ></b-form-datepicker>\n </b-col>\n </b-row>\n </b-container>\n </b-modal> \n </span> \n `\n });\n\n /*\n * T-STUDYPLAN\n */\n Vue.component('t-studyplan', {\n props: ['value', 'index'],\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 },\n },\n edit: {\n studyline: {\n editmode: false,\n data: { \n name: '',\n shortname: '',\n color: '#DDDDDD',\n },\n original: {},\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 };\n },\n created() {\n \n },\n mounted() {\n if(this.page.studylines.length == 0){\n // start in editmode if studylines are empty\n this.edit.studyline.editmode = true;\n } \n this.$root.$emit('redrawLines');\n },\n updated() {\n console.info(\"UPDATED Studyplan\");\n this.$root.$emit('redrawLines');\n ItemEventBus.$emit('redrawLines');\n },\n computed: {\n columns() {\n return 1+ (this.page.periods * 2);\n },\n columns_stylerule() {\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<this.page.periods;i++){\n s+= \" var(--studyplan-course-width) var(--studyplan-filter-width)\";\n }\n return s+\";\";\n },\n page(){\n // FIXME: Temporary hack until real page management is implemented\n return this.value.pages[0];\n }\n },\n methods: {\n countLineLayers(line){\n let maxLayer = -1;\n for(let i = 0; i <= this.page.periods; i++){\n const slot = line.slots[i];\n // Determine the amount of used layers in a studyline slit\n for(const ix in line.slots[i].competencies){\n const item = line.slots[i].competencies[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 return maxLayer+1;\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].competencies)){\n count += slots[i].competencies.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 }\n }])[0].done(function(response){\n debug.info(\"New studyline:\",response);\n page.studylines.push(response);\n newlineinfo.name = '';\n newlineinfo.shortname = '';\n newlineinfo.color = \"#dddddd\";\n }).fail(notification.exception);\n },\n editLineStart(line) {\n Object.assign(this.edit.studyline.data,line);\n this.edit.studyline.original = line;\n this.$bvModal.show('modal-edit-studyline-'+this.value.id);\n },\n editLineFinish() {\n let editedline = this.edit.studyline.data;\n let originalline = this.edit.studyline.original;\n debug.info('Edit Line',this.edit.studyline);\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 }])[0].done(function(response){\n debug.info('Edit response:', response);\n originalline['name'] = response['name'];\n originalline['shortname'] = response['shortname'];\n originalline['color'] = response['color'];\n }).fail(notification.exception);\n },\n deleteLine(page,line) {\n debug.info('Delete Line',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].done(function(response){\n debug.info('Delete response:', response);\n if(response.success == true){\n let index = page.studylines.indexOf(line);\n page.studylines.splice(index, 1);\n }\n }).fail(notification.exception);\n }\n });\n });\n },\n reorderLines(event,lines){\n debug.info(\"Reorder lines\",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].done(function(response){\n debug.info('Reorder response:', response);\n }).fail(notification.exception);\n },\n deletePlan(studyplan){\n const self=this;\n debug.info('Delete studyplan:', studyplan);\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, }\n }])[0].done(function(response){\n debug.info('Delete response:', response);\n if(response.success == true){\n self.$root.$emit(\"studyplanRemoved\",studyplan);\n }\n }).fail(notification.exception);\n }\n });\n });\n },\n deleteStudyItem(event){\n debug.info('Delete studyitem:', event);\n //const self = this;\n let item = event.data;\n\n call([{\n methodname: 'local_treestudyplan_delete_studyitem',\n args: { 'id': item.id, }\n }])[0].done(function(response){\n debug.info('Delete response:', response);\n if(response.success == true){\n event.source.$emit('cut',event);\n }\n }).fail(notification.exception);\n\n },\n showslot(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 = this.page.periods;\n let show = true;\n for(let i = 0; i < periods; i++){\n if(line.slots[index-i] && line.slots[index-i].competencies){\n const list = line.slots[index-i].competencies;\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 }\n ,\n template: \n `\n <div>\n <div class='controlbox t-studyplan-controlbox'>\n <b-form-checkbox v-model=\"edit.studyline.editmode\" class=\"sw-studyline-editmode\" switch\n >{{ text.studyline_editmode }}</b-form-checkbox>\n <drop \n mode='copy'\n class='t-item-deletebox text-danger border-danger'\n @drop='deleteStudyItem'\n :accepts-type=\"['gradable-item','filter-item']\"\n ><i class='fa fa-trash'></i>\n </drop>\n <span class='control deletable'>\n <a v-if='page.studylines.length == 0' href='#' @click='deletePlan(value)'\n ><i class='text-danger fa fa-trash'></i></a>\n </span>\n <span class='control editable'>\n <t-studyplan-edit v-model=\"value\" @moved=\"movedStudyplan\"\n ><i class='fa fa-pencil'></i> {{text.edit$core}}</t-studyplan-edit> \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-advanced v-model=\"value\"></t-studyplan-advanced>\n </span>\n </div>\n <div class='t-studyplan-content-edit' v-if=\"edit.studyline.editmode\">\n <drop-list\n :items=\"page.studylines\"\n class=\"t-slot-droplist\"\n :accepts-type=\"'studyline-'+page.id\"\n xreorder=\"$event.apply(page.studylines)\"\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-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\n <!-- Now paint the headings column -->\n <div class='t-studyplan-headings'>\n <s-studyline-header-heading></s-studyline-header-heading>\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)+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 </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\">\n <!-- add period information -->\n <template v-for=\"(n,index) in (page.periods+1)\">\n <s-studyline-header-period \n v-if=\"index > 0\"\n v-model=\"page.perioddesc[index-1]\"\n ><t-period-edit v-model=\"page.perioddesc[index-1]\"></t-period-edit\n ></s-studyline-header-period>\n <div class=\"s-studyline-header-filter\"></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)+1\"\n ><template v-for=\"(n,index) in (page.periods+1)\"\n >\n <t-studyline-slot \n v-if=\"index > 0 && showslot(line, index, layeridx, 'gradable')\"\n type='gradable'\n v-model=\"line.slots[index].competencies\" \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 ></t-studyline-slot\n ><t-studyline-slot \n type='filter'\n v-if=\"showslot(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 >\n </t-studyline-slot\n ></template\n ></template\n ></template\n ></div>\n </div>\n </div>\n <div v-if=\"edit.studyline.editmode\" class='t-studyline-add'>\n <a href=\"#\" v-b-modal=\"'modal-add-studyline-'+page.id\" @click=\"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 </b-container>\n </b-modal>\n <b-modal \n :id=\"'modal-edit-studyline-'+value.id\" \n size=\"lg\" \n ok-variant=\"primary\"\n :title=\"text.studyline_edit\"\n @ok=\"editLineFinish()\"\n :ok-disabled=\"Math.min(edit.studyline.data.name.length,edit.studyline.data.shortname.length) == 0\"\n >\n <b-container>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_name}}</b-col>\n <b-col>\n <b-form-input \n v-model=\"edit.studyline.data.name\" \n :placeholder=\"text.studyline_name_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_shortname}}</b-col>\n <b-col>\n <b-form-input \n v-model=\"edit.studyline.data.shortname\" \n :placeholder=\"text.studyline_shortname_ph\"></b-form-input>\n </b-col>\n </b-row>\n <b-row>\n <b-col cols=\"3\">{{ text.studyline_color}}</b-col>\n <b-col>\n <input type=\"color\" v-model=\"edit.studyline.data.color\" />\n </b-col>\n </b-row>\n </b-container>\n </b-modal>\n </div>\n `\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 :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].competencies)){\n count += slots[i].competencies.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 },\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'>\n <a href='#' @click='onEdit'><i class='fa fa-pencil'></i></a>\n </span>\n <span class='control deletable'>\n <a v-if='deletable' href='#' @click='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 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 dragacceptlist(){\n if(this.type == \"gradable\"){\n return [\"course\", \"gradable-item\"];\n } else {\n return [\"filter\", \"filter-item\"];\n }\n },\n courseHoverDummy(){\n return {course: this.hover.component};\n },\n current(){\n if( this.period && this.period.startdate && this.period.enddate){\n const now = new Date();\n const pstart = new Date(this.period.startdate);\n const pend = new Date(this.period.enddate);\n return (now >= pstart && now < pend);\n }\n else {\n return false;\n }\n },\n spanCss(){\n if(this.item && this.item.span > 1){\n const span = (2 * this.item.span) - 1;\n return `width: 100%; grid-column: span ${span};`;\n } else {\n return \"\";\n }\n }\n },\n data() {\n return {\n text: strings.course_timing,\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 onDrop(event) {\n this.hover.component = null;\n this.hover.type = null;\n\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 this.$nextTick(() => {\n self.relocateStudyItem(item).done(()=>{\n self.validate_course_period();\n });\n });\n }\n else if(event.type.component){\n\n if(event.type.type == \"course\"){\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].done((response) => {\n console.info('Add item response:', response);\n let item = response;\n self.relocateStudyItem(item).done(()=>{\n self.value.push(item);\n self.$emit(\"input\",self.value);\n // call the validate period function on next tick,\n // since it paints the item in the slot first\n this.$nextTick(self.validate_course_period);\n });\n }).fail(notification.exception);\n } \n else if(event.type.type == \"filter\") {\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].done((response) => {\n console.info('Add item response:', response);\n let item = response;\n self.relocateStudyItem(item).done(()=>{\n self.value.push(item);\n self.$emit(\"input\",self.value); \n });\n }).fail(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 },\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].fail(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 validate_course_period() {\n const self = this;\n debug.info(\"Validating course and period\",self.item,self.period);\n if(self.item && self.item.type == 'course'){\n self.datechanger.coursespan = datespaninfo(self.item.course.startdate,self.item.course.enddate);\n self.datechanger.periodspan = datespaninfo(self.period.startdate,self.period.enddate);\n if( self.datechanger.coursespan.first != self.datechanger.periodspan.first \n || self.datechanger.coursespan.last != self.datechanger.periodspan.last ){\n debug.info(\"Course timing does not match period timing\");\n\n if(self.item.course.canupdatecourse){\n if(!self.datechanger.default){\n // Periods do not match, pop up the date change request \n this.$bvModal.show(\"t-course-date-matching-\"+this.slotkey);\n } else if (self.datechanger.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.datechanger.hidewarn){\n this.$bvModal.show(\"t-course-date-warning-\"+this.slotkey);\n }\n }\n }\n else {\n debug.info(\"Course timing matches period\",self.datechanger);\n }\n }\n },\n change_course_period() {\n const self=this;\n return call([{\n methodname: 'local_treestudyplan_course_period_timing',\n args: { page_id: self.page_id,\n period: self.period.period, \n course_id: this.item.course.id,\n }\n }])[0].fail(notification.exception); \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 maxSpan(){\n // Determine the maximum span for components in this slot\n // Used for setting the max in the timing adjustment screen (s)\n // And for checking the filter types\n\n // Assume this slot is first one available\n let freeIndex = this.slotindex;\n // Determine last free slot following this one in the layer\n for(let i = this.slotindex + 1; i <= this.page.periods; i++){\n if(this.line.slots && this.line.slots[i] && this.line.slots[i].competencies){\n const l = this.line.slots[i].competencies;\n if(l[this.layer]) {\n // slot is busy in this layer.\n break;\n } else {\n freeIndex = i;\n }\n } else {\n break; // stop processing\n }\n }\n // calculate span from that\n return freeIndex - this.slotindex + 1;\n\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(type == 'filter'){\n return true;\n } else if(type.span <= this.maxSpan()){\n return true;\n } else {\n return false;\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 + (current?'current ':' ')\"\n :data-studyline=\"line.id\" ref=\"main\"\n :style='spanCss'\n ><drag v-if=\"item\"\n \n :key=\"item.id\" \n class=\"t-slot-item\" \n :data=\"item\" \n :type=\"makeType(item)\" \n @cut=\"onCut\"\n ><t-item v-model=\"item\" :plan=\"plan\"></t-item\n ></drag\n ><drop v-else\n :class=\"'t-slot-drop '+type + (layer > 0?' secondary':' primary')\"\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 ></drop>\n <b-modal \n :id=\"'t-course-date-matching-'+this.slotkey\" \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 && item && item.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><b>{{ item.course.fullname }}</b></p>\n <p><b>{{ item.course.shortname }}</b></p>\n <p>{{ datechanger.coursespan.formatted.first}} - {{ datechanger.coursespan.formatted.last}}</p>\n <p><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><b>{{ period.fullname }}</b></p>\n <p><b>{{ period.shortname }}</b></p>\n <p>{{ datechanger.periodspan.formatted.first}} - {{ datechanger.periodspan.formatted.last}}</p>\n <p><b>{{ text.duration }}</b><br>\n {{ format_duration(datechanger.periodspan)}}</p>\n </b-col>\n </b-row>\n <b-row><b-col cols=\"12\">\n <b-form-checkbox type=\"checkbox\" v-model=\"datechanger.default\">{{ text.rememberchoice }}</b-form-checkbox>\n </b-col></b-row>\n </b-container>\n </b-modal>\n <b-modal \n :id=\"'t-course-date-warning-'+this.slotkey\" \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 && item && item.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><b>{{ item.course.fullname }}</b></p>\n <p><b>{{ item.course.shortname }}</b></p>\n <p>{{ datechanger.coursespan.formatted.first}} - {{ datechanger.coursespan.formatted.last}}</p>\n <p><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><b>{{ period.fullname }}</b></p>\n <p><b>{{ period.shortname }}</b></p>\n <p>{{ datechanger.periodspan.formatted.first}} - {{ datechanger.periodspan.formatted.last}}</p>\n <p><b>{{ text.duration }}</b><br>\n {{ format_duration(datechanger.periodspan)}}</p>\n </b-col>\n </b-row>\n <b-row><b-col cols=\"12\">\n <b-form-checkbox type=\"checkbox\" v-model=\"datechanger.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 },\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].done((result)=>{\n console.info(\"Drop result\",result);\n let conn = {'id': result.id, 'from_id': result.from_id, 'to_id': result.to_id};\n ItemEventBus.$emit(\"createdConnection\",conn);\n this.value.connections.in.push(conn);\n }).fail(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 // console.info(\"Delete Line\",conn);\n call([{\n methodname: 'local_treestudyplan_disconnect_studyitems',\n args: { 'from_id': conn.from_id, 'to_id': conn.to_id }\n }])[0].done((result)=>{\n if(result.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 }).fail(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].fail(notification.exception);\n },\n doShowContext(event) {\n if(this.hasContext){\n this.showContext=true;\n event.preventDefault();\n }\n },\n redrawLines(){\n for(let i in this.value.connections.out){\n let conn = this.value.connections.out[i];\n // console.info('Connection out', conn);\n this.redrawLine(conn);\n }\n },\n\n // EVENT LISTENERS\n onCreatedConnection(conn){\n if(conn.from_id == this.value.id){\n // console.info(\"incomingConnection\",conn);\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 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 // console.info(\"Deleting incoming connection\",conn);\n self.value.connections.out.splice(i, 1);\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 for(let i in this.value.connections.out){\n let conn = this.value.connections.out[i];\n this.redrawLine(conn);\n }\n },\n // When an item is disPositioned - (temporarily) removed from the list,\n // all connections need to be deleted.\n onDisPositioned(re_id){\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 // 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 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 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 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\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 ['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 // console.info('Mounted', this);\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 v-model=\"value\" v-if=\"value.type == 'course'\"\n :plan='plan' ></t-item-course>\n <t-item-junction v-model=\"value\" v-if=\"value.type == 'junction'\" ></t-item-junction>\n <t-item-start v-model=\"value\" v-if=\"value.type == 'start'\" ></t-item-start>\n <t-item-finish v-model=\"value\" v-if=\"value.type == 'finish'\" ></t-item-finish>\n <t-item-badge v-model=\"value\" v-if=\"value.type == 'badge'\" ></t-item-badge>\n <t-item-invalid v-model=\"value\" v-if=\"value.type == 'invalid'\" ></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=\"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=\"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='t-item-contextview'\n :id=\"'t-item-config-'+value.id\"\n :title=\"text['item_configuration']\"\n scrollable\n ok-only\n >\n <b-form-group\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 </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 <b-card no-body class=\"t-item-invalid\">\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 </b-card-body>\n </b-col>\n </b-row>\n </b-card>\n `,\n });\n\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 },\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()) {\n return \"t-configured-ok\";\n } else {\n return \"t-configured-alert\";\n }\n },\n\n configurationIcon(){\n if(this.hasGrades() || this.hasCompletions()) {\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){\n return format_date(this.value.course.enddate);\n } \n else {\n return this.text.noenddate;\n }\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 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].fail(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].fail(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].fail(notification.exception);\n },\n },\n created() {\n\n },\n template: `\n <b-card no-body class=\"t-item-course\">\n <div class='d-flex flex-wrap mr-0 ml-0'>\n <div>\n <span \n :title=\"text['coursetiming_'+value.course.timing]\" \n v-b-popover.hover.top=\"startdate+' - '+enddate\" \n :class=\"'t-timing-indicator timing-'+value.course.timing\"></span>\n </div>\n <div class=\"flex-fill\">\n <b-card-body class=\"align-items-center\">\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 <a v-b-modal=\"'t-item-course-config-'+value.id\"\n :id=\"'t-item-course-details-'+value.id\" \n :href=\"'/course/view.php?id='+value.course.id\"\n @click.prevent.stop=\"\">{{ value.course.displayname }}</a>\n </b-card-body>\n </div>\n </div>\n <b-modal\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 >\n <template #modal-header>\n <div>\n <h1><a :href=\"'/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=\"'/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 </div>\n </template>\n \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 </b-modal>\n </b-card>\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].fail(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].fail(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>{{g.name}}</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 },\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=\"'/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\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 };\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\n :id=\"'t-item-badge-details-'+value.id\" \n :title=\"value.badge.name\" \n size=\"lg\"\n ok-only\n centered\n scrollable\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 </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 || this.value.children.length == 0)) ||\n (this.value.hascourses && (!this.value.courses || this.value.courses.length == 0));\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].done(function(response){\n debug.info(\"Course info:\",response);\n self.$emit('input', response);\n }).fail(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\"></i>\n <i class=\"when-open fa fa-caret-down\"></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 <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 <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 </li>\n </ul> \n `,\n });\n \n },\n};\n"],"names":["STUDYPLAN_EDITOR_FIELDS","STUDYPLAN_EDITOR_PAGE_FIELDS","PERIOD_EDITOR_FIELDS","install","Vue","debug","Debugger","isVisible","elem","offsetWidth","offsetHeight","getClientRects","length","enable","ItemEventBus","string_keys","conditions","value","textkey","strings","studyplan_text","studyline_editmode","editmode_modules_hidden","studyline_add","add$core","edit$core","studyline_name","studyline_name_ph","studyline_shortname","studyline_shortname_ph","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_slots","studyplan_startdate","studyplan_enddate","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_force_scale_title","advanced_force_scale_desc","advanced_force_scale_button","advanced_disable_autoenddate_title","advanced_disable_autoenddate_desc","advanced_disable_autoenddate_button","advanced_confirm_header","advanced_force_scale_confirm","advanced_import","advanced_export","advanced_export_csv","advanced_import_from_file","advanced_purge","advanced_purge_expl","advanced_cascade_cohortsync_title","advanced_cascade_cohortsync_desc","advanced_cascade_cohortsync","studyplan_edit","studyplan_context","choose_aggregation_style","setting_bistate_thresh_excellent","settingdesc_bistate_thresh_excellent","setting_bistate_thresh_good","settingdesc_bistate_thresh_good","setting_bistate_thresh_completed","settingdesc_bistate_thresh_completed","setting_bistate_support_failed","settingdesc_bistate_support_failed","setting_bistate_thresh_progress","settingdesc_bistate_thresh_progress","setting_bistate_accept_pending_submitted","settingdesc_bistate_accept_pending_submitted","period_edit","edit","fullname","shortname","startdate","enddate","course_timing","title","desc","question","warning","course","period","yes","no","duration","years","year","weeks","week","days","day","rememberchoice","hidewarning","studyplan_associate","associate_cohorts","associate_users","add_association","delete_association","associations_empty","associations_search","cohorts","users","selected","name","context","item_text","select_conditions","item_configuration","item_course_text","select_grades","coursetiming_past","coursetiming_present","coursetiming_future","grade_include","grade_require","invalid","error","completion","completion_completed","completion_incomplete","aggregation_all","aggregation_any","aggregation_overall_all","aggregation_overall_any","completion_not_configured","configure_completion","badge","share_badge","dateissued","dateexpire","badgeinfo","component","props","type","Object","default","data","force_scales","selected_scale","result","text","created","mounted","updated","computed","scales","id","disabled","this","concat","advanced","methods","disable_autoenddate","self","methodname","args","studyplan_id","done","response","$bvModal","msgBoxConfirm","success","msg","fail","notification","exception","force_scales_start","okVariant","okTitle","cancelTitle","then","_this","scale_id","export_plan","format","undefined","includes","content","import_studylines","filename","_this2","location","reload","purge_studyline","force","cascade_cohortsync","msgBoxOk","modal_close","template","String","show","config","userfields","key","cohortfields","editdata","description","context_id","periods","Date","getFullYear","aggregation","aggregation_config","aggregation_parsed","aggregators","categories","category","path","ix","ag","defaultconfig","JSON","parse","e","warn","operation","cat","pathname","join","editPlanStart","mode","pages","editPlanFinish","method","stringify","$emit","moved_from","moved_to","moved","numberFilter","association","loading","search","associated","showModal","loadAssociations","cohortOptionModel","c","userOptionModel","u","firstname","lastname","map","searchCohorts","searchtext","like","exclude_id","cohortAssociate","requests","searchselected","i","r","push","cohort_id","cohortDisassociate","associatedselected","searchUsers","userAssociate","user_id","userDisassociate","editStart","editFinish","create","studyline","editmode","color","original","studyplan","slots","aggregation_info","useRequiredGrades","useItemCondition","page","studylines","$root","console","info","columns","columns_stylerule","s","countLineLayers","line","maxLayer","competencies","item","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","layers","Number","layerHeights","$on","onLineHeightChange","lineid","layerid","newheight","$refs","main","items","document","querySelectorAll","heightSum","forEach","el","height","getBoundingClientRect","heightStyle","style","deletable","onEdit","onDelete","slotindex","resizeListener","ResizeObserver","size","observe","unmounted","disconnect","slotkey","itm","listtype","dragacceptlist","courseHoverDummy","hover","current","now","pstart","pend","spanCss","datechanger","coursespan","periodspan","defaultchoice","hidewarn","onDrop","slot","$nextTick","relocateStudyItem","validate_course_period","_this3","onCut","iteminfo","onDragEnter","onDragLeave","first","last","canupdatecourse","defaultvalue","change_course_period","page_id","course_id","format_duration","dsi","toLocaleLowerCase","maxSpan","freeIndex","makeType","checkType","Boolean","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","_this4","connections","in","redrawLine","_this5","removeLine","out","highlight","setConfig","normalize","updateItem","continuation_id","doShowContext","hasContext","preventDefault","onCreatedConnection","onRemovedConnection","c_in","onRePositioned","onDisPositioned","re_id","onItemDeleted","item_id","onRedrawLines","hasConnectionsOut","hasConnectionsIn","dummy","setTimeout","_this6","beforeDestroy","$off","beforeUpdate","useItemConditions","configurationState","hasGrades","hasCompletions","configurationIcon","noenddate","grades","cgroup","includeChanged","newValue","g","required","requiredChanged","updateConditions","selectedgrades","guestmode","stringkeys","completion_icon","completion_tag","txt","showSpinner","canLoadMore","hasDetails","haschildren","hascourses","children","courses","onShowDetails"],"mappings":"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"}