Merge pull request #2412 from FinnStutzenstein/Issue2109

Agenda duration and estimated time (closes #2109)
This commit is contained in:
Emanuel Schütze 2016-09-22 22:40:23 +02:00 committed by GitHub
commit 2495d7dd7f
6 changed files with 152 additions and 3 deletions

View File

@ -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)
except ValueError:
return False
else:
return True
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',
),
]

View File

@ -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.
"""

View File

@ -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;

View File

@ -134,6 +134,12 @@
<translate>Agenda item</translate>
<th os-perms="agenda.can_see_hidden_items" class="optional">
<translate>Duration</translate>
<span ng-if="sumDurations() > 0">
{{ sumDurations() | osMinutesToTime }}h
<span ng-if="config('agenda_start_event_date_time')">
(<translate>Estimated end:</translate> {{ calculateEndTime() }})
</span>
</span>
<th class="minimum optional">
<translate>Done</translate>
<tbody>
@ -196,7 +202,7 @@
</span>
</div>
<td ng-show="!item.quickEdit" os-perms="agenda.can_see_hidden_items" class="optional">
{{ item.duration }}
{{ item.duration | osMinutesToTime }}
<span ng-if="item.duration" translate-comment="'h' means time in hours" translate>h</span>
<td ng-if="!item.quickEdit" class="optional">
<span os-perms="!agenda.can_manage">
@ -227,7 +233,8 @@
</div>
<div class="col-xs-6">
<label for="inputDuration" translate>Duration</label>
<input type="text" ng-model="item.duration" class="form-control input-sm" id="inputDuration">
<input type="text" ng-model="item.duration" placeholder="hh:mm" hour-min-format
class="form-control input-sm" id="inputDuration">
</div>
</div>
<div class="spacer">

View File

@ -429,6 +429,27 @@ angular.module('OpenSlidesApp.core', [
}
])
/* Converts number of minutes into string "h:mm" or "hh:mm" */
.filter('osMinutesToTime', [
function () {
return function (totalminutes) {
var time = '';
if (totalminutes) {
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) {

View File

@ -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) {