From ed940f3a6a9645068ad93c40c9471282dc07eba8 Mon Sep 17 00:00:00 2001 From: Gabriel Herbert Date: Tue, 16 May 2023 15:23:18 +0200 Subject: [PATCH] Fixed: Timezone offset issue in list views Same issue addressed in last fix for negative timezone offsets, was overlooked before. --- www/comps/inputDate.js | 129 ++++++++++++++++++----------------------- www/comps/valueRich.js | 7 ++- 2 files changed, 61 insertions(+), 75 deletions(-) diff --git a/www/comps/inputDate.js b/www/comps/inputDate.js index 85937743..0be60ffb 100644 --- a/www/comps/inputDate.js +++ b/www/comps/inputDate.js @@ -33,12 +33,10 @@ let MyInputDateEntryInput = { }, emits:['update:modelValue'], computed:{ - styles:function() { - return `width:${this.size}ch;`; - }, + styles:(s) => `width:${s.size}ch;`, value:{ - get:function() { return this.modelValue; }, - set:function() {} + get() { return this.modelValue; }, + set(v) {} } } }; @@ -115,7 +113,7 @@ let MyInputDateEntry = { emits:['update:modelValue'], watch:{ modelValue:{ - handler: function(v) { + handler(v) { // fill input fields if value changed if(v === null) { this.year = ''; @@ -142,66 +140,44 @@ let MyInputDateEntry = { immediate:true } }, - data:function() { + data() { return { year:'', month:'', day:'', hour:'', minute:'', second:'' }; }, computed:{ - isDateOnly:function() { - return this.isDate && !this.isTime; - }, - isDateTime:function() { - return this.isDate && this.isTime; - }, - isTimeOnly:function() { - return !this.isDate && this.isTime; - }, - inputSeparatorSymbol:function() { - if(this.settings.dateFormat.indexOf('/') !== -1) - return '/'; - - if(this.settings.dateFormat.indexOf('.') !== -1) - return '.'; - - return '-'; - }, - /* alternative inputs for mobile devices */ /* uses datetime-local for native datetime inputs on mobile devices */ /* works reliably with format 2019-12-31T12:12:00 */ valueDatetimeInput:{ - get:function() { + get() { return this.modelValue !== null - ? `${this.year}-${this.month}-${this.day}T${this.hour}:${this.minute}:${this.second}` - : ''; + ? `${this.year}-${this.month}-${this.day}T${this.hour}:${this.minute}:${this.second}` : ''; }, - set:function(v) { + set(v) { let d = new Date(v); if(!isNaN(d.getTime())) this.$emit('update:modelValue',d.getTime() / 1000); } }, valueDateInput:{ - get:function() { + get() { return this.modelValue !== null - ? `${this.year}-${this.month}-${this.day}` - : ''; + ? `${this.year}-${this.month}-${this.day}` : ''; }, - set:function(v) { + set(v) { let d = new Date(v); if(!isNaN(d.getTime())) this.$emit('update:modelValue',d.getTime() / 1000); } }, valueTimeInput:{ - get:function() { + get() { return this.modelValue !== null - ? `${this.hour}:${this.minute}:${this.second}` - : ''; + ? `${this.hour}:${this.minute}:${this.second}` : ''; }, - set:function(v) { + set(v) { let m = v.match(/^(\d+)\:(\d+)\:(\d+)$/); if(m !== null && m.length === 4) return this.$emit('update:modelValue', @@ -217,10 +193,22 @@ let MyInputDateEntry = { } }, + // display + inputSeparatorSymbol:(s) => { + if(s.settings.dateFormat.indexOf('/') !== -1) return '/'; + if(s.settings.dateFormat.indexOf('.') !== -1) return '.'; + return '-'; + }, + + // simple + isDateOnly:(s) => s.isDate && !s.isTime, + isDateTime:(s) => s.isDate && s.isTime, + isTimeOnly:(s) => !s.isDate && s.isTime, + // stores - capApp: function() { return this.$store.getters.captions.input.date; }, - isMobile:function() { return this.$store.getters.isMobile; }, - settings:function() { return this.$store.getters.settings; } + capApp: (s) => s.$store.getters.captions.input.date, + isMobile:(s) => s.$store.getters.isMobile, + settings:(s) => s.$store.getters.settings }, methods:{ // externals @@ -228,7 +216,7 @@ let MyInputDateEntry = { getDateShifted, getStringFilled, - parseInput:function(name,input) { + parseInput(name,input) { let d; let p = parseInt(input); if(isNaN(p)) return; @@ -273,20 +261,20 @@ let MyInputDateEntry = { } this.$emit('update:modelValue',Math.floor(d.getTime() / 1000)); }, - getInputCaption:function(position) { + getInputCaption(position) { switch(this.getInputType(position)) { case 'Y': return this.capApp.inputYear; break; case 'm': return this.capApp.inputMonth; break; case 'd': return this.capApp.inputDay; break; } }, - getInputSize:function(position) { + getInputSize(position) { return this.getInputType(position) === 'Y' ? 4 : 2; }, - getInputType:function(position) { + getInputType(position) { return this.settings.dateFormat.substr(position,1); }, - getInputValue:function(position) { + getInputValue(position) { switch(this.getInputType(position)) { case 'Y': return this.year; break; case 'm': return this.month; break; @@ -385,7 +373,7 @@ let MyInputDate = { unixTo: { required:false, default:null } }, emits:['blurred','focused','set-unix-from','set-unix-to'], - data:function() { + data() { return { calendarFresh:false, // new calendar opened, new date range selection date:new Date(), // date to control calendar navigation @@ -399,34 +387,27 @@ let MyInputDate = { // full day events start and end at 00:00:00 UTC // if used in datetime context, they can only be used in date range, // otherwise regular datetime value can appear as full day event - fullDay:function() { - - // pure dates are always full day - if(this.isDate && !this.isTime) - return true; - - // pure times are never full day - if(!this.isDate && this.isTime) - return false; + fullDay:(s) => { + if(s.isDate && !s.isTime) return true; // pure dates are always full day + if(!s.isDate && s.isTime) return false; // pure times are never full day // if not pure date, a range is required to allow for full day events // otherwise we cannot separate regular from full day events - if(!this.isRange) - return false; + if(!s.isRange) return false; // full day if start and end date are not set or UTC 00:00:00 - return (this.unixFrom === null || this.isUnixUtcZero(this.unixFrom)) - && (this.unixTo === null || this.isUnixUtcZero(this.unixTo)); + return (s.unixFrom === null || s.isUnixUtcZero(s.unixFrom)) + && (s.unixTo === null || s.isUnixUtcZero(s.unixTo)); }, // date|time inputs unixFromInput:{ - get:function() { return this.unixFrom; }, - set:function(v) { this.$emit('set-unix-from',v); } + get() { return this.unixFrom; }, + set(v) { this.$emit('set-unix-from',v); } }, unixToInput:{ - get:function() { return this.unixTo; }, - set:function(v) { + get() { return this.unixTo; }, + set(v) { // if to unix is smaller, set to from if(v !== null && v < this.unixFromInput) v = this.unixFromInput; @@ -436,11 +417,11 @@ let MyInputDate = { }, // start/end date of calendar (month input) - date0:function() { return this.getCalendarCutOff0('month',new Date(this.date.valueOf())) }, - date1:function() { return this.getCalendarCutOff1('month',new Date(this.date.valueOf()),this.date0) }, + date0:(s) => s.getCalendarCutOff0('month',new Date(s.date.valueOf())), + date1:(s) => s.getCalendarCutOff1('month',new Date(s.date.valueOf()),s.date0), // stores - capApp:function() { return this.$store.getters.captions.input.date; } + capApp:(s) => s.$store.getters.captions.input.date }, methods:{ // externals @@ -455,21 +436,21 @@ let MyInputDate = { isUnixUtcZero, // events - escaped:function() { + escaped() { this.showCalendar = false; }, - focused:function() { + focused() { if(!this.isReadonly && !this.showCalendar) this.showCalendar = true; }, - updateDropdownDirection:function() { + updateDropdownDirection() { let headersPx = 200; // rough height in px of all headers (menu/form) combined let calPx = 320; // rough height in px of calendar input this.showUpwards = this.isDropdownUpwards(this.$el,calPx,headersPx); }, // actions - toggleCalendar:function() { + toggleCalendar() { if(!this.showCalendar) { // reset date range selection @@ -501,7 +482,7 @@ let MyInputDate = { } this.showCalendar = !this.showCalendar; }, - toggleFullDayRange:function() { + toggleFullDayRange() { // if range is empty, set both dates to a datetime today if(this.unixFrom === null && this.unixTo === null) { let unix = this.getUnixFromDate(this.getDateNoUtcZero(new Date())); @@ -521,7 +502,7 @@ let MyInputDate = { this.$emit('set-unix-to',this.getUnixFromDate(this.getDateFullDayToggled( new Date(this.unixTo*1000),this.fullDay))); }, - dateSet:function(dSet,shift) { + dateSet(dSet,shift) { let apply = (d,unixOld) => { if(!this.fullDay) { // dates are always UTC zero @@ -556,7 +537,7 @@ let MyInputDate = { this.unixToInput = apply(dSet,this.unixTo); this.showCalendar = false; }, - setNull:function() { + setNull() { this.unixFromInput = null; this.unixToInput = null; this.showCalendar = false; diff --git a/www/comps/valueRich.js b/www/comps/valueRich.js index bf72727d..e1c8861b 100644 --- a/www/comps/valueRich.js +++ b/www/comps/valueRich.js @@ -4,6 +4,7 @@ import { } from './shared/attribute.js'; import { getUnixFormat, + getUnixShifted, getUtcTimeStringFromUnix } from './shared/time.js'; import { @@ -127,6 +128,7 @@ let MyValueRich = { getHtmlStripped, getLinkMeta, getUnixFormat, + getUnixShifted, getUtcTimeStringFromUnix, openLink, @@ -180,7 +182,10 @@ let MyValueRich = { case 'integer': // fallthrough case 'bigint': switch(atr.contentUse) { - case 'date': this.stringValueFull = this.getUnixFormat(this.value,this.settings.dateFormat); break; + case 'date': // shift to local offset to show correct date + this.stringValueFull = this.value === null ? '' + : this.getUnixFormat(this.getUnixShifted(this.value,true),this.settings.dateFormat); + break; case 'datetime': this.stringValueFull = this.getUnixFormat(this.value,this.settings.dateFormat + ' H:i'); break; case 'time': this.stringValueFull = this.getUtcTimeStringFromUnix(this.value); break; default: directValue = true; break;