Skip to content
Snippets Groups Projects
Commit 26b1abc3 authored by jaden's avatar jaden
Browse files

mv lastEdited timer to css animation, closes #45

parent 4e2e8e8c
No related branches found
No related tags found
1 merge request!223Reports overhaul
/*
* 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>
`
};
}]);
......@@ -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.`);
......
......@@ -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 = [];
......
......@@ -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;
}
}
......@@ -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' %}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment