/*eslint no-var: "error"*/
/*eslint no-console: "off"*/
/*eslint-disable no-trailing-spaces */
/*eslint-env es6*/
// Put this file in path/to/plugin/amd/src
import {load_strings} from './util/string-helper';
import {format_date, studyplanDates, studyplanTiming} from './util/date-helper';
import FitTextVue from './util/fittext-vue';
export default {
install(Vue/*,options*/){
Vue.use(FitTextVue);
let strings = load_strings({
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: {
timing(){
return studyplanTiming(this.value);
},
dates(){
const dates = studyplanDates(this.value);
return {
start: format_date(dates.start),
end: (dates.end)?format_date(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;}
}
},
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 format_date(this.value.startdate);
},
enddate(){
return format_date(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 format_date(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 {
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}}
`,
});
}
};