/* eslint no-var: "error"*/ /* eslint no-console: "off"*/ /* eslint camelcase: "off" */ /* eslint-disable no-trailing-spaces */ /* eslint-env es6*/ // Put this file in path/to/plugin/amd/src 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 { install(Vue /* ,options */) { Vue.use(FitTextVue); let strings = 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", } }); // Create new eventbus for interaction between item components const ItemEventBus = new Vue(); Vue.component('s-studyplan-card', { props: { value: { type: Object, }, open: { type: Boolean }, ignoresuspend: { type: Boolean, 'default': false, }, }, data() { return { text: strings.studyplancard }; }, computed: { timeless() { const plan = this.value; if (!plan.pages || plan.pages.length == 0 || plan.pages[0].timeless) { return true; } else { return false; } }, timing() { return studyplanTiming(this.value); }, dates() { const dates = studyplanDates(this.value); return { start: formatDate(dates.start), end: (dates.end) ? formatDate(dates.end) : this.text.noenddate, }; }, suspended() { return (this.value.suspended && !this.ignoresuspend); } }, methods: { onOpenClick(e) { this.$emit('open', e); } }, template: `
{{value.name}}
{{text.suspended}}
{{ text.idnumber }}: {{ value.idnumber }}
`, }); Vue.component('s-progress-bar', { props: { value: { type: Number, }, min: { type: Number, default() { return 0; } }, max: { type: Number, default() { return 1; } } }, data() { return { text: strings.studyplancard }; }, computed: { width_completed() { if (this.value) { const v = ((this.value - this.min) / (this.max - this.min)); return v * 100; } else { return 0; } }, width_incomplete() { if (this.value) { const v = ((this.value - this.min) / (this.max - this.min)); return (1 - v) * 100; } else { return 100; } }, percentage_complete() { if (this.value) { const v = ((this.value - this.min) / (this.max - this.min)); return Math.round(v * 100) + "%"; } else { return "0%"; } } }, template: `
{{ percentage_complete}} {{ text.completed.toLowerCase() }}
`, }); /* * S-STUDYLINE-HEADER-HEADING * The only reasing this is not a simple empty div, is the fact that the header height * needs to match that of the period headers */ Vue.component('s-studyline-header-heading', { props: { identifier: { type: Number, // Page reference. default() { return 0; } } }, data() { return { layerHeights: {} }; }, created() { // Listener for the signal that a new connection was made and needs to be drawn // Sent by the incoming item - By convention, outgoing items are responsible for drawing the lines ItemEventBus.$on('headerHeightChange', this.onHeaderHeightChange); }, computed: { }, methods: { onHeaderHeightChange(newheight, identifier) { if (this.identifier == identifier) { if (this.$refs.main) { this.$refs.main.style.height = `${newheight}px`; } } } }, template: `
`, }); Vue.component('s-studyline-header-period', { props: { value: { type: Object, // Dict with layer as index }, identifier: { type: Number, // Page reference. default() { return 0; } }, mode: { type: String, 'default': "view", } }, mounted() { const self = this; if (self.value.period == 1) { 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() { if (this.resizeListener) { this.resizeListener.disconnect(); } }, computed: { startdate() { return formatDate(this.value.startdate); }, enddate() { return formatDate(this.value.enddate); }, current() { if (this.value && this.value.startdate && this.value.enddate) { const now = new Date(); const pstart = new Date(this.value.startdate); const pend = new Date(this.value.enddate); return (now >= pstart && now < pend); } else { return false; } } }, data() { return { }; }, template: `

{{ value.shortname }} {{ value.fullname }}
{{ startdate }} - {{ enddate }}

{{ startdate }} - {{ enddate }}

`, }); Vue.component('s-studyplan-details', { props: { value: { type: Object, }, variant: { type: String, default() { return "info"; } }, pill: { type: Boolean, default() { return false; } }, size: { type: String, default() { return ""; } } }, data() { return { text: strings.details, }; }, template: ` {{ text.details}} `, }); Vue.component('s-course-extrafields', { props: { value: { type: Array, }, variant: { type: String, default() { return "info"; } }, position: { type: String, default() { return "below"; } }, size: { type: String, default() { return ""; } } }, data() { return { text: strings.extrafields, }; }, computed: { fields() { const fields = []; for (const ix in this.value) { const field = this.value[ix]; if (field.position == this.position && field.value && field.value.length > 0) { fields.push(field); } } return fields; }, }, methods: { displaydate(field) { return formatDate(field.value, false); }, }, template: `
{{ field.title}} {{ displaydate(field) }} {{ field.value }} {{text.show}}...
`, }); Vue.component('s-prevnext-selector', { props: { value: { type: Object, default() { return null; } }, options: { type: Array, }, grouped: { type: Boolean, 'default': false, }, titlefield: { type: String, 'default': "title", }, labelfield: { type: String, 'default': "label", }, optionsfield: { type: String, 'default': "options", }, defaultselectable: { type: Boolean, 'default': false, }, variant: { type: String, 'default': "", }, arrows: { type: Boolean, 'default': false, }, }, data() { return { showarrows: settings("showprevnextarrows"), text: strings.prevnext, }; }, computed: { fields() { const f = []; if (this.defaultselectable) { f.push(null); } if (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) ? v : null); }, } }, methods: { atFirst() { if (this.fields.length > 0) { return this.fields[0] == this.value; } return true; // Since it disables the button, do so if pressing it would make no sense. }, atLast() { if (this.fields.length > 0) { const l = this.fields.length - 1; return this.fields[l] == this.value; } return true; // Since it disables the button, do so if pressing it would make no sense. }, prev() { if (this.fields.length > 0) { const index = this.fields.indexOf(this.value); if (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); const l = this.fields.length - 1; if (index >= 0 && index < l) { this.$emit("input", this.fields[index + 1]); this.$emit("change", this.fields[index + 1]); } } }, selectedchanged(value) { this.$emit("change", value); } }, template: `
{{text.select}}
`, }); } };