/* 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: `
{{ text.idnumber }}: {{ value.idnumber }}
{{ text.open }}
`,
});
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 }}
`,
});
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: `
`,
});
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.prev}} {{text.select}}{{o[titlefield]}}
{{o[titlefield]}} {{text.next}}
`,
});
}
};