Handle start date/time; fix task list sorting

This commit is contained in:
Thomas Bruederli 2012-07-29 13:36:16 +02:00
parent e6fff6a96a
commit 78077bcb0a
9 changed files with 134 additions and 32 deletions

View file

@ -32,6 +32,8 @@ CREATE TABLE `tasks` (
`tags` text,
`date` varchar(10) DEFAULT NULL,
`time` varchar(5) DEFAULT NULL,
`startdate` varchar(10) DEFAULT NULL,
`starttime` varchar(5) DEFAULT NULL,
`flagged` tinyint(4) NOT NULL DEFAULT '0',
`complete` float NOT NULL DEFAULT '0',
`alarms` varchar(255) NOT NULL,

View file

@ -343,7 +343,7 @@ class tasklist_database_driver extends tasklist_driver
{
$rec['id'] = $rec['task_id'];
$rec['list'] = $rec['tasklist_id'];
$rec['changed'] = strtotime($rec['changed']);
$rec['changed'] = new DateTime($rec['changed']);
$rec['tags'] = array_filter(explode(',', $rec['tags']));
if (!$rec['parent_id'])
@ -409,7 +409,7 @@ class tasklist_database_driver extends tasklist_driver
if (isset($prop[$col]))
$sql_set[] = $this->rc->db->quote_identifier($col) . '=' . $this->rc->db->quote($prop[$col]);
}
foreach (array('parent_id', 'date', 'time') as $col) {
foreach (array('parent_id', 'date', 'time', 'startdate', 'starttime') as $col) {
if (isset($prop[$col]))
$sql_set[] = $this->rc->db->quote_identifier($col) . '=' . (empty($prop[$col]) ? 'NULL' : $this->rc->db->quote($prop[$col]));
}

View file

@ -337,8 +337,13 @@ class tasklist_kolab_driver extends tasklist_driver
$task['date'] = $record['due']->format('Y-m-d');
$task['time'] = $record['due']->format('h:i');
}
// convert from DateTime to internal date format
if (is_a($record['start'], 'DateTime')) {
$task['startdate'] = $record['start']->format('Y-m-d');
$task['starttime'] = $record['start']->format('h:i');
}
if (is_a($record['dtstamp'], 'DateTime')) {
$task['changed'] = $record['dtstamp']->format('U');
$task['changed'] = $record['dtstamp'];
}
return $task;
@ -360,6 +365,13 @@ class tasklist_kolab_driver extends tasklist_driver
unset($object['date']);
}
if (!empty($task['startdate'])) {
$object['start'] = new DateTime($task['startdate'].' '.$task['starttime'], $this->plugin->timezone);
if (empty($task['starttime']))
$object['start']->_dateonly = true;
unset($object['startdate']);
}
$object['complete'] = $task['complete'] * 100;
if ($task['complete'] == 1.0)
$object['status'] = 'COMPLETED';

View file

@ -30,12 +30,14 @@
* 'parent_id' => 'ID of parent task', // null if top-level task
* 'uid' => 'Unique identifier of this task',
* 'list' => 'Task list identifier to add the task to or where the task is stored',
* 'changed' => <unixtime>, // Last modification date of record
* 'changed' => <DateTime>, // Last modification date/time of the record
* 'title' => 'Event title/summary',
* 'description' => 'Event description',
* 'tags' => array(), // List of tags for this task
* 'date' => 'Due date', // as string of format YYYY-MM-DD or null if no date is set
* 'time' => 'Due time', // as string of format hh::ii or null if no due time is set
* 'startdate' => 'Start date' // Delay start of the task until that date
* 'starttime' => 'Start time' // ...and time
* 'categories' => 'Task category',
* 'flagged' => 'Boolean value whether this record is flagged',
* 'complete' => 'Float value representing the completeness state (range 0..1)',

View file

