From 970f42cacba8f52b332dc9770c9b77f0c7c1395a Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Thu, 22 Sep 2016 13:19:11 +0200 Subject: [PATCH] Agenda duration and estimated time (closes #2109) --- openslides/agenda/migrations/0002_duration.py | 56 +++++++++++++++++++ openslides/agenda/models.py | 2 +- openslides/agenda/static/js/agenda/site.js | 25 +++++++++ .../static/templates/agenda/item-list.html | 11 +++- openslides/core/static/js/core/base.js | 23 ++++++++ openslides/core/static/js/core/site.js | 40 +++++++++++++ 6 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 openslides/agenda/migrations/0002_duration.py diff --git a/openslides/agenda/migrations/0002_duration.py b/openslides/agenda/migrations/0002_duration.py new file mode 100644 index 000000000..3c183544f --- /dev/null +++ b/openslides/agenda/migrations/0002_duration.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-22 11:08 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def convert_duration(apps, schema_editor): + Item = apps.get_model('agenda', 'item') + for item in Item.objects.all(): + duration = item.duration + + item.duration_tmp = None + if is_int(duration): + # assuming that these are minutes + item.duration_tmp = int(duration) + else: + split = duration.split(':') + # assuming format (h)h:(m)m + if len(split) == 2 and is_int(split[0]) and is_int(split[1]): + # duration = hours * 60 + minutes + item.duration_tmp = int(split[0]) * 60 + int(split[1]) + item.save() + + +def is_int(s): + try: + int(s) + return True + except ValueError: + return False + + +class Migration(migrations.Migration): + + dependencies = [ + ('agenda', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='item', + name='duration_tmp', + field=models.IntegerField(blank=True, null=True), + ), + migrations.RunPython(convert_duration), + migrations.RemoveField( + model_name='item', + name='duration', + ), + migrations.RenameField( + model_name='item', + old_name='duration_tmp', + new_name='duration', + ), + ] diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index 8e1564187..a97d9701a 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -220,7 +220,7 @@ class Item(RESTModelMixin, models.Model): See Item.ITEM_TYPE for more information. """ - duration = models.CharField(null=True, blank=True, max_length=5) + duration = models.IntegerField(null=True, blank=True) """ The intended duration for the topic. """ diff --git a/openslides/agenda/static/js/agenda/site.js b/openslides/agenda/static/js/agenda/site.js index 31be6db39..5c9e06eb5 100644 --- a/openslides/agenda/static/js/agenda/site.js +++ b/openslides/agenda/static/js/agenda/site.js @@ -112,6 +112,31 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda']) }); $scope.alert = {}; + $scope.sumDurations = function () { + var totalDuration = 0; + $scope.items.forEach(function (item) { + if (item.duration) { + totalDuration += item.duration; + } + }); + return totalDuration; + }; + + $scope.calculateEndTime = function () { + var totalDuration = $scope.sumDurations(); + var startTime = $scope.config('agenda_start_event_date_time'); + // This date-time has a fixed structure: DD.MM.YYYY HH:MM + if (startTime) { + var timestamp = Date.parse(startTime) + totalDuration * 60 * 1000; + var endDate = new Date(timestamp); + var mm = ("0"+endDate.getMinutes()).slice(-2); + var dateStr = endDate.getHours() + ':' + mm; + return dateStr; + } else { + return ''; + } + }; + // pagination $scope.currentPage = 1; $scope.itemsPerPage = 100; diff --git a/openslides/agenda/static/templates/agenda/item-list.html b/openslides/agenda/static/templates/agenda/item-list.html index fb6a0469c..e29581c04 100644 --- a/openslides/agenda/static/templates/agenda/item-list.html +++ b/openslides/agenda/static/templates/agenda/item-list.html @@ -134,6 +134,12 @@ Agenda item Duration + + {{ sumDurations() | osMinutesToTime }}h + + (Estimated end: {{ calculateEndTime() }}) + + Done @@ -196,7 +202,7 @@ - {{ item.duration }} + {{ item.duration | osMinutesToTime }} h @@ -227,7 +233,8 @@
- +
diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index df98b96fb..147a03819 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -429,6 +429,29 @@ angular.module('OpenSlidesApp.core', [ } ]) +/* Converts number of minutes into string "h:mm" or "hh:mm" */ +.filter('osMinutesToTime', [ + function () { + return function (totalminutes) { + if (!totalminutes) { + return ''; + } else { + var time = ""; + if (totalminutes < 0) { + time = "-"; + 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; + } + }; + } +]) + .filter('osFilter', [ function () { return function (array, string, getFilterString) { diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index 173c457e9..d768045b9 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -1502,6 +1502,46 @@ angular.module('OpenSlidesApp.core.site', [ } ]) +// format time string for model ("m") and view format ("h:mm" or "hh:mm") +.directive('hourMinFormat', [ + function () { + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModelController) { + ngModelController.$parsers.push(function(data) { + //convert data from view format (hh:mm) to model format (m) + var time = data.split(':'); + 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) { + //convert data from model format (m) to view format (hh:mm) + var time = ""; + if (totalminutes < 0) { + time = "-"; + 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; + }); + } + }; + } +]) + .directive('osFocusMe', [ '$timeout', function ($timeout) {