var dbg = null; Vue.createApp({ data: function() { return { 'events': null , 'frm': { 'e': null, 'modal': null, 'tab': 'agenda' } , 'faults': null , 'fields': { 'coordinates': { 'patterns': [ '^$', '^-?\\d{1,3}(?:\\.\\d+)?,-?\\d{1,3}(?:\\.\\d+)?$' ], 'default': '-27.38621539644283,153.0351689206467' } , 'start': { 'patterns': [ '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:?\\d{0,2}$' ], 'default': '' } , 'end': { 'patterns': [ '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:?\\d{0,2}$' ], 'default': '' } , 'title': { 'patterns': [ '^.{10,50}$' ], 'default': 'Event Title' } , 'description': { 'patterns': [ '^.{16,}$' ], 'default': 'Event Description' } , 'location': { 'patterns': [ '^.{5,100}$' ], 'default': 'Event Location' } } } }, methods: { formatDate: function(dt) { var fmt = 'DD MMM YYYY'; var m = moment(dt); var t = m.hour() * 3600 + m.minute() * 60 + m.second(); if ( t > 0 ) { fmt = ' ddd DD MMM YYYY, h:mm A'; } var ret = moment(dt).format(fmt); return ret; }, tabEnabled: function(e, tab) { var ret = ( Object.keys(this.events[e]).indexOf(tab) >= 0 ); return ret; }, toggleMD: function(evt) { evt.preventDefault(); if ( this.events[this.frm.e][this.frm.tab] == undefined ) { this.events[this.frm.e][this.frm.tab] = ''; } else { delete this.events[this.frm.e][this.frm.tab]; } this.events = JSON.parse(JSON.stringify(this.events)); }, hoursDiff: function(d1, d2) { return moment(d2).diff(moment(d1), 'hours', true); }, createEvent: function() { var event = {}; for ( var k in this.fields ) { event[k] = this.fields[k].default; } const now = moment(); let next7pm = moment().hour(19).minute(0).second(0); if (now.isSameOrAfter(next7pm)) { next7pm.add(1, 'day'); } event.hours = 2.5; const twoHoursLater = moment(next7pm).add(event.hours, 'hours'); event.start = next7pm.format('YYYY-MM-DDTHH:mm'); event.end = twoHoursLater.format('YYYY-MM-DDTHH:mm'); this.events.unshift(event); this.frm.e = 0; }, saveEvents: function() { console.log(this.events); var app = this; jQuery.post( 'api.php' , { 'cmd': 'put' , 'payload': btoa(JSON.stringify(this.events)) } , function(data) { app.events = data; app.frm.e = null; app.validateEvents(); } ); }, deleteEvent: function() { this.events.splice(this.frm.e, 1); this.frm.e = null; this.validateEvents(); }, validateEvents: function() { var faults = []; for ( var e in this.events ) { var start = moment(this.events[e].start); var end = start.add(this.events[e].hours, 'hours'); this.events[e].end = end.format('YYYY-MM-DDTHH:mm'); for ( var k in this.fields ) { var value = this.events[e][k]; value = ( value == undefined ? '' : value ); var patterns = this.fields[k].patterns; var match = false; for ( var p in patterns ) { var pattern = new RegExp(patterns[p]); match = match || pattern.test(value); } if ( ! match ) { var fault = {}; fault.e = e; fault.k = k; fault.v = value; fault.msg = 'Bad format for ' + k + '.'; faults.push(fault); } } var d1 = moment(this.events[e].start); var d2 = moment(this.events[e].end); if ( d2.isSameOrBefore(d1) ) { var fault = {}; fault.e = e; fault.k = 'end'; fault.v = this.formatDate(d2); fault.msg = 'Event ends before start.'; faults.push(fault); } } this.faults = ( faults.length == 0 ? null : faults ); }, load: function() { var app = this; jQuery.get( 'api.php' , { 'cmd': 'get' } , function(data) { app.events = data; app.validateEvents(); $('body').fadeIn(); } ); }, modal: function(property) { var d = {}; d.property = property; d.value = this.events[this.frm.e][property]; this.frm.modal = d; }, modalUpdate: function() { this.events[this.frm.e][this.frm.modal.property] = this.frm.modal.value; this.frm.modal = null; this.validateEvents(); }, modalCancel: function() { this.frm.modal = null; } }, mounted: function() { dbg = this; this.load(); } }).mount('#app')