@ -2,8 +2,8 @@
$labels = array();
$labels['navtitle'] = 'Aufgaben';
$labels['lists'] = 'Ressourcen';
$labels['list'] = 'Ressource';
$labels['lists'] = 'Aufgabenlisten';
$labels['list'] = 'Liste';
$labels['tags'] = 'Tags';
$labels['newtask'] = 'Neue Aufgabe';
@ -15,6 +15,7 @@ $labels['delete'] = 'Löschen';
$labels['title'] = 'Titel';
$labels['description'] = 'Beschreibung';
$labels['datetime'] = 'Datum/Zeit';
$labels['start'] = 'Beginn';
$labels['all'] = 'Alle';
$labels['flagged'] = 'Markiert';
@ -51,3 +52,4 @@ $labels['next'] = 'nächsten';
$labels['savingdata'] = 'Daten werden gespeichert...';
$labels['errorsaving'] = 'Fehler beim Speichern.';
$labels['notasksfound'] = 'Für die aktuellen Kriterien wurden keine Aufgaben gefunden.';
$labels['invalidstartduedates'] = 'Beginn der Aufgabe darf nicht grösser als das Enddatum sein.';

View file

@ -2,8 +2,8 @@
$labels = array();
$labels['navtitle'] = 'Tasks';
$labels['lists'] = 'Resources';
$labels['list'] = 'Resource';
$labels['lists'] = 'Tasklists';
$labels['list'] = 'Tasklist';
$labels['tags'] = 'Tags';
$labels['newtask'] = 'New Task';
@ -15,6 +15,7 @@ $labels['delete'] = 'Delete';
$labels['title'] = 'Title';
$labels['description'] = 'Description';
$labels['datetime'] = 'Date/Time';
$labels['start'] = 'Start';
$labels['all'] = 'All';
$labels['flagged'] = 'Flagged';
@ -51,3 +52,4 @@ $labels['next'] = 'next';
$labels['savingdata'] = 'Saving data...';
$labels['errorsaving'] = 'Failed to save data.';
$labels['notasksfound'] = 'No tasks found for the given criteria';
$labels['invalidstartduedates'] = 'Start date must not be greater than due date.';

View file

@ -107,6 +107,11 @@
<span class="task-text"></span>
<span id="task-time"></span>
</div>
<div id="task-start" class="form-section">
<label><roundcube:label name="tasklist.start" /></label>
<span class="task-text"></span>
<span id="task-starttime"></span>
</div>
<div id="task-list" class="form-section">
<label><roundcube:label name="tasklist.list" /></label>
<span class="task-text"></span>
@ -137,16 +142,22 @@
<label for="edit-date"><roundcube:label name="tasklist.datetime" /></label>
<input type="text" name="date" size="10" id="edit-date" tabindex="20" /> &nbsp;
<input type="text" name="time" size="6" id="edit-time" tabindex="21" />
<a href="#nodate" style="margin-left:1em" id="edit-nodate"><roundcube:label name="tasklist.nodate" /></a>
<a href="#nodate" style="margin-left:1em" class="edit-nodate" rel="#edit-date,#edit-time"><roundcube:label name="tasklist.nodate" /></a>
</div>
<div class="form-section">
<label for="edit-startdate"><roundcube:label name="tasklist.start" /></label>
<input type="text" name="startdate" size="10" id="edit-startdate" tabindex="23" /> &nbsp;
<input type="text" name="starttime" size="6" id="edit-starttime" tabindex="24" />
<a href="#nodate" style="margin-left:1em" class="edit-nodate" rel="#edit-startdate,#edit-starttime"><roundcube:label name="tasklist.nodate" /></a>
</div>
<div class="form-section">
<label for="edit-completeness"><roundcube:label name="tasklist.complete" /></label>
<input type="text" name="title" id="edit-completeness" size="3" tabindex="23" />&nbsp;%
<input type="text" name="title" id="edit-completeness" size="3" tabindex="25" />&nbsp;%
<div id="edit-completeness-slider"></div>
</div>
<div class="form-section" id="tasklist-select">
<label for="edit-tasklist"><roundcube:label name="tasklist.list" /></label>
<roundcube:object name="plugin.tasklist_select" id="edit-tasklist" tabindex="24" />
<roundcube:object name="plugin.tasklist_select" id="edit-tasklist" tabindex="26" />
</div>
</form>
</div>

View file

