From 26b1abc309e0545c98c1468e7d7d2c3ca2749b38 Mon Sep 17 00:00:00 2001 From: jaden <noreply@example.com> Date: Mon, 12 Jun 2017 14:52:19 +0200 Subject: [PATCH] mv lastEdited timer to css animation, closes #45 --- .../reports/app/directives/lastEdited.js | 141 ------------------ .../static/reports/app/directives/save.js | 7 +- .../reports/app/services/reportService.js | 1 - beat/web/reports/static/reports/css/style.css | 18 +++ .../web/reports/templates/reports/report.html | 7 +- 5 files changed, 27 insertions(+), 147 deletions(-) delete mode 100644 beat/web/reports/static/reports/app/directives/lastEdited.js diff --git a/beat/web/reports/static/reports/app/directives/lastEdited.js b/beat/web/reports/static/reports/app/directives/lastEdited.js deleted file mode 100644 index c824d170f..000000000 --- a/beat/web/reports/static/reports/app/directives/lastEdited.js +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * lastEdited - * Desc: - * shows a live & humanized last-edited timestamp - */ -angular.module('reportApp') -.directive("lastEdited", ['ReportService', '$interval', '$timeout', function(ReportService, $interval, $timeout){ - return { - scope: { - initStr: '@' - }, - link: function(scope){ - scope.ReportService = ReportService; - - // humanize some amount of time - const nowFunc = () => 'Just now'; - const secondFunc = (s) => `${s} second${s === 1 ? '' : 's'} ago`; - const minuteFunc = (m) => `${m} minute${m === 1 ? '' : 's'} ago`; - const hourFunc = (h) => `${h} hour${h === 1 ? '' : 's'} ago`; - - // convert from/to ms to/from a different time seg - const intoSeconds = (t) => Math.floor(t / 1000); - const intoMinutes = (t) => Math.floor(intoSeconds(t) / 60); - const intoHours = (t) => Math.floor(intoMinutes(t) / 60); - const fromSeconds = (s) => s * 1000; - const fromMinutes = (m) => fromSeconds(m * 60); - const fromHours = (h) => fromMinutes(h * 60); - - // cutoffs & corresponding update freq - const before1m = fromSeconds(5); - const before10m = fromMinutes(1); - const before1h = fromMinutes(10); - const after1h = fromHours(1); - - // different update funcs for diff time intervals - const beginning = () => nowFunc(); - const every5s = (t) => secondFunc(intoSeconds(t)); - const every1m = (t) => minuteFunc(intoMinutes(t)); - const every10m = (t) => minuteFunc(intoMinutes(t)); - const every1h = (t) => hourFunc(intoHours(t)); - - // current string to be shown - scope.currStr = { - val: scope.initStr - }; - - const updateCurrStr = (t, strFunc) => { - const str = strFunc(Date.now() - t); - scope.currStr.val = str; - return str; - }; - - // curr interval ids - let currIntervalIds = []; - - // interval funcs - const secondsInterval = (t) => { - const id = $interval(updateCurrStr, before1m, 0, true, t, every5s); - const tid = $timeout(() => $interval.cancel(id), fromSeconds(59)); - - return [id, tid]; - }; - const singleMinutesInterval = (t) => { - const id = $interval(updateCurrStr, before10m, 0, true, t, every1m); - const tid = $timeout(() => $interval.cancel(id), fromMinutes(9.9)); - - return [id, tid]; - }; - const tenMinutesInterval = (t) => { - const id = $interval(updateCurrStr, before1h, 0, true, t, every10m); - const tid = $timeout(() => $interval.cancel(id), fromMinutes(59)); - - return [id, tid]; - }; - const hourInterval = (t) => { - const id = $interval(updateCurrStr, after1h, 0, true, t, every1h); - const tid = $timeout(() => $interval.cancel(id), fromMinutes(61)); - - return [id, tid]; - }; - - const setupIntervals = (t) => { - const intervalIds = [ - ...secondsInterval(t), - ...singleMinutesInterval(t), - ...tenMinutesInterval(t), - ...hourInterval(t) - ]; - - return intervalIds; - }; - - const cancelIntervals = () => currIntervalIds.forEach(id => $interval.cancel(id)); - - const reset = () => { - cancelIntervals(); - updateCurrStr(0, beginning); - currIntervalIds = setupIntervals(ReportService.lastEditedTime); - }; - - // watch lastEditedTime for a change and start/restart the timers - scope.$watch('ReportService.lastEditedTime', (newTime, oldTime) => { - if(newTime > oldTime && newTime !== 0 && Date.now() > newTime){ - reset(); - } - }); - - // need to clear timers/intervals when this el is destroyed - scope.$on('$destroy', cancelIntervals); - - if(ReportService.lastEditedTime > 0){ - reset(); - } - }, - template: ` -Last Edited: <strong>{{ currStr.val }}</strong> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/save.js b/beat/web/reports/static/reports/app/directives/save.js index 5fefdd874..77c48e8bb 100644 --- a/beat/web/reports/static/reports/app/directives/save.js +++ b/beat/web/reports/static/reports/app/directives/save.js @@ -32,6 +32,7 @@ angular.module('reportApp') }, restrict: 'A', link: function(scope, el){ + const saveReport = () => { // save the serialized group data... // the rest of the state is reconstructed from it and the URL @@ -44,8 +45,10 @@ angular.module('reportApp') return reportFactory.removeExperiments(ExperimentsService.cachedDeletedExperiments) .then(() => reportFactory.updateReport(ReportService.author, ReportService.name, saveData, '')) .then(() => { - ReportService.lastEditedTime = Date.now(); - scope.$apply(); + const lastEditedEl = document.querySelector('.lastEdited'); + lastEditedEl.classList.remove('lastEditedAnimating'); + void lastEditedEl.offsetWidth; + lastEditedEl.classList.add('lastEditedAnimating'); }) .catch(e => { ErrorService.logError(e, `Could not save the report.`); diff --git a/beat/web/reports/static/reports/app/services/reportService.js b/beat/web/reports/static/reports/app/services/reportService.js index 1dd40c919..67c8802d7 100644 --- a/beat/web/reports/static/reports/app/services/reportService.js +++ b/beat/web/reports/static/reports/app/services/reportService.js @@ -35,7 +35,6 @@ angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterF rs.number = undefined; rs.author = undefined; rs.name = undefined; - rs.lastEditedTime = 0; rs.plotters = []; rs.defaultPlotters = []; diff --git a/beat/web/reports/static/reports/css/style.css b/beat/web/reports/static/reports/css/style.css index 8bbdc3678..8ced0afd2 100644 --- a/beat/web/reports/static/reports/css/style.css +++ b/beat/web/reports/static/reports/css/style.css @@ -215,3 +215,21 @@ div.report_commands div.report_buttons_bloc .publish_report:hover margin-left: 20px; margin-bottom: 0; } + +.lastEdited { +} + +.lastEditedAnimating { + animation-duration: 3s; + animation-name: reportSaved; +} + +@keyframes reportSaved { + from { + background-color: #dff0d8; + } + + to { + background-color: white; + } +} diff --git a/beat/web/reports/templates/reports/report.html b/beat/web/reports/templates/reports/report.html index bdaebcf58..a5ec574f2 100644 --- a/beat/web/reports/templates/reports/report.html +++ b/beat/web/reports/templates/reports/report.html @@ -42,6 +42,7 @@ <link rel="stylesheet" href="{% fingerprint "chosen-bootstrap/chosen.bootstrap.min.css" %}" type="text/css" media="screen" /> <link rel="stylesheet" href="{% fingerprint "datatables/media/css/dataTables.bootstrap.min.css" %}" type="text/css" media="screen" /> <link rel="stylesheet" href="{% fingerprint "jquery-ui/themes/base/minified/jquery-ui.min.css" %}" type="text/css" media="screen" /> + <link rel="stylesheet" href="{% fingerprint "reports/css/style.css" %}" type="text/css" media="screen" /> {% code_editor_css %} {% endblock %} @@ -102,7 +103,6 @@ <script src="{% fingerprint "reports/app/directives/save.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/error.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/experimentsTable.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/lastEdited.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/editableLabel.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/panelExperiments.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/panelContainer.js" %}" type="text/javascript" charset="utf-8"></script> @@ -151,7 +151,7 @@ <div class="row"> <div class="col-sm-12"> - <p class="bs-callout bs-callout-{% if status == 'Editable' %}danger{% elif status == 'Locked' %}warning{% else %}info{% endif %}"> + <p class="bs-callout bs-callout-{% if status == 'Editable' %}danger{% elif status == 'Locked' %}warning{% else %}info{% endif %} lastEdited"> {% if report.short_description %} <i class="fa fa-file-text"></i> {{ report.short_description }}<br/> @@ -167,7 +167,8 @@ <i class="fa fa-calendar-o"></i> Created: <strong>{{ report.creation_date|naturaltime }}</strong><br/> {% endif %} {% if report.last_edited_date != None and not report.publication_date %} - <i class="fa fa-calendar-o"></i> <last-edited init-str='{{ report.last_edited_date|naturaltime }}'></last-edited><br/> + + <i class="fa fa-calendar-o"></i> Last Edited: <strong>{{ report.last_edited_date|naturaltime }}</strong><br/> {% endif %} {% if status == 'Editable' %} -- GitLab