diff --git a/amd/build/treestudyplan-components.min.js b/amd/build/treestudyplan-components.min.js
index d7f02eb..3c8ea44 100644
--- a/amd/build/treestudyplan-components.min.js
+++ b/amd/build/treestudyplan-components.min.js
@@ -1,3 +1,3 @@
-define("local_treestudyplan/treestudyplan-components",["exports","./util/string-helper","./util/date-helper","./util/fittext-vue"],(function(_exports,_stringHelper,_dateHelper,_fittextVue){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_fittextVue=(obj=_fittextVue)&&obj.__esModule?obj:{default:obj};var _default={install(Vue){Vue.use(_fittextVue.default);let strings=(0,_stringHelper.loadStrings)({studyplancard:{open:"open",noenddate:"noenddate",idnumber:"studyplan_idnumber",description:"studyplan_description",completed:"completed",details:"studyplan_details",suspended:"suspended"},details:{details:"studyplan_details"},extrafields:{show:"show@core"},prevnext:{prev:"prev@core",previous:"previous@core",next:"next@core",select:"selectanoptions@core"}});const ItemEventBus=new Vue;Vue.component("s-studyplan-card",{props:{value:{type:Object},open:{type:Boolean},ignoresuspend:{type:Boolean,default:!1}},data:()=>({text:strings.studyplancard}),computed:{timeless(){const plan=this.value;return!(plan.pages&&0!=plan.pages.length&&!plan.pages[0].timeless)},timing(){return(0,_dateHelper.studyplanTiming)(this.value)},dates(){const dates=(0,_dateHelper.studyplanDates)(this.value);return{start:(0,_dateHelper.formatDate)(dates.start),end:dates.end?(0,_dateHelper.formatDate)(dates.end):this.text.noenddate}},suspended(){return this.value.suspended&&!this.ignoresuspend}},methods:{onOpenClick(e){this.$emit("open",e)}},template:"\n \n \n \n \n
\n
\n
\n
\n {{ text.idnumber }}: {{ value.idnumber }}\n
\n
\n
\n \n
\n \n \n \n \n \n \n {{ text.open }}\n \n \n \n "}),Vue.component("s-progress-bar",{props:{value:{type:Number},min:{type:Number,default:()=>0},max:{type:Number,default:()=>1}},data:()=>({text:strings.studyplancard}),computed:{width_completed(){if(this.value){return 100*((this.value-this.min)/(this.max-this.min))}return 0},width_incomplete(){if(this.value){return 100*(1-(this.value-this.min)/(this.max-this.min))}return 100},percentage_complete(){if(this.value){const v=(this.value-this.min)/(this.max-this.min);return Math.round(100*v)+"%"}return"0%"}},template:"\n
\n
0\"\n :style=\"{width: width_completed+'%'}\"\n class='s-studyplan-card-progress-segment s-studyplan-card-progress-completed'\n >
\n
\n {{ percentage_complete}} {{ text.completed.toLowerCase() }} \n
\n
\n "}),Vue.component("s-studyline-header-heading",{props:{identifier:{type:Number,default:()=>0}},data:()=>({layerHeights:{}}),created(){ItemEventBus.$on("headerHeightChange",this.onHeaderHeightChange)},computed:{},methods:{onHeaderHeightChange(newheight,identifier){this.identifier==identifier&&this.$refs.main&&(this.$refs.main.style.height=`${newheight}px`)}},template:'\n \n '}),Vue.component("s-studyline-header-period",{props:{value:{type:Object},identifier:{type:Number,default:()=>0},mode:{type:String,default:"view"}},mounted(){const self=this;1==self.value.period&&(self.resizeListener=new ResizeObserver((()=>{if(self.$refs.main){const size=self.$refs.main.getBoundingClientRect();ItemEventBus.$emit("headerHeightChange",size.height,self.identifier)}})).observe(self.$refs.main))},unmounted(){this.resizeListener&&this.resizeListener.disconnect()},computed:{startdate(){return(0,_dateHelper.formatDate)(this.value.startdate)},enddate(){return(0,_dateHelper.formatDate)(this.value.enddate)},current(){if(this.value&&this.value.startdate&&this.value.enddate){const now=new Date,pstart=new Date(this.value.startdate),pend=new Date(this.value.enddate);return now>=pstart&&now({}),template:'\n {{ value.shortname }}\n {{ value.fullname }}
\n \n \n
\n
\n
\n '}),Vue.component("s-studyplan-details",{props:{value:{type:Object},variant:{type:String,default:()=>"info"},pill:{type:Boolean,default:()=>!1},size:{type:String,default:()=>""}},data:()=>({text:strings.details}),template:'\n \n \n {{ text.details}}\n \n \n \n \n \n \n \n \n \n \n \n \n '}),Vue.component("s-course-extrafields",{props:{value:{type:Array},variant:{type:String,default:()=>"info"},position:{type:String,default:()=>"below"},size:{type:String,default:()=>""}},data:()=>({text:strings.extrafields}),computed:{fields(){const fields=[];for(const ix in this.value){const field=this.value[ix];field.position==this.position&&field.value&&field.value.length>0&&fields.push(field)}return fields}},methods:{displaydate:field=>(0,_dateHelper.formatDate)(field.value,!1)},template:'\n \n
\n \n {{ field.title}} | \n \n {{ displaydate(field) }}\n {{ field.value }}\n \n {{text.show}}...\n \n \n \n | \n
\n
\n
\n '}),Vue.component("s-prevnext-selector",{props:{value:{type:Object,default:()=>null},options:{type:Array},grouped:{type:Boolean,default:!1},titlefield:{type:String,default:"title"},labelfield:{type:String,default:"label"},optionsfield:{type:String,default:"options"},defaultselectable:{type:Boolean,default:!1},variant:{type:String,default:""},arrows:{type:Boolean,default:!1}},data:()=>({text:strings.prevnext}),computed:{fields(){const f=[];if(this.defaultselectable&&f.push(null),this.grouped)for(const gix in this.options){const group=this.options[gix];for(const ix in group[this.optionsfield]){const v=group[this.optionsfield][ix];f.push(v)}}else for(const ix in this.options){const v=this.options[ix];f.push(v)}return f},bubblevalue:{get(){return this.value?this.value:null},set(v){this.$emit("input",v||null)}}},methods:{atFirst(){return!(this.fields.length>0)||this.fields[0]==this.value},atLast(){if(this.fields.length>0){const l=this.fields.length-1;return this.fields[l]==this.value}return!0},prev(){if(this.fields.length>0){const index=this.fields.indexOf(this.value);index>0&&(this.$emit("input",this.fields[index-1]),this.$emit("change",this.fields[index-1]))}},next(){if(this.fields.length>0){const index=this.fields.indexOf(this.value),l=this.fields.length-1;index>=0&&index\n {{text.prev}}\n \n {{text.select}}\n \n \n \n \n {{o[titlefield]}}\n \n \n \n \n {{o[titlefield]}}\n \n \n {{text.next}}\n \n '})}};return _exports.default=_default,_exports.default}));
+define("local_treestudyplan/treestudyplan-components",["exports","./util/string-helper","./util/date-helper","./util/fittext-vue","./util/settings"],(function(_exports,_stringHelper,_dateHelper,_fittextVue,_settings){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_fittextVue=(obj=_fittextVue)&&obj.__esModule?obj:{default:obj};var _default={install(Vue){Vue.use(_fittextVue.default);let strings=(0,_stringHelper.loadStrings)({studyplancard:{open:"open",noenddate:"noenddate",idnumber:"studyplan_idnumber",description:"studyplan_description",completed:"completed",details:"studyplan_details",suspended:"suspended"},details:{details:"studyplan_details"},extrafields:{show:"show@core"},prevnext:{prev:"prev@core",previous:"previous@core",next:"next@core",select:"selectanoptions@core"}});const ItemEventBus=new Vue;Vue.component("s-studyplan-card",{props:{value:{type:Object},open:{type:Boolean},ignoresuspend:{type:Boolean,default:!1}},data:()=>({text:strings.studyplancard}),computed:{timeless(){const plan=this.value;return!(plan.pages&&0!=plan.pages.length&&!plan.pages[0].timeless)},timing(){return(0,_dateHelper.studyplanTiming)(this.value)},dates(){const dates=(0,_dateHelper.studyplanDates)(this.value);return{start:(0,_dateHelper.formatDate)(dates.start),end:dates.end?(0,_dateHelper.formatDate)(dates.end):this.text.noenddate}},suspended(){return this.value.suspended&&!this.ignoresuspend}},methods:{onOpenClick(e){this.$emit("open",e)}},template:"\n \n \n \n \n
\n
\n
\n
\n {{ text.idnumber }}: {{ value.idnumber }}\n
\n
\n
\n \n
\n \n \n \n \n \n \n {{ text.open }}\n \n \n \n "}),Vue.component("s-progress-bar",{props:{value:{type:Number},min:{type:Number,default:()=>0},max:{type:Number,default:()=>1}},data:()=>({text:strings.studyplancard}),computed:{width_completed(){if(this.value){return 100*((this.value-this.min)/(this.max-this.min))}return 0},width_incomplete(){if(this.value){return 100*(1-(this.value-this.min)/(this.max-this.min))}return 100},percentage_complete(){if(this.value){const v=(this.value-this.min)/(this.max-this.min);return Math.round(100*v)+"%"}return"0%"}},template:"\n \n
0\"\n :style=\"{width: width_completed+'%'}\"\n class='s-studyplan-card-progress-segment s-studyplan-card-progress-completed'\n >
\n
\n {{ percentage_complete}} {{ text.completed.toLowerCase() }} \n
\n
\n "}),Vue.component("s-studyline-header-heading",{props:{identifier:{type:Number,default:()=>0}},data:()=>({layerHeights:{}}),created(){ItemEventBus.$on("headerHeightChange",this.onHeaderHeightChange)},computed:{},methods:{onHeaderHeightChange(newheight,identifier){this.identifier==identifier&&this.$refs.main&&(this.$refs.main.style.height=`${newheight}px`)}},template:'\n \n '}),Vue.component("s-studyline-header-period",{props:{value:{type:Object},identifier:{type:Number,default:()=>0},mode:{type:String,default:"view"}},mounted(){const self=this;1==self.value.period&&(self.resizeListener=new ResizeObserver((()=>{if(self.$refs.main){const size=self.$refs.main.getBoundingClientRect();ItemEventBus.$emit("headerHeightChange",size.height,self.identifier)}})).observe(self.$refs.main))},unmounted(){this.resizeListener&&this.resizeListener.disconnect()},computed:{startdate(){return(0,_dateHelper.formatDate)(this.value.startdate)},enddate(){return(0,_dateHelper.formatDate)(this.value.enddate)},current(){if(this.value&&this.value.startdate&&this.value.enddate){const now=new Date,pstart=new Date(this.value.startdate),pend=new Date(this.value.enddate);return now>=pstart&&now({}),template:'\n {{ value.shortname }}\n {{ value.fullname }}
\n \n \n
\n
\n
\n '}),Vue.component("s-studyplan-details",{props:{value:{type:Object},variant:{type:String,default:()=>"info"},pill:{type:Boolean,default:()=>!1},size:{type:String,default:()=>""}},data:()=>({text:strings.details}),template:'\n \n \n {{ text.details}}\n \n \n \n \n \n \n \n \n \n \n \n \n '}),Vue.component("s-course-extrafields",{props:{value:{type:Array},variant:{type:String,default:()=>"info"},position:{type:String,default:()=>"below"},size:{type:String,default:()=>""}},data:()=>({text:strings.extrafields}),computed:{fields(){const fields=[];for(const ix in this.value){const field=this.value[ix];field.position==this.position&&field.value&&field.value.length>0&&fields.push(field)}return fields}},methods:{displaydate:field=>(0,_dateHelper.formatDate)(field.value,!1)},template:'\n \n
\n \n {{ field.title}} | \n \n {{ displaydate(field) }}\n {{ field.value }}\n \n {{text.show}}...\n \n \n \n | \n
\n
\n
\n '}),Vue.component("s-prevnext-selector",{props:{value:{type:Object,default:()=>null},options:{type:Array},grouped:{type:Boolean,default:!1},titlefield:{type:String,default:"title"},labelfield:{type:String,default:"label"},optionsfield:{type:String,default:"options"},defaultselectable:{type:Boolean,default:!1},variant:{type:String,default:""},arrows:{type:Boolean,default:!1}},data:()=>({showarrows:(0,_settings.settings)("showprevnextarrows"),text:strings.prevnext}),computed:{fields(){const f=[];if(this.defaultselectable&&f.push(null),this.grouped)for(const gix in this.options){const group=this.options[gix];for(const ix in group[this.optionsfield]){const v=group[this.optionsfield][ix];f.push(v)}}else for(const ix in this.options){const v=this.options[ix];f.push(v)}return f},bubblevalue:{get(){return this.value?this.value:null},set(v){this.$emit("input",v||null)}}},methods:{atFirst(){return!(this.fields.length>0)||this.fields[0]==this.value},atLast(){if(this.fields.length>0){const l=this.fields.length-1;return this.fields[l]==this.value}return!0},prev(){if(this.fields.length>0){const index=this.fields.indexOf(this.value);index>0&&(this.$emit("input",this.fields[index-1]),this.$emit("change",this.fields[index-1]))}},next(){if(this.fields.length>0){const index=this.fields.indexOf(this.value),l=this.fields.length-1;index>=0&&index\n {{text.prev}} \n {{text.select}}\n \n \n \n \n {{o[titlefield]}}\n \n \n \n \n {{o[titlefield]}}\n \n {{text.next}}\n \n '})}};return _exports.default=_default,_exports.default}));
//# sourceMappingURL=treestudyplan-components.min.js.map
\ No newline at end of file
diff --git a/amd/build/treestudyplan-components.min.js.map b/amd/build/treestudyplan-components.min.js.map
index 4c2a934..64686aa 100644
--- a/amd/build/treestudyplan-components.min.js.map
+++ b/amd/build/treestudyplan-components.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"treestudyplan-components.min.js","sources":["../src/treestudyplan-components.js"],"sourcesContent":["/* eslint no-var: \"error\"*/\n/* eslint no-console: \"off\"*/\n/* eslint camelcase: \"off\" */\n/* eslint-disable no-trailing-spaces */\n/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n\nimport {loadStrings} from './util/string-helper';\nimport {formatDate, studyplanDates, studyplanTiming} from './util/date-helper';\nimport FitTextVue from './util/fittext-vue';\n\n\nexport default {\n\n install(Vue /* ,options */) {\n Vue.use(FitTextVue);\n\n let strings = loadStrings({\n studyplancard: {\n open: \"open\",\n noenddate: \"noenddate\",\n idnumber: \"studyplan_idnumber\",\n description: \"studyplan_description\",\n completed: \"completed\",\n details: \"studyplan_details\",\n suspended: \"suspended\",\n },\n details: {\n details: \"studyplan_details\",\n },\n extrafields: {\n show: \"show@core\"\n },\n prevnext: {\n prev: \"prev@core\",\n previous: \"previous@core\",\n next: \"next@core\",\n select: \"selectanoptions@core\",\n }\n });\n // Create new eventbus for interaction between item components\n const ItemEventBus = new Vue();\n\n Vue.component('s-studyplan-card', {\n props: {\n value: {\n type: Object,\n },\n open: {\n type: Boolean\n },\n ignoresuspend: {\n type: Boolean,\n 'default': false,\n },\n },\n data() {\n return {\n text: strings.studyplancard\n };\n },\n computed: {\n timeless() {\n const plan = this.value;\n if (!plan.pages || plan.pages.length == 0 || plan.pages[0].timeless) {\n return true;\n } else {\n return false;\n }\n },\n timing() {\n return studyplanTiming(this.value);\n },\n dates() {\n const dates = studyplanDates(this.value);\n return {\n start: formatDate(dates.start),\n end: (dates.end) ? formatDate(dates.end) : this.text.noenddate,\n };\n },\n suspended() {\n return (this.value.suspended && !this.ignoresuspend);\n }\n \n },\n methods: {\n onOpenClick(e) {\n this.$emit('open', e);\n }\n },\n template: `\n \n \n \n \n
\n
\n
\n
\n {{ text.idnumber }}: {{ value.idnumber }}\n
\n
\n
\n \n
\n \n \n \n \n \n \n {{ text.open }}\n \n \n \n `,\n });\n\n Vue.component('s-progress-bar', {\n props: {\n value: {\n type: Number, \n },\n min: {\n type: Number,\n default() {\n return 0;\n }\n },\n max: {\n type: Number,\n default() {\n return 1;\n }\n }\n },\n data() {\n return {\n text: strings.studyplancard\n };\n },\n computed: {\n width_completed() {\n if (this.value) {\n const v = ((this.value - this.min) / (this.max - this.min));\n return v * 100;\n } else {\n return 0;\n }\n },\n width_incomplete() {\n if (this.value) {\n const v = ((this.value - this.min) / (this.max - this.min));\n return (1 - v) * 100;\n } else {\n return 100;\n }\n },\n percentage_complete() {\n if (this.value) {\n const v = ((this.value - this.min) / (this.max - this.min));\n return Math.round(v * 100) + \"%\";\n } else {\n return \"0%\";\n }\n }\n },\n template: `\n \n
0\"\n :style=\"{width: width_completed+'%'}\"\n class='s-studyplan-card-progress-segment s-studyplan-card-progress-completed'\n >
\n
\n {{ percentage_complete}} {{ text.completed.toLowerCase() }} \n
\n
\n `,\n });\n\n /*\n * S-STUDYLINE-HEADER-HEADING\n * The only reasing this is not a simple empty div, is the fact that the header height\n * needs to match that of the period headers\n */\n Vue.component('s-studyline-header-heading', {\n props: {\n identifier: {\n type: Number, // Page reference.\n default() {\n return 0;\n }\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('headerHeightChange', this.onHeaderHeightChange);\n },\n computed: {\n\n },\n methods: {\n onHeaderHeightChange(newheight, identifier) {\n if (this.identifier == identifier) {\n if (this.$refs.main) {\n this.$refs.main.style.height = `${newheight}px`;\n }\n }\n }\n },\n template: `\n \n `,\n });\n\n Vue.component('s-studyline-header-period', {\n props: {\n value: {\n type: Object, // Dict with layer as index\n },\n identifier: {\n type: Number, // Page reference.\n default() {\n return 0;\n }\n },\n mode: {\n type: String,\n 'default': \"view\",\n }\n },\n mounted() {\n const self = this;\n if (self.value.period == 1) {\n self.resizeListener = new ResizeObserver(() => {\n if (self.$refs.main) {\n const size = self.$refs.main.getBoundingClientRect();\n ItemEventBus.$emit('headerHeightChange', size.height, self.identifier);\n }\n }).observe(self.$refs.main);\n }\n },\n unmounted() {\n if (this.resizeListener) {\n this.resizeListener.disconnect();\n }\n },\n computed: {\n startdate() {\n return formatDate(this.value.startdate);\n },\n enddate() {\n return formatDate(this.value.enddate);\n },\n current() {\n if (this.value && this.value.startdate && this.value.enddate) {\n const now = new Date();\n const pstart = new Date(this.value.startdate);\n const pend = new Date(this.value.enddate);\n return (now >= pstart && now < pend);\n } else {\n return false;\n }\n }\n\n },\n data() {\n return {\n };\n },\n template: `\n {{ value.shortname }}\n {{ value.fullname }}
\n \n \n
0\" \n class=\"s-studyline-header-period-datespan small\">\n {{ startdate }}\n - 0\">{{ enddate }}∞\n
\n
\n
\n `,\n });\n\n\n Vue.component('s-studyplan-details', {\n props: {\n value: {\n type: Object, \n },\n variant: {\n type: String,\n default() {\n return \"info\";\n }\n },\n pill: {\n type: Boolean,\n default() {\n return false;\n }\n },\n size: {\n type: String,\n default() {\n return \"\";\n }\n }\n },\n data() {\n return {\n text: strings.details,\n };\n },\n template: `\n \n \n {{ text.details}}\n \n \n \n \n \n \n \n \n \n \n \n \n `,\n });\n\n Vue.component('s-course-extrafields', {\n props: {\n value: {\n type: Array, \n },\n variant: {\n type: String,\n default() {\n return \"info\";\n }\n },\n position: {\n type: String,\n default() {\n return \"below\";\n }\n },\n size: {\n type: String,\n default() {\n return \"\";\n }\n }\n },\n data() {\n return {\n text: strings.extrafields,\n };\n },\n computed: {\n fields() {\n const fields = [];\n for (const ix in this.value) {\n const field = this.value[ix];\n if (field.position == this.position && field.value && field.value.length > 0) {\n fields.push(field);\n }\n }\n return fields;\n },\n },\n methods: {\n displaydate(field) {\n return formatDate(field.value, false);\n },\n },\n template: `\n 0)?position:'empty')\">\n
0\">\n \n {{ field.title}} | \n \n {{ displaydate(field) }}\n {{ field.value }}\n \n {{text.show}}...\n \n \n \n | \n
\n
\n
\n `,\n });\n\n Vue.component('s-prevnext-selector', {\n props: {\n value: {\n type: Object, \n default() {\n return null;\n }\n },\n options: {\n type: Array,\n },\n grouped: {\n type: Boolean,\n 'default': false,\n },\n titlefield: {\n type: String,\n 'default': \"title\",\n },\n labelfield: {\n type: String,\n 'default': \"label\",\n },\n optionsfield: {\n type: String,\n 'default': \"options\",\n },\n defaultselectable: {\n type: Boolean,\n 'default': false,\n },\n variant: {\n type: String,\n 'default': \"\",\n },\n arrows: {\n type: Boolean,\n 'default': false,\n },\n },\n data() {\n return {\n text: strings.prevnext,\n };\n },\n computed: {\n fields() {\n const f = [];\n if (this.defaultselectable) {\n f.push(null);\n }\n if (this.grouped) {\n for (const gix in this.options) {\n const group = this.options[gix];\n for (const ix in group[this.optionsfield]) {\n const v = group[this.optionsfield][ix];\n f.push(v);\n }\n }\n } else {\n for (const ix in this.options) {\n const v = this.options[ix];\n f.push(v);\n }\n }\n return f;\n },\n bubblevalue: {\n get() {\n return (this.value) ? this.value : null;\n },\n set(v) {\n this.$emit('input', (v) ? v : null);\n },\n }\n },\n methods: {\n atFirst() {\n if (this.fields.length > 0) {\n return this.fields[0] == this.value;\n }\n return true; // Since it disables the button, do so if pressing it would make no sense.\n },\n atLast() {\n if (this.fields.length > 0) {\n const l = this.fields.length - 1;\n return this.fields[l] == this.value;\n }\n return true; // Since it disables the button, do so if pressing it would make no sense.\n },\n prev() {\n if (this.fields.length > 0) {\n const index = this.fields.indexOf(this.value);\n if (index > 0) {\n this.$emit(\"input\", this.fields[index - 1]);\n this.$emit(\"change\", this.fields[index - 1]);\n }\n }\n },\n next() {\n if (this.fields.length > 0) {\n const index = this.fields.indexOf(this.value);\n const l = this.fields.length - 1;\n if (index >= 0 && index < l) {\n this.$emit(\"input\", this.fields[index + 1]);\n this.$emit(\"change\", this.fields[index + 1]);\n }\n }\n },\n selectedchanged(value) {\n this.$emit(\"change\", value);\n }\n },\n template: `\n \n {{text.prev}}\n \n {{text.select}}\n \n \n \n 0\"\n :label=\"g[labelfield]\"\n >\n {{o[titlefield]}}\n \n \n \n \n {{o[titlefield]}}\n \n \n {{text.next}}\n
\n `,\n });\n\n\n }\n};"],"names":["install","Vue","use","FitTextVue","strings","studyplancard","open","noenddate","idnumber","description","completed","details","suspended","extrafields","show","prevnext","prev","previous","next","select","ItemEventBus","component","props","value","type","Object","Boolean","ignoresuspend","data","text","computed","timeless","plan","this","pages","length","timing","dates","start","end","methods","onOpenClick","e","$emit","template","Number","min","default","max","width_completed","width_incomplete","percentage_complete","v","Math","round","identifier","layerHeights","created","$on","onHeaderHeightChange","newheight","$refs","main","style","height","mode","String","mounted","self","period","resizeListener","ResizeObserver","size","getBoundingClientRect","observe","unmounted","disconnect","startdate","enddate","current","now","Date","pstart","pend","variant","pill","Array","position","fields","ix","field","push","displaydate","options","grouped","titlefield","labelfield","optionsfield","defaultselectable","arrows","f","gix","group","bubblevalue","get","set","atFirst","atLast","l","index","indexOf","selectedchanged"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"treestudyplan-components.min.js","sources":["../src/treestudyplan-components.js"],"sourcesContent":["/* eslint no-var: \"error\"*/\n/* eslint no-console: \"off\"*/\n/* eslint camelcase: \"off\" */\n/* eslint-disable no-trailing-spaces */\n/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n\nimport {loadStrings} from './util/string-helper';\nimport {formatDate, studyplanDates, studyplanTiming} from './util/date-helper';\nimport FitTextVue from './util/fittext-vue';\nimport {settings} from \"./util/settings\";\n\nexport default {\n\n install(Vue /* ,options */) {\n Vue.use(FitTextVue);\n\n let strings = loadStrings({\n studyplancard: {\n open: \"open\",\n noenddate: \"noenddate\",\n idnumber: \"studyplan_idnumber\",\n description: \"studyplan_description\",\n completed: \"completed\",\n details: \"studyplan_details\",\n suspended: \"suspended\",\n },\n details: {\n details: \"studyplan_details\",\n },\n extrafields: {\n show: \"show@core\"\n },\n prevnext: {\n prev: \"prev@core\",\n previous: \"previous@core\",\n next: \"next@core\",\n select: \"selectanoptions@core\",\n }\n });\n // Create new eventbus for interaction between item components\n const ItemEventBus = new Vue();\n\n Vue.component('s-studyplan-card', {\n props: {\n value: {\n type: Object,\n },\n open: {\n type: Boolean\n },\n ignoresuspend: {\n type: Boolean,\n 'default': false,\n },\n },\n data() {\n return {\n text: strings.studyplancard\n };\n },\n computed: {\n timeless() {\n const plan = this.value;\n if (!plan.pages || plan.pages.length == 0 || plan.pages[0].timeless) {\n return true;\n } else {\n return false;\n }\n },\n timing() {\n return studyplanTiming(this.value);\n },\n dates() {\n const dates = studyplanDates(this.value);\n return {\n start: formatDate(dates.start),\n end: (dates.end) ? formatDate(dates.end) : this.text.noenddate,\n };\n },\n suspended() {\n return (this.value.suspended && !this.ignoresuspend);\n }\n \n },\n methods: {\n onOpenClick(e) {\n this.$emit('open', e);\n }\n },\n template: `\n \n \n \n \n
\n
\n
\n
\n {{ text.idnumber }}: {{ value.idnumber }}\n
\n
\n
\n \n
\n \n \n \n \n \n \n {{ text.open }}\n \n \n \n `,\n });\n\n Vue.component('s-progress-bar', {\n props: {\n value: {\n type: Number, \n },\n min: {\n type: Number,\n default() {\n return 0;\n }\n },\n max: {\n type: Number,\n default() {\n return 1;\n }\n }\n },\n data() {\n return {\n text: strings.studyplancard\n };\n },\n computed: {\n width_completed() {\n if (this.value) {\n const v = ((this.value - this.min) / (this.max - this.min));\n return v * 100;\n } else {\n return 0;\n }\n },\n width_incomplete() {\n if (this.value) {\n const v = ((this.value - this.min) / (this.max - this.min));\n return (1 - v) * 100;\n } else {\n return 100;\n }\n },\n percentage_complete() {\n if (this.value) {\n const v = ((this.value - this.min) / (this.max - this.min));\n return Math.round(v * 100) + \"%\";\n } else {\n return \"0%\";\n }\n }\n },\n template: `\n \n
0\"\n :style=\"{width: width_completed+'%'}\"\n class='s-studyplan-card-progress-segment s-studyplan-card-progress-completed'\n >
\n
\n {{ percentage_complete}} {{ text.completed.toLowerCase() }} \n
\n
\n `,\n });\n\n /*\n * S-STUDYLINE-HEADER-HEADING\n * The only reasing this is not a simple empty div, is the fact that the header height\n * needs to match that of the period headers\n */\n Vue.component('s-studyline-header-heading', {\n props: {\n identifier: {\n type: Number, // Page reference.\n default() {\n return 0;\n }\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('headerHeightChange', this.onHeaderHeightChange);\n },\n computed: {\n\n },\n methods: {\n onHeaderHeightChange(newheight, identifier) {\n if (this.identifier == identifier) {\n if (this.$refs.main) {\n this.$refs.main.style.height = `${newheight}px`;\n }\n }\n }\n },\n template: `\n \n `,\n });\n\n Vue.component('s-studyline-header-period', {\n props: {\n value: {\n type: Object, // Dict with layer as index\n },\n identifier: {\n type: Number, // Page reference.\n default() {\n return 0;\n }\n },\n mode: {\n type: String,\n 'default': \"view\",\n }\n },\n mounted() {\n const self = this;\n if (self.value.period == 1) {\n self.resizeListener = new ResizeObserver(() => {\n if (self.$refs.main) {\n const size = self.$refs.main.getBoundingClientRect();\n ItemEventBus.$emit('headerHeightChange', size.height, self.identifier);\n }\n }).observe(self.$refs.main);\n }\n },\n unmounted() {\n if (this.resizeListener) {\n this.resizeListener.disconnect();\n }\n },\n computed: {\n startdate() {\n return formatDate(this.value.startdate);\n },\n enddate() {\n return formatDate(this.value.enddate);\n },\n current() {\n if (this.value && this.value.startdate && this.value.enddate) {\n const now = new Date();\n const pstart = new Date(this.value.startdate);\n const pend = new Date(this.value.enddate);\n return (now >= pstart && now < pend);\n } else {\n return false;\n }\n }\n\n },\n data() {\n return {\n };\n },\n template: `\n {{ value.shortname }}\n {{ value.fullname }}
\n \n \n
0\" \n class=\"s-studyline-header-period-datespan small\">\n {{ startdate }}\n - 0\">{{ enddate }}∞\n
\n
\n
\n `,\n });\n\n\n Vue.component('s-studyplan-details', {\n props: {\n value: {\n type: Object, \n },\n variant: {\n type: String,\n default() {\n return \"info\";\n }\n },\n pill: {\n type: Boolean,\n default() {\n return false;\n }\n },\n size: {\n type: String,\n default() {\n return \"\";\n }\n }\n },\n data() {\n return {\n text: strings.details,\n };\n },\n template: `\n \n \n {{ text.details}}\n \n \n \n \n \n \n \n \n \n \n \n \n `,\n });\n\n Vue.component('s-course-extrafields', {\n props: {\n value: {\n type: Array, \n },\n variant: {\n type: String,\n default() {\n return \"info\";\n }\n },\n position: {\n type: String,\n default() {\n return \"below\";\n }\n },\n size: {\n type: String,\n default() {\n return \"\";\n }\n }\n },\n data() {\n return {\n text: strings.extrafields,\n };\n },\n computed: {\n fields() {\n const fields = [];\n for (const ix in this.value) {\n const field = this.value[ix];\n if (field.position == this.position && field.value && field.value.length > 0) {\n fields.push(field);\n }\n }\n return fields;\n },\n },\n methods: {\n displaydate(field) {\n return formatDate(field.value, false);\n },\n },\n template: `\n 0)?position:'empty')\">\n
0\">\n \n {{ field.title}} | \n \n {{ displaydate(field) }}\n {{ field.value }}\n \n {{text.show}}...\n \n \n \n | \n
\n
\n
\n `,\n });\n\n Vue.component('s-prevnext-selector', {\n props: {\n value: {\n type: Object, \n default() {\n return null;\n }\n },\n options: {\n type: Array,\n },\n grouped: {\n type: Boolean,\n 'default': false,\n },\n titlefield: {\n type: String,\n 'default': \"title\",\n },\n labelfield: {\n type: String,\n 'default': \"label\",\n },\n optionsfield: {\n type: String,\n 'default': \"options\",\n },\n defaultselectable: {\n type: Boolean,\n 'default': false,\n },\n variant: {\n type: String,\n 'default': \"\",\n },\n arrows: {\n type: Boolean,\n 'default': false,\n },\n },\n data() {\n return {\n showarrows: settings(\"showprevnextarrows\"),\n text: strings.prevnext,\n };\n },\n computed: {\n fields() {\n const f = [];\n if (this.defaultselectable) {\n f.push(null);\n }\n if (this.grouped) {\n for (const gix in this.options) {\n const group = this.options[gix];\n for (const ix in group[this.optionsfield]) {\n const v = group[this.optionsfield][ix];\n f.push(v);\n }\n }\n } else {\n for (const ix in this.options) {\n const v = this.options[ix];\n f.push(v);\n }\n }\n return f;\n },\n bubblevalue: {\n get() {\n return (this.value) ? this.value : null;\n },\n set(v) {\n this.$emit('input', (v) ? v : null);\n },\n }\n },\n methods: {\n atFirst() {\n if (this.fields.length > 0) {\n return this.fields[0] == this.value;\n }\n return true; // Since it disables the button, do so if pressing it would make no sense.\n },\n atLast() {\n if (this.fields.length > 0) {\n const l = this.fields.length - 1;\n return this.fields[l] == this.value;\n }\n return true; // Since it disables the button, do so if pressing it would make no sense.\n },\n prev() {\n if (this.fields.length > 0) {\n const index = this.fields.indexOf(this.value);\n if (index > 0) {\n this.$emit(\"input\", this.fields[index - 1]);\n this.$emit(\"change\", this.fields[index - 1]);\n }\n }\n },\n next() {\n if (this.fields.length > 0) {\n const index = this.fields.indexOf(this.value);\n const l = this.fields.length - 1;\n if (index >= 0 && index < l) {\n this.$emit(\"input\", this.fields[index + 1]);\n this.$emit(\"change\", this.fields[index + 1]);\n }\n }\n },\n selectedchanged(value) {\n this.$emit(\"change\", value);\n }\n },\n template: `\n \n {{text.prev}} \n {{text.select}}\n \n \n \n 0\"\n :label=\"g[labelfield]\"\n >\n {{o[titlefield]}}\n \n \n \n \n {{o[titlefield]}}\n \n {{text.next}}\n
\n `,\n });\n\n\n }\n};"],"names":["install","Vue","use","FitTextVue","strings","studyplancard","open","noenddate","idnumber","description","completed","details","suspended","extrafields","show","prevnext","prev","previous","next","select","ItemEventBus","component","props","value","type","Object","Boolean","ignoresuspend","data","text","computed","timeless","plan","this","pages","length","timing","dates","start","end","methods","onOpenClick","e","$emit","template","Number","min","default","max","width_completed","width_incomplete","percentage_complete","v","Math","round","identifier","layerHeights","created","$on","onHeaderHeightChange","newheight","$refs","main","style","height","mode","String","mounted","self","period","resizeListener","ResizeObserver","size","getBoundingClientRect","observe","unmounted","disconnect","startdate","enddate","current","now","Date","pstart","pend","variant","pill","Array","position","fields","ix","field","push","displaydate","options","grouped","titlefield","labelfield","optionsfield","defaultselectable","arrows","showarrows","f","gix","group","bubblevalue","get","set","atFirst","atLast","l","index","indexOf","selectedchanged"],"mappings":"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"}
\ No newline at end of file
diff --git a/amd/src/treestudyplan-components.js b/amd/src/treestudyplan-components.js
index 936d8c4..95e105a 100644
--- a/amd/src/treestudyplan-components.js
+++ b/amd/src/treestudyplan-components.js
@@ -8,7 +8,7 @@
import {loadStrings} from './util/string-helper';
import {formatDate, studyplanDates, studyplanTiming} from './util/date-helper';
import FitTextVue from './util/fittext-vue';
-
+import {settings} from "./util/settings";
export default {
@@ -498,6 +498,7 @@ export default {
},
data() {
return {
+ showarrows: settings("showprevnextarrows"),
text: strings.prevnext,
};
},
@@ -571,10 +572,12 @@ export default {
},
template: `
- {{text.prev}}
- {{text.prev}}
{{o[titlefield]}}
-
- {{text.next}}
+ >{{text.next}}
`,
});
diff --git a/lang/en/local_treestudyplan.php b/lang/en/local_treestudyplan.php
index 459aff5..0c7cb13 100644
--- a/lang/en/local_treestudyplan.php
+++ b/lang/en/local_treestudyplan.php
@@ -128,12 +128,12 @@ $string["settingdesc_infofields_heading"] = 'Select up to 5 fields or custom fie
$string["setting_hivizdropslots"] = 'High visibility drop fields';
$string["settingdesc_hivizdropslots"] = 'Give the drop fields when editing a study plan extra visibility.';
-
$string["setting_toolboxleft"] = 'Toolbar left side by default';
$string["settingdesc_toolboxleft"] = 'Show the course and component toolbar on the left by default, instead of the right side of the screen.';
-
$string["setting_toolboxcoursesonly"] = 'Show only the courses in the toolbox';
$string["settingdesc_toolboxcoursesonly"] = 'Hide the badges and flow tabs in the toolbox and show only the courses.';
+$string["setting_showprevnextarrows"] = 'Show arrows next to student selector dropdowns';
+$string["settingdesc_showprevnextarrows"] = 'Show arrows for previous and next student in the student selector in coach and view mode.';
$string["drophere"] = "Drop here";
$string["infofield_position_above"] = 'Above course results';
diff --git a/lang/nl/local_treestudyplan.php b/lang/nl/local_treestudyplan.php
index d90090f..e2b4454 100644
--- a/lang/nl/local_treestudyplan.php
+++ b/lang/nl/local_treestudyplan.php
@@ -128,12 +128,12 @@ $string["settingdesc_infofields_heading"] = 'Kies tot 5 extra velden om in het c
$string["setting_hivizdropslots"] = 'Extra zichtbare sleepvelden';
$string["settingdesc_hivizdropslots"] = 'Maak de velden waar cursussen heen gesleept kunnen worden extra goed zichtbaar.';
-
$string["setting_toolboxleft"] = 'Toolbox standaard links';
$string["settingdesc_toolboxleft"] = 'Toon de toolbox met cursussen en componenten standaard links in plaats van rechts.';
-
$string["setting_toolboxcoursesonly"] = 'Toon alleen cursussen in toolbox';
$string["settingdesc_toolboxcoursesonly"] = 'Verberg de tabbladen "flow" en "badges" in de toolbox en toon alleen de cursussen.';
+$string["setting_showprevnextarrows"] = 'Toon pijltjes naast de studentselectie drop-down';
+$string["settingdesc_showprevnextarrows"] = 'Laat pijltjes zien voor de vorige en volgende student naast de drop-down box om een student te selecteren.';
$string["drophere"] = "Sleep hierheen";
$string["infofield_position_above"] = 'Boven cursusresultaten';
diff --git a/settings.php b/settings.php
index 86b45fd..8f978f4 100644
--- a/settings.php
+++ b/settings.php
@@ -150,6 +150,12 @@ if ($hassiteconfig) {
false,
));
+ $page->add(new admin_setting_configcheckbox('local_treestudyplan/showprevnextarrows',
+ get_string('setting_showprevnextarrows', 'local_treestudyplan'),
+ get_string('settingdesc_showprevnextarrows', 'local_treestudyplan'),
+ true,
+ ));
+
$page->add(new admin_setting_configcheckbox('local_treestudyplan/copystudylinesnewpage',
get_string('setting_copystudylinesnewpage', 'local_treestudyplan'),
get_string('settingdesc_copystudylinesnewpage', 'local_treestudyplan'),
@@ -234,6 +240,7 @@ if ($hassiteconfig) {
get_string('setting_competency_heading', 'local_treestudyplan'),
get_string('settingdesc_competency_heading', 'local_treestudyplan')
));
+
$page->add(new admin_setting_configtext('local_treestudyplan/competency_thresh_completed',
get_string('setting_competency_thresh_completed', 'local_treestudyplan'),
get_string('settingdesc_competency_thresh_completed', 'local_treestudyplan'),