@ -54,6 +54,7 @@ function rcube_tasklist(settings)
var saving_lock;
var ui_loading;
var taskcounts = {};
var listindex = [];
var listdata = {};
var tags = [];
var draghelper;
@ -354,12 +355,14 @@ function rcube_tasklist(settings)
function data_ready(response)
{
listdata = {};
listindex = [];
loadstate.lists = response.lists;
loadstate.filter = response.filter;
loadstate.search = response.search;
for (var i=0; i < response.data.length; i++) {
listdata[response.data[i].id] = response.data[i];
listindex.push(response.data[i].id);
}
render_tasklist();
@ -373,12 +376,13 @@ function rcube_tasklist(settings)
function render_tasklist()
{
// clear display
var rec,
var id, rec,
count = 0,
msgbox = $('#listmessagebox').hide(),
list = $(rcmail.gui_objects.resultlist).html('');
for (var id in listdata) {
for (var i=0; i < listindex.length; i++) {
id = listindex[i];
rec = listdata[id];
if (match_filter(rec)) {
render_task(rec);
@ -436,9 +440,18 @@ function rcube_tasklist(settings)
*/
function update_taskitem(rec)
{
var id = rec.id;
var id = rec.id,
oldid = rec.tempid || id;
oldindex = listindex.indexOf(oldid);
if (oldindex >= 0)
listindex[oldindex] = id;
else
listindex.push(id);
listdata[id] = rec;
render_task(rec, rec.tempid || id);
render_task(rec, oldid);
append_tags(rec.tags || []);
}
@ -525,7 +538,7 @@ function rcube_tasklist(settings)
*/
function resort_task(rec, li, animated)
{
var dir = 0, next_li, next_id, next_rec;
var dir = 0, index, slice, next_li, next_id, next_rec;
// animated moving
var insert_animated = function(li, before, after) {
@ -542,6 +555,13 @@ function rcube_tasklist(settings)
});
}
// remove from list index
var oldindex = listindex.indexOf(rec.id);
if (oldindex >= 0) {
slice = listindex.slice(0,oldindex);
listindex = slice.concat(listindex.slice(oldindex+1));
}
// find the right place to insert the task item
li.siblings().each(function(i, elem){
next_li = $(elem);
@ -558,17 +578,26 @@ function rcube_tasklist(settings)
}
else if (next_rec && next_li && task_cmp(rec, next_rec) < 0) {
if (animated) insert_animated(li, next_li);
else li.insertBefore(next_li)
else li.insertBefore(next_li);
next_li = null;
return false;
}
});
index = listindex.indexOf(next_id);
if (next_li) {
if (animated) insert_animated(li, null, next_li);
else li.insertAfter(next_li);
index++;
}
// insert into list index
if (next_id && index >= 0) {
slice = listindex.slice(0,index);
slice.push(rec.id);
listindex = slice.concat(listindex.slice(index));
}
return;
}
/**
@ -617,15 +646,19 @@ function rcube_tasklist(settings)
{
var drag_id = draggable.data('id'),
parent_id = $(this).data('id'),
rec = listdata[parent_id];
drag_rec = listdata[drag_id],
drop_rec = listdata[parent_id];
if (parent_id == listdata[drag_id].parent_id)
if (drop_rec && drop_rec.list != drag_rec.list)
return false;
while (rec && rec.parent_id) {
if (rec.parent_id == drag_id)
if (parent_id == drag_rec.parent_id)
return false;
rec = listdata[rec.parent_id];
while (drop_rec && drop_rec.parent_id) {
if (drop_rec.parent_id == drag_id)
return false;
drop_rec = listdata[drop_rec.parent_id];
}
return true;
@ -672,6 +705,8 @@ function rcube_tasklist(settings)
$('#task-description').html(text2html(rec.description || '', 300, 6))[(rec.description ? 'show' : 'hide')]();
$('#task-date')[(rec.date ? 'show' : 'hide')]().children('.task-text').html(Q(rec.date || rcmail.gettext('nodate','tasklist')));
$('#task-time').html(Q(rec.time || ''));
$('#task-start')[(rec.startdate ? 'show' : 'hide')]().children('.task-text').html(Q(rec.startdate || ''));
$('#task-starttime').html(Q(rec.starttime || ''));
$('#task-completeness .task-text').html(((rec.complete || 0) * 100) + '%');
$('#task-list .task-text').html(Q(me.tasklists[rec.list] ? me.tasklists[rec.list].name : ''));
@ -732,6 +767,8 @@ function rcube_tasklist(settings)
var description = $('#edit-description').val(rec.description || '');
var recdate = $('#edit-date').val(rec.date || '').datepicker(datepicker_settings);
var rectime = $('#edit-time').val(rec.time || '');
var recstartdate = $('#edit-startdate').val(rec.startdate || '').datepicker(datepicker_settings);
var recstarttime = $('#edit-starttime').val(rec.starttime || '');
var complete = $('#edit-completeness').val((rec.complete || 0) * 100);
completeness_slider.slider('value', complete.val());
var tasklist = $('#edit-tasklist').val(rec.list || 0); // .prop('disabled', rec.parent_id ? true : false);
@ -755,22 +792,31 @@ function rcube_tasklist(settings)
texts: { removeLinkTitle: rcmail.gettext('removetag', 'tasklist') }
});
$('#edit-nodate').unbind('click').click(function(){
recdate.val('');
rectime.val('');
$('a.edit-nodate').unbind('click').click(function(){
var sel = $(this).attr('rel');
if (sel) $(sel).val('');
return false;
})
// define dialog buttons
var buttons = {};
buttons[rcmail.gettext('save', 'tasklist')] = function() {
me.selected_task.title = title.val();
me.selected_task.description = description.val();
me.selected_task.date = recdate.val();
me.selected_task.time = rectime.val();
me.selected_task.list = tasklist.val();
// copy form field contents into task object to save
$.each({ title:title, description:description, date:recdate, time:rectime, startdate:recstartdate, starttime:recstarttime, list:tasklist }, function(key,input){
me.selected_task[key] = input.val();
});
me.selected_task.tags = [];
// do some basic input validation
if (me.selected_task.startdate && me.selected_task.date) {
var startdate = $.datepicker.parseDate(datepicker_settings.dateFormat, me.selected_task.startdate, datepicker_settings);
var duedate = $.datepicker.parseDate(datepicker_settings.dateFormat, me.selected_task.date, datepicker_settings);
if (startdate > duedate) {
alert(rcmail.gettext('invalidstartduedates', 'tasklist'));
return false;
}
}
$('input[name="tags[]"]', rcmail.gui_objects.edittagline).each(function(i,elem){
if (elem.value)
me.selected_task.tags.push(elem.value);
@ -812,9 +858,10 @@ function rcube_tasklist(settings)
$dialog.dialog('destroy').remove();
},
buttons: buttons,
minHeight: 340,
minWidth: 500,
width: 580
}).append(editform.show()); // adding form content AFTERWARDS massively speeds up opening on IE6
}).append(editform.show()); // adding form content AFTERWARDS massively speeds up opening on IE
title.select();
}

View file

@ -261,6 +261,18 @@ class tasklist extends rcube_plugin
}
}
if (!empty($rec['startdate'])) {
try {
$date = new DateTime($rec['startdate'] . ' ' . $rec['starttime'], $this->timezone);
$rec['startdate'] = $date->format('Y-m-d');
if (!empty($rec['starttime']))
$rec['starttime'] = $date->format('H:i');
}
catch (Exception $e) {
$rec['startdate'] = $rec['starttime'] = null;
}
}
return $rec;
}
@ -400,6 +412,7 @@ class tasklist extends rcube_plugin
$rec['mask'] = $this->filter_mask($rec);
$rec['flagged'] = intval($rec['flagged']);
$rec['complete'] = floatval($rec['complete']);
$rec['changed'] = is_object($rec['changed']) ? $rec['changed']->format('U') : null;
if ($rec['date']) {
try {
@ -417,6 +430,17 @@ class tasklist extends rcube_plugin
$rec['_hasdate'] = 0;
}
if ($rec['startdate']) {
try {
$date = new DateTime($rec['startdate'] . ' ' . $rec['starttime'], $this->timezone);
$rec['startdatetime'] = intval($date->format('U'));
$rec['startdate'] = $date->format($this->rc->config->get('date_format', 'Y-m-d'));
}
catch (Exception $e) {
$rec['startdate'] = $rec['startdatetime'] = null;
}
}
if (!isset($rec['_depth'])) {
$rec['_depth'] = 0;
$parent_id = $this->task_tree[$rec['id']];