Merge pull request #2800 from FinnStutzenstein/Issue2748

Consistent time handling and generic time converter code
This commit is contained in:
Norman Jäckel 2016-12-21 11:52:47 +01:00 committed by GitHub
commit bfa0b4b3fe
5 changed files with 116 additions and 124 deletions

View File

@ -5,16 +5,20 @@
angular.module('OpenSlidesApp.agenda.csv', []) angular.module('OpenSlidesApp.agenda.csv', [])
.factory('AgendaCsvExport', [ .factory('AgendaCsvExport', [
function () { 'HumanTimeConverter',
function (HumanTimeConverter) {
return function (element, agenda) { return function (element, agenda) {
var csvRows = [ var csvRows = [
['title', 'text', 'duration', 'comment', 'is_hidden'], ['title', 'text', 'duration', 'comment', 'is_hidden'],
]; ];
_.forEach(agenda, function (item) { _.forEach(agenda, function (item) {
var row = []; var row = [];
var duration = item.duration ? HumanTimeConverter.secondsToHumanTime(item.duration*60,
{ seconds: 'disabled',
hours: 'enabled' }) : '';
row.push('"' + (item.title || '') + '"'); row.push('"' + (item.title || '') + '"');
row.push('"' + (item.text || '') + '"'); row.push('"' + (item.text || '') + '"');
row.push('"' + (item.duration || '') + '"'); row.push('"' + duration + '"');
row.push('"' + (item.comment || '') + '"'); row.push('"' + (item.comment || '') + '"');
row.push('"' + (item.is_hidden ? '1' : '') + '"'); row.push('"' + (item.is_hidden ? '1' : '') + '"');
csvRows.push(row); csvRows.push(row);

View File

@ -692,30 +692,6 @@ angular.module('OpenSlidesApp.agenda.site', [
} }
]) ])
.factory('AgendaCsvExport', [
function () {
return function (element, agenda) {
var csvRows = [
['title', 'text', 'duration', 'comment', 'is_hidden'],
];
_.forEach(agenda, function (item) {
var row = [];
row.push('"' + (item.title || '') + '"');
row.push('"' + (item.text || '') + '"');
row.push('"' + (item.duration || '') + '"');
row.push('"' + (item.comment || '') + '"');
row.push('"' + (item.is_hidden ? '1' : '') + '"');
csvRows.push(row);
});
var csvString = csvRows.join("%0A");
element.href = 'data:text/csv;charset=utf-8,' + csvString;
element.download = 'agenda-export.csv';
element.target = '_blank';
};
}
])
//mark all agenda config strings for translation with Javascript //mark all agenda config strings for translation with Javascript
.config([ .config([
'gettext', 'gettext',

View File

@ -852,48 +852,105 @@ angular.module('OpenSlidesApp.core', [
} }
]) ])
/* Two functions to convert between time duration in seconds <-> human readable time span.
* E.g. 90 sec <-> 1:30 (min), 3661 sec <-> 1:01:01 (h)
*
* secondsToHumanTime: Expects seconds and give [h*:]mm[:ss]. The minutes part is always given, the hours
* and minutes could be controlled. The default are forced seconds and hours just if it is not 0.
* - seconds ('enabled', 'auto', 'disabled'): Whether to show seconds (Default 'enabled')
* - hours ('enabled', 'auto', 'disabled'): Whether to show hours (Default 'auto')
*
* humanTimeToSeconds: Expects [h*:]m*[:s*] with each part could have a variable length. The parsed time is
* in seconds. Minutes have to be given and hours and seconds are optional. One have to set 'seconds' or
* 'hours' to true toparse these.
*
* params could be an object with the given settings, e.g. {ignoreHours: true}
*/
.factory('HumanTimeConverter', [
function () {
return {
secondsToHumanTime: function (seconds, params) {
if (!params) {
params = {seconds: 'enabled', hours: 'auto'};
}
if (!params.seconds) {
params.seconds = 'enabled';
}
if (!params.hours) {
params.hours = 'auto';
}
var time;
// floor returns the largest integer of the absolut value of seconds
var total = Math.floor(Math.abs(seconds));
var h = Math.floor(total / 3600);
var m = Math.floor(total % 3600 / 60);
var s = Math.floor(total % 60);
// Add leading "0" for double digit values
time = ('0'+m).slice(-2); //minutes
if ((params.seconds == 'auto' && s > 0) || params.seconds == 'enabled') {
s = ('0'+s).slice(-2);
time = time + ':' + s;
}
if ((params.hours == 'auto' && h > 0) || params.hours == 'enabled') {
time = h + ':' + time;
}
if (seconds < 0) {
time = '-'+time;
}
return time;
},
humanTimeToSeconds: function (data, params) {
if (!params) {
params = {seconds: false, hours: false};
}
var minLength = 1;
if (params.seconds) {
minLength++;
}
if (params.hours){
minLength++;
}
var negative = data.charAt(0) == '-';
var time = data.split(':');
data = 0;
if (time.length >= minLength) {
for (var i = 0; i < minLength; i++) {
data = data*60 + (+time[i]);
}
if (!params.seconds) { // the last field was minutes (e.g. h:mm)
data *= 60;
}
if (negative) {
data = -data;
}
}
return data;
},
};
}
])
/* Converts number of seconds into string "h:mm:ss" or "mm:ss" */ /* Converts number of seconds into string "h:mm:ss" or "mm:ss" */
.filter('osSecondsToTime', [ .filter('osSecondsToTime', [
function () { 'HumanTimeConverter',
return function (totalseconds) { function (HumanTimeConverter) {
var time; return function (seconds) {
// floor returns the largest integer of the absolut value of totalseconds return HumanTimeConverter.secondsToHumanTime(seconds);
var total = Math.floor(Math.abs(totalseconds));
var h = Math.floor(total / 3600);
var mm = Math.floor(total % 3600 / 60);
var ss = Math.floor(total % 60);
var zero = "0";
// Add leading "0" for double digit values
mm = (zero+mm).slice(-2);
ss = (zero+ss).slice(-2);
if (h == "0")
time = mm + ':' + ss;
else
time = h + ":" + mm + ":" + ss;
if (totalseconds < 0)
time = "-"+time;
return time;
}; };
} }
]) ])
/* Converts number of minutes into string "h:mm" or "hh:mm" */ /* Converts number of minutes into string "h:mm" or "hh:mm" */
.filter('osMinutesToTime', [ .filter('osMinutesToTime', [
function () { 'HumanTimeConverter',
return function (totalminutes) { function (HumanTimeConverter) {
var time = ''; return function (minutes) {
if (totalminutes) { return HumanTimeConverter.secondsToHumanTime(minutes*60,
if (totalminutes < 0) { { seconds: 'disabled',
time = "-"; hours: 'enabled' }
totalminutes = -totalminutes; );
}
var hh = Math.floor(totalminutes / 60);
var mm = Math.floor(totalminutes % 60);
// Add leading "0" for double digit values
mm = ("0" + mm).slice(-2);
time += hh + ":" + mm;
}
return time;
}; };
} }
]) ])

View File

@ -1338,40 +1338,19 @@ angular.module('OpenSlidesApp.core.site', [
// format time string for model ("s") and view format ("h:mm:ss" or "mm:ss") // format time string for model ("s") and view format ("h:mm:ss" or "mm:ss")
.directive('minSecFormat', [ .directive('minSecFormat', [
function () { 'HumanTimeConverter',
function (HumanTimeConverter) {
return { return {
require: 'ngModel', require: 'ngModel',
link: function(scope, element, attrs, ngModelController) { link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function(data) { ngModelController.$parsers.push(function(data) {
//convert data from view format (mm:ss) to model format (s) //convert data from view format (mm:ss) to model format (s)
var time = data.split(':'); return HumanTimeConverter.humanTimeToSeconds(data, {seconds: true});
if (time.length > 1) {
data = (+time[0]) * 60 + (+time[1]);
if (data < 0) {
data = "-"+data;
}
}
return data;
}); });
ngModelController.$formatters.push(function(data) { ngModelController.$formatters.push(function(data) {
//convert data from model format (s) to view format (mm:ss) //convert data from model format (s) to view format (mm:ss)
var time; return HumanTimeConverter.secondsToHumanTime(data);
// floor returns the largest integer of the absolut value of totalseconds
var total = Math.floor(Math.abs(data));
var mm = Math.floor(total / 60);
var ss = Math.floor(total % 60);
var zero = "0";
// Add leading "0" for double digit values
if (mm.length < 2) {
mm = (zero+mm).slice(-2);
}
ss = (zero+ss).slice(-2);
time = mm + ':' + ss;
if (data < 0) {
time = "-"+time;
}
return time;
}); });
} }
}; };
@ -1380,38 +1359,22 @@ angular.module('OpenSlidesApp.core.site', [
// format time string for model ("m") and view format ("h:mm" or "hh:mm") // format time string for model ("m") and view format ("h:mm" or "hh:mm")
.directive('hourMinFormat', [ .directive('hourMinFormat', [
function () { 'HumanTimeConverter',
function (HumanTimeConverter) {
return { return {
require: 'ngModel', require: 'ngModel',
link: function(scope, element, attrs, ngModelController) { link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function(data) { ngModelController.$parsers.push(function(data) {
//convert data from view format (hh:mm) to model format (m) //convert data from view format (hh:mm) to model format (m)
var time = data.split(':'); return HumanTimeConverter.humanTimeToSeconds(data, {hours: true})/60;
if (time.length > 1 && !isNaN(time[0]) && !isNaN(time[1])) {
data = (+time[0]) * 60 + (+time[1]);
if (data < 0) {
data = "-"+data;
}
}
if (data === '') {
data = 0;
}
return data;
}); });
ngModelController.$formatters.push(function(totalminutes) { ngModelController.$formatters.push(function(data) {
//convert data from model format (m) to view format (hh:mm) //convert data from model format (m) to view format (hh:mm)
var time = ""; return HumanTimeConverter.secondsToHumanTime(data*60,
if (totalminutes < 0) { { seconds: 'disabled',
time = "-"; hours: 'enabled' }
totalminutes = -totalminutes; );
}
var hh = Math.floor(totalminutes / 60);
var mm = Math.floor(totalminutes % 60);
// Add leading "0" for double digit values
mm = ("0"+mm).slice(-2);
time += hh + ":" + mm;
return time;
}); });
} }
}; };

View File

@ -271,7 +271,8 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics'])
'gettext', 'gettext',
'Agenda', 'Agenda',
'Topic', 'Topic',
function($scope, gettext, Agenda, Topic) { 'HumanTimeConverter',
function($scope, gettext, Agenda, Topic, HumanTimeConverter) {
// Big TODO: Change wording from "item" to "topic". // Big TODO: Change wording from "item" to "topic".
// import from textarea // import from textarea
$scope.importByLine = function () { $scope.importByLine = function () {
@ -342,22 +343,13 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics'])
} }
// duration // duration
if (item.duration) { if (item.duration) {
var time = item.duration.replace(quotionRe, '$1').split(':'), var time = item.duration.replace(quotionRe, '$1');
len = time.length, time = HumanTimeConverter.humanTimeToSeconds(time, {hours: true})/60;
data = '';
if (len > 1 && !isNaN(time[len-2]) && !isNaN(time[len-1])) { // minutes and hours
// e.g.: [sl:1000:]10:34 (the [] will not be parsed)
data = (+time[len-2]) * 60 + (+time[len-1]);
} else if (len == 1) { // just interpret minutes
data = (+time[0]);
} else {
data = null;
}
if (data < 0 || data === '') { if (time <= 0) { // null instead of 0 or negative duration
data = null; // no negative duration time = null;
} }
item.duration = data; item.duration = time;
} else { } else {
item.duration = null; item.duration = null;
} }