From 2834af46bcc4e023ec34ca55da9355ea79f9b23a Mon Sep 17 00:00:00 2001 From: ralf Date: Mon, 17 Oct 2022 11:38:54 +0200 Subject: [PATCH] WIP timesheet timers: fix overwriting time via clicking on time displayed under the button --- api/js/jsapi/egw_timer.js | 61 ++++++++++++++++++++++++--------------- timesheet/src/Events.php | 12 ++------ 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/api/js/jsapi/egw_timer.js b/api/js/jsapi/egw_timer.js index a2bf15a910..6bc07d8441 100644 --- a/api/js/jsapi/egw_timer.js +++ b/api/js/jsapi/egw_timer.js @@ -64,6 +64,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() stopTimer(overall); } overall.last = _state.overall.last ? new Date(_state.overall.last) : undefined; + overall.id = _state.overall?.id; // initiate specific timer, only if running or paused if (_state.specific?.start || _state.specific?.paused) @@ -82,6 +83,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() } } specific.last = _state.specific.last ? new Date(_state.specific.last) : undefined; + specific.id = _state.specific?.id; } /** @@ -111,6 +113,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() */ function timerAction(_action, _time, _app_id) { + const [type, action] = _action.split('-'); switch(_action) { case 'overall-start': @@ -141,27 +144,22 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() break; } // set _app_id on timer, if specified - if (_app_id && _action.substring(0, 8) === 'specific') + if (_app_id && type === 'specific') { specific.app_id = _app_id; } // persist state - return egw.request('timesheet.EGroupware\\Timesheet\\Events.ajax_event', [getState(_action, _time)]).then((tse_id) => { - if (_action.substring(0, 8) === 'specific') + return egw.request('timesheet.EGroupware\\Timesheet\\Events.ajax_event', [getState(_action, _time)]).then((tse_id) => + { + const timer = type === 'specific' ? specific : overall; + // do NOT set/change timer.id, if a paused timer get stopped (to show and update paused time, not irrelevant stop) + if (timer.start || typeof timer.paused !== 'undefined') { - specific.id = tse_id; - if (_action.substring(9) === 'start') - { - specific.started_id = tse_id; - } + timer.id = tse_id; } - else + if (action === 'start') { - overall.id = tse_id; - if (_action.substring(9) === 'start') - { - overall.started_id = tse_id; - } + timer.started_id = tse_id; } if (_action === 'specific-stop') { @@ -176,7 +174,6 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() // unset the app_id and the tse_id to not associate the next start with it specific.app_id = undefined; - specific.id = undefined; } }); } @@ -282,6 +279,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() function startTimer(_timer, _start, _offset) { _timer.started = _start ? new Date(_start) : new Date(); + _timer.started.setSeconds(0); // only use full minutes, as this is what we display if (_timer.last && _timer.started.valueOf() < _timer.last.valueOf()) { throw egw.lang('Start-time can not be before last stop- or pause-time %1!', formatUTCTime(_timer.last)); @@ -320,6 +318,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() function stopTimer(_timer, _pause, _time) { const time = _time ? new Date(_time) : new Date(); + time.setSeconds(0); // only use full minutes, as this is what we display if (time.valueOf() < _timer.last.valueOf()) { const last_time = formatUTCTime(_timer.last); @@ -341,8 +340,16 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() _timer.offset = time.valueOf() - _timer.start.valueOf(); _timer.start = undefined; } - _timer.paused = _pause || false; - _timer.last = time; + // if we stop an already paused timer, we keep the paused event as last, not the stop + if (_timer.paused) + { + _timer.paused = _pause || undefined; + } + else + { + _timer.last = time; + _timer.paused = _pause || false; + } // update timer display updateTimer(timer, _timer); @@ -433,7 +440,6 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() timerAction(button_id.replace(/_([a-z]+)\[([a-z]+)\]/, '$1-$2'), // eT2 operates in user-time, while timers here always operate in UTC value.time ? new Date((new Date(value.time)).valueOf() + egw.getTimezoneOffset() * 60000) : undefined); - dialog._overlayContentNode.querySelector('et2-date-time').value = ''; } catch (e) { Et2Dialog.alert(e, egw.lang('Invalid Input'), Et2Dialog.ERROR_MESSAGE); @@ -522,18 +528,27 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() const [, which, action] = _widget.id.match(/times\[([^\]]+)\]\[([^\]]+)\]/); const timer = which === 'overall' ? overall : specific; const tse_id = timer[action === 'start' ? 'started_id' : 'id']; - const time = _widget.value; const dialog = new Et2Dialog(egw); // Set attributes. They can be set in any way, but this is convenient. dialog.transformAttributes({ callback: (_button, _values) => { - if (_button === Et2Dialog.OK_BUTTON) + const change = (new Date(_widget.value)).valueOf() - (new Date(_values.time)).valueOf(); + if (_button === Et2Dialog.OK_BUTTON && change) { _widget.value = _values.time; - // for start we need to take the (not stored) offset into account - const offset = action === 'start' ? timer.started.valueOf() - timer.start.valueOf() : 0; - timer[action] = new Date((new Date(_values.time)).valueOf() + egw.getTimezoneOffset() * 60000 - offset); + timer[action === 'start' ? 'started' : action] = new Date((new Date(_values.time)).valueOf() + egw.getTimezoneOffset() * 60000); + // for a stopped or paused timer, we need to adjust the offset (duration) and the displayed timer too + if (timer.offset) + { + timer.offset -= action === 'start' ? -change : change; + update(); + } + // for a running timer, we need to adjust the (virtual) start too + else if (timer.start) + { + timer.start = new Date(timer.start.valueOf() - change); + } egw.request('timesheet.EGroupware\\Timesheet\\Events.ajax_updateTime', [tse_id, new Date((new Date(_values.time)).valueOf() + egw.getTimezoneOffset() * 60000)]) } diff --git a/timesheet/src/Events.php b/timesheet/src/Events.php index 28c7d005d6..1588ad6e17 100644 --- a/timesheet/src/Events.php +++ b/timesheet/src/Events.php @@ -176,7 +176,7 @@ class Events extends Api\Storage\Base ], __LINE__, __FILE__, self::APP); // if a stop event is overwritten, we need to adjust the timesheet duration and quantity - if (!empty($event['ts_id']) && ($diff = round(($time->getTimestamp() - $event['tse_time'].getTimestamp()) / 60))) + if (!empty($event['ts_id']) && ($diff = round(($time->getTimestamp() - $event['tse_time']->getTimestamp()) / 60))) { $bo = new \timesheet_bo(); if ($bo->read($event['ts_id'])) @@ -278,15 +278,6 @@ class Events extends Api\Storage\Base { $state['specific']['app_id'] = $row['tse_app'].'::'.$row['tse_app_id']; } - // for not stopped events, set the tse_id, so we can associate with an "app:id" - if ($row['tse_type'] & self::STOP) - { - $state['specific']['id'] = null; - } - else - { - $state['specific']['id'] = $row['tse_id']; - } } } // format start-times in UTZ as JavaScript Date() understands @@ -351,6 +342,7 @@ class Events extends Api\Storage\Base $timer['paused'] = ($row['tse_type'] & self::PAUSE) === self::PAUSE; } $timer['last'] = $row['tse_time']; + $timer['id'] = $row['tse_id']; return $time ?? null; }