diff --git a/app.js b/app.js index 2c1bbc4..bbd1210 100644 --- a/app.js +++ b/app.js @@ -1,389 +1,521 @@ -if (!String.prototype.includes) { - String.prototype.includes = function () { - 'use strict'; - return String.prototype.indexOf.apply(this, arguments) !== -1; - }; -} -//extend FileReader -if (!FileReader.prototype.readAsBinaryString) { - FileReader.prototype.readAsBinaryString = function (fileData) { - var binary = ""; - var pt = this; - var reader = new FileReader(); - reader.onload = function (e) { - var bytes = new Uint8Array(reader.result); - var length = bytes.byteLength; - for (var i = 0; i < length; i++) { - binary += String.fromCharCode(bytes[i]); - } - //pt.result - readonly so assign binary - pt.content = binary; - $(pt).trigger('onload'); - } - reader.readAsArrayBuffer(file); - } -} - -var options = { - timepicker: { - twelveHour: false, - } -}; - -document.addEventListener('DOMContentLoaded', function() { - M.AutoInit(); - var elems = document.querySelectorAll('.timepicker'); - var timepickers = M.Timepicker.init(elems, options.timepicker); -}); -//localStorage persistence - -var SHIFT_STORAGE_KEY = "dienstplan_chrosey"; -var RULE_STORAGE_KEY = "regeln_chrosey"; -var shiftStorage = { - fetch: function () { - 'use strict'; - var parsed = JSON.parse(localStorage.getItem(SHIFT_STORAGE_KEY) || '[]'), - shifts = []; - parsed.forEach(function (el, index) { - var shift = Shift.thaw(el); - shift.id = index; - shifts.push(shift); - }); - shiftStorage.uid = shifts.length; - return shifts; - }, - save: function (shifts) { - 'use strict'; - var json = JSON.stringify(shifts) - localStorage.setItem(SHIFT_STORAGE_KEY, json); - }, - count: function () { - return JSON.parse(localStorage.getItem(SHIFT_STORAGE_KEY) || '[]').length; - } -}; -var ruleStorage = { - fetch: function () { - 'use strict'; - var parsed = JSON.parse(localStorage.getItem(RULE_STORAGE_KEY)) | []; - var rules = parsed.length > 0 - ? parsed.map((e,i) => { - var r = Rule.thaw(e); - r.id = i; - return r; - }) - : Rule.defaults(); - ruleStorage.uid = rules.length; - return rules; - }, - save: function (rules) { - 'use strict'; - var json = JSON.stringify(rules); - localStorage.setItem(RULE_STORAGE_KEY, json); - } -}; - -Vue.component('chip-input', { - template: ` -
- `, - data() { - return { - instance: null, - chips: [] - } - }, - - computed: { - chipsData() { - return this.instance.chipsData; - } - }, - - watch:{ - initData:{ - deep: true, - handler(n,o) { - if (n !== o) { - this.initialize(); - this.$emit('init'); - } - } - } - }, - props: { - name: String, - initData: Array - }, - - methods: { - initialize() { - this.chips = this.initData.map(e => e); - var el = $('#'+this.name)[0]; - this.instance = M.Chips.init(el, { - data: this.chips, - onChipAdd: () => { - this.$emit("change",this.chipsData); - }, - onChipDelete: () => { - this.$emit("change",this.chipsData); - } - }); - } - }, - - mounted() { - this.initialize(); - } -}); - -var app = new Vue({ - el: '#app', - data: { - shifts: shiftStorage.fetch(), - rules: ruleStorage.fetch(), - icsFile: null, - blob: null, - dp_sheet: '', - deletedShift: '', - remaining: shiftStorage.count(), - selectedShift: new Shift({}), - selectedShiftIndex: -1, - selectedRule: new Rule({}), - selectedRuleIndex: -1, - saveto: 'dienstplan.ics', - uploadFileName: "", - config: { - moment: { - parse_formats: [ - "ddd, DD/ MMM. 'YY HH:mm", - "ddd, DD/ MMM. YYYY HH:mm" - ], - parse_language: 'en', - display_language: 'de' - }, - toast: { - displayLength: 3000 - } - }, - }, - watch: { - shifts: { - handler: function (shifts) { - 'use strict'; - shiftStorage.save(shifts); - this.remaining = shifts.length; - this.makeToast("Änderungen gespeichert."); - }, - deep: true - }, - rules: { - handler: function (rules) { - 'use strict'; - ruleStorage.save(rules); - this.makeToast("Änderungen gespeichert."); - }, - deep: true - } - }, - - computed: { - groupedTermine() { - return _.groupBy(this.shifts, e => e.Datum); - } - }, - - methods: { - updateArten(value){ - this.selectedRule.Arten = value; - }, - - updateTitel(value){ - this.selectedRule.Titel = value; - }, - - makeToast(message) { - var toastOptions = this.config.toast; - toastOptions.html = message; - M.toast(toastOptions); - }, - - onFileChange: function (event) { - var files = event.target.files || event.dataTransfer.files; - this.handleInputFile(files[0]); - this.uploadFileName = files[0].name + " [" + Math.round(files[0].size / 1024) + " kB]"; - this.makeToast(this.uploadFileName + " ausgewählt"); - }, - - handleInputFile: function (file) { - var reader = new FileReader(); - var vm = this; - reader.onload = (e) => { - var data = !e ? reader.content : e.target.result; - var workbook = XLSX.read(data, { - type: 'binary', - cellDates: true, - }); - var isErfurterDienstplan = workbook.SheetNames.indexOf("Dienstplan") > -1; - - if(isErfurterDienstplan){ - vm.parseForErfurt(workbook.Sheets["Dienstplan"]); - } else { - var sheetName = workbook.SheetNames[0]; - vm.parseForStuttgart(workbook.Sheets[sheetName]); - } - }; - reader.readAsBinaryString(file); - }, - - parseForErfurt: function (dp) { - var arr = XLSX.utils.sheet_to_row_object_array(dp, { - range: 1 - }); - var vm = this; - var day; - - this.makeToast("Erfurter Dienstplan erkannt."); - - arr.forEach(element => { - moment.locale(vm.config.moment.parse_language); - if (element.hasOwnProperty('Datum')) { - day = moment(element.Datum); - } - if (element.hasOwnProperty('Dienst')) { - var time = element.Zeit ? moment(element.Zeit) : day; - var termin = { - datum: day.clone().hour(time.hour()).minute(time.minute()), - art: element.Dienst ? element.Dienst.trim() : "", - beschreibung: element.Bemerkung ? element.Bemerkung.trim(): "", - name: element.__EMPTY ? element.__EMPTY.trim() : "" - } - vm.addShift(new Shift(termin)); - } - }); - }, - - parseForStuttgart: function (dp) { - var arr = XLSX.utils.sheet_to_json(dp, { - header: "A", - blankrows: false, - }); - var vm = this; - var day; - - this.makeToast("Stuttgarter Dienstplan erkannt."); - - arr.forEach(element => { - moment.locale(vm.config.moment.parse_language); - if (element.hasOwnProperty('C')) { - day = moment(element.C); - } - if (element.hasOwnProperty('D') && moment(element.D, "HH:mm").isValid()) { - var termin = { - ort: element.H ? element.H.trim() : "", - art: element.E ? element.E.trim() : "", - beschreibung: element.H ? element.H.trim(): "", - name: element.F ? element.F.trim() : "" - } - var time = day.clone(); - if (typeof(element.D) === "object") { - time = moment(element.D); - termin.datum = day.clone().hour(time.hour()).minute(time.minute()); - } else if(element.D.indexOf("-") > -1 ) { - var tArray = element.D.split(" - "); - time = moment(tArray[0],"HH:mm"); - termin.datum = day.clone().hour(time.hour()).minute(time.minute()); - termin.ende = moment(tArray[1], "HH:mm").format("HH:mm"); - } - vm.addShift(new Shift(termin)); - - } - }); - }, - - addShift: function (shift) { - this.shifts.push(shift); - }, - - removeShift: function (shift) { - this.shifts.splice(this.shifts.indexOf(shift), 1); - this.makeToast(shift.VEventTitle + " gelöscht"); - }, - - cleanStorage: function () { - this.shifts = []; - this.makeToast("Alle Einträge gelöscht"); - }, - - createDownloadFile: function () { - var vCal = new VCalendar("Dienstplan Kalender"); - this.shifts.forEach(function (shift) { - vCal.add(shift.toVEvent()); - }); - var calString = vCal.toString(); - this.blob = new Blob([calString], { - type: 'text/plain' - }); - - if (this.icsFile !== null) { - window.URL.revokeObjectURL(this.icsFile); - } - - this.icsFile = window.URL.createObjectURL(this.blob); - this.makeToast(this.saveto + " erstellt."); - }, - - downloadFile: function () { - if (window.navigator.msSaveOrOpenBlob) { - window.navigator.msSaveOrOpenBlob(this.blob, this.saveto); - } - }, - - selectShift: function (shift) { - this.selectedShift = Shift.thaw(shift); - this.keepShift = shift; - M.updateTextFields(); - $('#shiftModal').modal('open'); - }, - - saveChanges: function (changedShift) { - this.shifts.splice(this.shifts.indexOf(this.keepShift), 1, changedShift); - - $('#shiftModal').modal('close'); - this.keepShift = ''; - this.selectedShift = ''; - }, - - discardChanges: function (changedShift) { - $('#shiftModal').modal('close'); - this.keepShift = ''; - this.selectedShift = ''; - }, - - editRule: function (rule) { - this.selectedRule = Rule.thaw(rule); - this.selectedRuleIndex = this.rules.indexOf(rule); - $('#ruleModal').modal('open'); - }, - - saveRule: function () { - this.rules[this.selectedRuleIndex] = this.selectedRule; - - $('#ruleModal').modal('close'); - this.selectedRule = new Rule(); - }, - - discardRule: function () { - $('#ruleModal').modal('close'); - - this.selectedRule = new Rule(); - } - - }, - directives: { - 'edit-focus': function (el, value) { - if (value) { - el.focus(); - } - } - } -}) +if (!String.prototype.includes) { + String.prototype.includes = function () { + 'use strict'; + return String.prototype.indexOf.apply(this, arguments) !== -1; + }; +} +//extend FileReader +if (!FileReader.prototype.readAsBinaryString) { + FileReader.prototype.readAsBinaryString = function (fileData) { + var binary = ""; + var pt = this; + var reader = new FileReader(); + reader.onload = function (e) { + var bytes = new Uint8Array(reader.result); + var length = bytes.byteLength; + for (var i = 0; i < length; i++) { + binary += String.fromCharCode(bytes[i]); + } + //pt.result - readonly so assign binary + pt.content = binary; + $(pt).trigger('onload'); + } + reader.readAsArrayBuffer(file); + } +} + +var options = { + timepicker: { + twelveHour: false, + } +}; + +document.addEventListener('DOMContentLoaded', function() { + M.AutoInit(); + var elems = document.querySelectorAll('.timepicker'); + var timepickers = M.Timepicker.init(elems, options.timepicker); +}); +//localStorage persistence + +var SHIFT_STORAGE_KEY = "dienstplan_chrosey"; +var RULE_STORAGE_KEY = "regeln_chrosey"; +var shiftStorage = { + fetch: function () { + 'use strict'; + var parsed = JSON.parse(localStorage.getItem(SHIFT_STORAGE_KEY) || '[]'), + shifts = []; + parsed.forEach(function (el, index) { + var shift = Shift.thaw(el); + shift.id = index; + shifts.push(shift); + }); + shiftStorage.uid = shifts.length; + return shifts; + }, + save: function (shifts) { + 'use strict'; + var json = JSON.stringify(shifts) + localStorage.setItem(SHIFT_STORAGE_KEY, json); + }, + count: function () { + return JSON.parse(localStorage.getItem(SHIFT_STORAGE_KEY) || '[]').length; + } +}; +var ruleStorage = { + fetch: function () { + 'use strict'; + var parsed = JSON.parse(localStorage.getItem(RULE_STORAGE_KEY)) | []; + var rules = parsed.length > 0 + ? parsed.map((e,i) => { + var r = Rule.thaw(e); + r.id = i; + return r; + }) + : Rule.defaults(); + ruleStorage.uid = rules.length; + return rules; + }, + save: function (rules) { + 'use strict'; + var json = JSON.stringify(rules); + localStorage.setItem(RULE_STORAGE_KEY, json); + } +}; + +Vue.component('ask-format-modal',{ + template: ` + + `, + data() { + return { + picked: null + } + }, + props: ["options"], + methods: { + submitPick() { + this.$emit('picked-format', this.picked); + $('#ask-format-modal').modal('close'); + } + } + +}); + +Vue.component('chip-input', { + template: ` +
+ `, + data() { + return { + instance: null, + chips: [] + } + }, + + computed: { + chipsData() { + return this.instance.chipsData; + } + }, + + watch:{ + initData:{ + deep: true, + handler(n,o) { + if (n !== o) { + this.initialize(); + this.$emit('init'); + } + } + } + }, + props: { + name: String, + initData: Array + }, + + methods: { + initialize() { + this.chips = this.initData.map(e => e); + var el = $('#'+this.name)[0]; + this.instance = M.Chips.init(el, { + data: this.chips, + onChipAdd: () => { + this.$emit("change",this.chipsData); + }, + onChipDelete: () => { + this.$emit("change",this.chipsData); + } + }); + } + }, + + mounted() { + this.initialize(); + } +}); + +var app = new Vue({ + el: '#app', + data: { + shifts: shiftStorage.fetch(), + rules: ruleStorage.fetch(), + icsFile: null, + blob: null, + dp_sheet: '', + deletedShift: '', + remaining: shiftStorage.count(), + selectedShift: new Shift({}), + selectedShiftIndex: -1, + selectedRule: new Rule({}), + selectedRuleIndex: -1, + saveto: 'dienstplan.ics', + uploadFileName: "", + availableFormats: ["Erfurt","Stuttgart","X"], + config: { + moment: { + parse_formats: [ + "ddd, DD/ MMM. 'YY HH:mm", + "ddd, DD/ MMM. YYYY HH:mm" + ], + parse_language: 'en', + display_language: 'de' + }, + toast: { + displayLength: 3000 + } + }, + workbook: null, + }, + watch: { + shifts: { + handler: function (shifts) { + 'use strict'; + shiftStorage.save(shifts); + this.remaining = shifts.length; + this.makeToast("Änderungen gespeichert."); + }, + deep: true + }, + rules: { + handler: function (rules) { + 'use strict'; + ruleStorage.save(rules); + this.makeToast("Änderungen gespeichert."); + }, + deep: true + } + }, + + computed: { + groupedTermine() { + return _.groupBy(this.shifts, e => e.Datum); + } + }, + + methods: { + updateArten(value){ + this.selectedRule.Arten = value; + }, + + updateTitel(value){ + this.selectedRule.Titel = value; + }, + + makeToast(message) { + var toastOptions = this.config.toast; + toastOptions.html = message; + M.toast(toastOptions); + }, + + onFileChange: function (event) { + var files = event.target.files || event.dataTransfer.files; + this.handleInputFile(files[0]); + this.uploadFileName = files[0].name + " [" + Math.round(files[0].size / 1024) + " kB]"; + this.makeToast(this.uploadFileName + " ausgewählt"); + }, + + handleInputFile: function (file) { + var reader = new FileReader(); + var vm = this; + reader.onload = (e) => { + var data = !e ? reader.content : e.target.result; + var workbook = XLSX.read(data, { + type: 'binary', + cellDates: true, + }); + var isErfurterDienstplan = workbook.SheetNames.indexOf("Dienstplan") > -1; + + if(isErfurterDienstplan){ + vm.parseForErfurt(workbook.Sheets["Dienstplan"]); + } else { + this.workbook = workbook; + this.askForDienstplanFormat(); + } + }; + reader.readAsBinaryString(file); + }, + + askForDienstplanFormat: function() { + this.makeToast("Dienstplanformat nicht erkannt."); + $('#ask-format-modal').modal("open"); + }, + + parseForErfurt: function (dp) { + var arr = XLSX.utils.sheet_to_row_object_array(dp, { + range: 1 + }); + var vm = this; + var day; + + this.makeToast("Erfurter Dienstplan erkannt."); + + arr.forEach(element => { + moment.locale(vm.config.moment.parse_language); + if (element.hasOwnProperty('Datum')) { + day = moment(element.Datum); + } + if (element.hasOwnProperty('Dienst')) { + var time = element.Zeit ? moment(element.Zeit) : day; + var termin = { + datum: day.clone().hour(time.hour()).minute(time.minute()), + art: element.Dienst ? element.Dienst.trim() : "", + beschreibung: element.Bemerkung ? element.Bemerkung.trim(): "", + name: element.__EMPTY ? element.__EMPTY.trim() : "" + } + vm.addShift(new Shift(termin)); + } + }); + }, + + parseForStuttgart: function (dp) { + var arr = XLSX.utils.sheet_to_json(dp, { + header: "A", + blankrows: false, + }); + var vm = this; + var day; + + this.makeToast("Stuttgarter Dienstplan erkannt."); + + arr.forEach(element => { + moment.locale(vm.config.moment.parse_language); + if (element.hasOwnProperty('C')) { + day = moment(element.C); + } + if (element.hasOwnProperty('D') && moment(element.D, "HH:mm").isValid()) { + var termin = { + ort: element.H ? element.H.trim() : "", + art: element.E ? element.E.trim() : "", + beschreibung: element.H ? element.H.trim(): "", + name: element.F ? element.F.trim() : "" + } + var time = day.clone(); + if (typeof(element.D) === "object") { + time = moment(element.D); + termin.datum = day.clone().hour(time.hour()).minute(time.minute()); + } else if(element.D.indexOf("-") > -1 ) { + var tArray = element.D.split(" - "); + time = moment(tArray[0],"HH:mm"); + termin.datum = day.clone().hour(time.hour()).minute(time.minute()); + termin.ende = moment(tArray[1], "HH:mm").format("HH:mm"); + } + vm.addShift(new Shift(termin)); + + } + }); + }, + + parseForX: function (dp, sheetName) { + moment.locale(this.config.moment.parse_language); + var arr = XLSX.utils.sheet_to_json(dp, { + header: "A", + blankrows: false, + }); + var vm = this; + var month = moment(sheetName.substr(sheetName.indexOf(" ")+1), "MMMM YYYY", "de"); + var day; + + arr.forEach(element => { + var art, name, beschreibung = null; + var time = moment().hour(0).minute(0); + try { + if (element.hasOwnProperty('A')) { + day = moment(element.A, "D.","de"); + day = Number(element.A); + } + if ((!element.F && !element.H && !element.J) || element.I == "Spielort/ Extras" || element.J == "Spielort/Extras"){ + + } else { + + + if (element.hasOwnProperty("D") && element.hasOwnProperty("E")) { + // Probe + time = moment(element.D); + art = element.E.trim(); + name = element.F ? element.F.trim() : ""; + beschreibung = typeof(element.I) != 'undefined' ? element.I.trim() + : typeof(element.J) != 'undefined' ? element.J.trim() + : ""; + } + else if (element.hasOwnProperty("G") && element.hasOwnProperty("H")) + { + // Vorstellung + time = moment(element.G); + art = "VS"; + name = element.H.trim(); + beschreibung = typeof(element.I) != 'undefined' ? element.I.trim() + : typeof(element.J) != 'undefined' ? element.J.trim() + : ""; + } + else if (element.hasOwnProperty("I")) + { + // Spielort/Extras + beschreibung = element.I.trim(); + name = name ? name : "Spielort/Extras"; + } + else if (element.hasOwnProperty("J")) + { + // Spielort/Extras Fallback + beschreibung = element.J.trim(); + name = name ? name : "Spielort/Extras"; + } + + var datumStr = day + '.' + month.clone().format("MM.YY") + time.format(" HH:mm"); + var termin = { + ort: "", + art: art, + beschreibung: beschreibung, + name: name, + datum: moment(datumStr, "D.MM.YY HH:mm") + } + vm.addShift(new Shift(termin)); + } + } catch (error) { + console.error("Fehler beim Parsen", element, error); + } + + }); + }, + + parsePickedFormat: function (format) { + this.makeToast(`Versuche ${format} zu lesen.`); + switch (format) { + case "Erfurt": + this.parseForErfurt(this.workbook.Sheets["Dienstplan"]); + break; + case "Stuttgart": + var sheetName = this.workbook.SheetNames[0]; + this.parseForStuttgart(this.workbook.Sheets[sheetName]); + break; + case "X": + var sheetName = this.workbook.SheetNames[0]; + this.parseForX(this.workbook.Sheets[sheetName], sheetName); + break; + default: + break; + } + + this.workbook = null; + }, + + addShift: function (shift) { + this.shifts.push(shift); + }, + + removeShift: function (shift) { + this.shifts.splice(this.shifts.indexOf(shift), 1); + this.makeToast(shift.VEventTitle + " gelöscht"); + }, + + cleanStorage: function () { + this.shifts = []; + this.makeToast("Alle Einträge gelöscht"); + }, + + createDownloadFile: function () { + var vCal = new VCalendar("Dienstplan Kalender"); + this.shifts.forEach(function (shift) { + vCal.add(shift.toVEvent()); + }); + var calString = vCal.toString(); + this.blob = new Blob([calString], { + type: 'text/plain' + }); + + if (this.icsFile !== null) { + window.URL.revokeObjectURL(this.icsFile); + } + + this.icsFile = window.URL.createObjectURL(this.blob); + this.makeToast(this.saveto + " erstellt."); + }, + + downloadFile: function () { + if (window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveOrOpenBlob(this.blob, this.saveto); + } + }, + + selectShift: function (shift) { + this.selectedShift = Shift.thaw(shift); + this.keepShift = shift; + M.updateTextFields(); + $('#shiftModal').modal('open'); + }, + + saveChanges: function (changedShift) { + this.shifts.splice(this.shifts.indexOf(this.keepShift), 1, changedShift); + + $('#shiftModal').modal('close'); + this.keepShift = ''; + this.selectedShift = ''; + }, + + discardChanges: function (changedShift) { + $('#shiftModal').modal('close'); + this.keepShift = ''; + this.selectedShift = ''; + }, + + editRule: function (rule) { + this.selectedRule = Rule.thaw(rule); + this.selectedRuleIndex = this.rules.indexOf(rule); + $('#ruleModal').modal('open'); + }, + + saveRule: function () { + this.rules[this.selectedRuleIndex] = this.selectedRule; + + $('#ruleModal').modal('close'); + this.selectedRule = new Rule(); + }, + + discardRule: function () { + $('#ruleModal').modal('close'); + + this.selectedRule = new Rule(); + } + + }, + directives: { + 'edit-focus': function (el, value) { + if (value) { + el.focus(); + } + } + } +})