$result->task = $task->toJson(true, $prefs->getValue('twentyFour') ? 'H:i' : 'h:i A');
break;
+ case 'SaveTask':
+ if (!$registry->hasMethod('tasks/updateTask')) {
+ break;
+ }
+ if (is_null($id = Horde_Util::getFormData('task_id')) ||
+ is_null($list = Horde_Util::getFormData('old_tasklist'))) {
+ break;
+ }
+ $task = Horde_Util::getFormData('task');
+
+ $due = trim($task['due_date'] . ' ' . $task['due_time']);
+ if (!empty($due)) {
+ // strptime() is locale dependent, i.e. %p is not always matching
+ // AM/PM. Set the locale to C to workaround this, but grab the
+ // locale's D_FMT before that.
+ $date_format = Horde_Nls::getLangInfo(D_FMT);
+ $old_locale = setlocale(LC_TIME, 0);
+ setlocale(LC_TIME, 'C');
+ $format = $date_format . ' '
+ . ($prefs->getValue('twentyFour') ? '%H:%M' : '%I:%M %p');
+
+ // Try exact format match first.
+ if ($date_arr = strptime($due, $format)) {
+ $task['due'] = new Horde_Date(
+ array('year' => $date_arr['tm_year'] + 1900,
+ 'month' => $date_arr['tm_mon'] + 1,
+ 'mday' => $date_arr['tm_mday'],
+ 'hour' => $date_arr['tm_hour'],
+ 'min' => $date_arr['tm_min'],
+ 'sec' => $date_arr['tm_sec']));
+ } else {
+ $task['due'] = new Horde_Date($due);
+ }
+ setlocale(LC_TIME, $old_locale);
+ }
+
+ if ($task['alarm']['on']) {
+ $task['alarm'] = $task['alarm']['value'] * $task['alarm']['unit'];
+ } else {
+ $task['alarm'] = 0;
+ }
+
+ $result = $registry->tasks->updateTask($list, $id, $task);
+ if (is_a($result, 'PEAR_Error')) {
+ $notification->push($result, 'horde.error');
+ break;
+ }
+ $task = $registry->tasks->getTask($task['tasklist'], $id);
+ if (is_a($task, 'PEAR_Error')) {
+ $notification->push($task, 'horde.error');
+ break;
+ }
+ $result = new stdClass;
+ $result->type = $task->completed ? 'complete' : 'incomplete';
+ $result->list = $task->tasklist;
+ $result->sig = Horde_Util::getFormData('sig');
+ $result->tasks = array($id => $task->toJson(false, $prefs->getValue('twentyFour') ? 'H:i' : 'h:i A'));
+ break;
+
case 'DeleteTask':
if (!$registry->hasMethod('tasks/deleteTask')) {
break;
Object.isUndefined(this.tcache.get(type).get(list))) {
loading = true;
this.startLoading('tasks:' + type + list, tasktype);
- this._storeTasksCache($H(), type, list);
+ this._storeTasksCache($H(), type, list, true);
this.doAction('ListTasks',
{ 'type': type,
'sig' : tasktype,
'list': list },
function(r) {
- this._loadTasksCallback(r, tasktype);
+ this._loadTasksCallback(r, tasktype, true);
}.bind(this));
}
}, this);
/**
* Callback method for inserting tasks in the current view.
*
- * @param object r The ajax response object.
+ * @param object r The ajax response object.
+ * @param string tasktype The (UI) task type for that the response was
+ * targeted.
+ * @param boolean createCache Whether to create a cache list entry for the
+ * response, if none exists yet. Useful for
+ * adding individual tasks to the cache without
+ * assuming to have all tasks of the list.
*/
- _loadTasksCallback: function(r, tasktype)
+ _loadTasksCallback: function(r, tasktype, createCache)
{
// Hide spinner.
this.loading--;
$('kronolithLoading').hide();
}
- this._storeTasksCache(r.response.tasks || {}, r.response.type, r.response.list);
+ this._storeTasksCache(r.response.tasks || {}, r.response.type, r.response.list, createCache);
// Check if this is the still the result of the most current request.
if (this.view != 'tasks' ||
}
});
- // TODO: Assuming that tasks of the same tasklist are already in
- // order
- if (rowTasklist == newTask.value.l) {
- continue;
- }
-
if (Object.isUndefined(rowTask)) {
// TODO: Throw error
return;
} else {
$('kronolithTaskId').clear();
$('kronolithTaskOldList').clear();
- $('kronolithTaskList').setValue(Kronolith.conf.default_tasklist);
+ //$('kronolithTaskList').setValue(Kronolith.conf.default_tasklist);
$('kronolithTaskDelete').hide();
$('kronolithTaskDueDate').setValue(d.toString(Kronolith.conf.date_format));
$('kronolithTaskDueTime').setValue(d.toString(Kronolith.conf.time_format));
$('kronolithTaskList').update();
$H(Kronolith.conf.calendars.tasklists).each(function(cal) {
if (cal.value.edit) {
- $('kronolithTaskList').insert(new Element('OPTION', { 'value': 'tasks|' + cal.key })
+ $('kronolithTaskList').insert(new Element('OPTION', { 'value': cal.key.substring(6) })
.setStyle({ 'backgroundColor': cal.value.bg, 'color': cal.value.fg })
.update(cal.value.name.escapeHTML()));
}
},
/**
+ * Submits the task edit form to create or update a task.
+ */
+ saveTask: function()
+ {
+ var tasklist = $F('kronolithTaskList'),
+ taskid = $F('kronolithTaskId');
+ this.startLoading('tasks:' + ($F('kronolithTaskCompleted') ? 'complete' : 'incomplete') + tasklist, this.tasktype);
+ this.doAction('SaveTask',
+ $H($('kronolithTaskForm').serialize({ 'hash': true }))
+ .merge({ 'sig': this.tasktype }),
+ function(r) {
+ if (r.response.tasks && taskid) {
+ this._removeTask(taskid, tasklist);
+ this._loadTasksCallback(r, this.tasktype, false);
+ }
+ this._closeRedBox();
+ window.history.back();
+ }.bind(this));
+ },
+
+ /**
* Parses a date attribute string into a Date object.
*
* For other strings use Date.parse().
/**
* Stores a set of tasks in the cache.
*
- * @param Hash tasks The tasks to be stored.
- * @param string tasktypes The task type that's being stored.
- * @param string tasklist The task list to which the tasks belong.
+ * @param Hash tasks The tasks to be stored.
+ * @param string tasktypes The task type that's being stored.
+ * @param string tasklist The task list to which the tasks belong.
+ * @param boolean createCache Whether to create a cache list entry for the
+ * response, if none exists yet.
*/
- _storeTasksCache: function(tasks, tasktypes, tasklist)
+ _storeTasksCache: function(tasks, tasktypes, tasklist, createCache)
{
- var taskHashes = {};
+ var taskHashes = {}, cacheExists = {};
if (tasktypes == 'all' || tasktypes == 'future') {
tasktypes = [ 'complete', 'incomplete' ];
}
tasktypes.each(function(tasktype) {
+ cacheExists[tasktype] = false;
if (!this.tcache.get(tasktype)) {
- this.tcache.set(tasktype, $H());
+ if (createCache) {
+ this.tcache.set(tasktype, $H());
+ } else {
+ return;
+ }
}
if (!this.tcache.get(tasktype).get(tasklist)) {
- this.tcache.get(tasktype).set(tasklist, $H());
+ if (createCache) {
+ this.tcache.get(tasktype).set(tasklist, $H());
+ cacheExists[tasktype] = true;
+ } else {
+ return;
+ }
+ } else {
+ cacheExists[tasktype] = true;
}
taskHashes[tasktype] = this.tcache.get(tasktype).get(tasklist);
}, this);
$H(tasks).each(function(task) {
+ var tasktype = task.value.cp ? 'complete' : 'incomplete';
+ if (!cacheExists[tasktype]) {
+ return;
+ }
if (!Object.isUndefined(task.value.s)) {
task.value.start = Date.parse(task.value.s);
}
if (!Object.isUndefined(task.value.du)) {
task.value.due = Date.parse(task.value.du);
}
- taskHashes[task.value.cp ? 'complete' : 'incomplete'].set(task.key, task.value);
+ taskHashes[tasktype].set(task.key, task.value);
});
},
e.stop();
break;
+ case 'kronolithTaskForm':
+ this.saveTask();
+ e.stop();
+ break;
+
case 'kronolithSearchForm':
this.go('search:' + $F('kronolithSearchContext') + ':' + $F('kronolithSearchTerm'))
e.stop();
e.stop();
return;
+ case 'kronolithTaskSave':
+ this.saveTask();
+ e.stop();
+ return;
+
case 'kronolithEventDelete':
var cal = $F('kronolithEventCalendar'),
eventid = $F('kronolithEventId');
}
},
+ /**
+ * Submits the event edit form to create or update an event.
+ */
saveEvent: function()
{
var cal = $F('kronolithEventCalendar'),
<div>
<label for="kronolithTaskTitle"><?php echo _("Name") ?>:</label><br />
- <input type="text" name="name" id="kronolithTaskTitle" class="kronolithLongField" />
+ <input type="text" name="task[name]" id="kronolithTaskTitle" class="kronolithLongField" />
</div>
<div>
- <label><input type="checkbox" name="completed" id="kronolithTaskCompleted" value="" /> <?php echo _("completed") ?></label>
+ <label><input type="checkbox" name="task[completed]" id="kronolithTaskCompleted" value="1" /> <?php echo _("completed") ?></label>
</div>
<table cellspacing="" cellpadding="0" border="0"><tbody><tr>
<td>
<div>
<label for="kronolithTaskPriority"><?php echo _("Priority") ?>:</label><br />
- <select name="priority" id="kronolithTaskPriority">
+ <select name="task[priority]" id="kronolithTaskPriority">
<?php foreach (array(1 => '1 ' . _("(highest)"), 2 => 2, 3 => 3, 4 => 4, 5 => '5 ' . _("(lowest)")) as $prio => $label): ?>
<option value="<?php echo $prio ?>"><?php echo $label ?></option>
<?php endforeach; ?>
<td>
<div>
<label for="kronolithTaskList"><?php echo _("Task List") ?>:</label><br />
- <select name="tasklist_id" id="kronolithTaskList">
+ <select name="task[tasklist]" id="kronolithTaskList">
</select>
</div>
</td>
<td>
<div>
<label><?php echo _("Due date") ?>:</label><br />
- <input type="text" name="due_date" id="kronolithTaskDueDate" size="10" class="kronolithDatePicker" />
+ <input type="text" name="task[due_date]" id="kronolithTaskDueDate" size="10" class="kronolithDatePicker" />
<?php echo _("at") ?>
- <input type="text" name="due_time" id="kronolithTaskDueTime" size="8" />
+ <input type="text" name="task[due_time]" id="kronolithTaskDueTime" size="8" />
</div>
</td>
</tr></tbody></table>
<br class="clear" />
<div id="kronolithTaskTabDescription" class="kronolithTabsOption">
- <textarea name="desc" id="kronolithTaskDescription" rows="5" cols="40" class="kronolithLongField"></textarea>
+ <textarea name="task[desc]" id="kronolithTaskDescription" rows="5" cols="40" class="kronolithLongField"></textarea>
</div>
<div id="kronolithTaskTabReminder" class="kronolithTabsOption" style="display:none">
- <label><input type="radio" name="nag_alarm[on]" id="kronolithTaskAlarmOff" value="0" checked="checked" /> <?php echo _("don't set") ?></label>
+ <label><input type="radio" name="task[alarm][on]" id="kronolithTaskAlarmOff" value="0" checked="checked" /> <?php echo _("don't set") ?></label>
<?php echo _("or") ?>
- <label><input type="radio" name="nag_alarm[on]" id="kronolithTaskAlarmOn" value="1" /> <?php echo _("set") ?></label>
+ <label><input type="radio" name="task[alarm][on]" id="kronolithTaskAlarmOn" value="1" /> <?php echo _("set") ?></label>
+ <input type="text" name="task[alarm][value]" id="kronolithTaskAlarmValue" size="3" value="15" class="kronolithEventValue" />
<label>
- <input type="text" name="nag_alarm[value]" id="kronolithTaskAlarmValue" size="3" value="15" class="kronolithEventValue" />
- <select name="nag_alarm[unit]" id="kronolithTaskAlarmUnit">
+ <select name="task[alarm][unit]" id="kronolithTaskAlarmUnit">
<option value="1"><?php echo _("minutes") ?></option>
<option value="60"><?php echo _("hours") ?></option>
<option value="1440"><?php echo _("days") ?></option>
</div>
<div id="kronolithTaskTabUrl" class="kronolithTabsOption" style="display:none">
- <input type="text" name="url" id="taskUrl" class="kronolithLongField" value="http://" />
+ <input type="text" name="task[url]" id="taskUrl" class="kronolithLongField" value="http://" />
</div>
<div id="kronolithTaskActions">
}
/**
+ * Changes a task identified by tasklist and ID.
+ *
+ * @param string $tasklist A tasklist id.
+ * @param string $id A task id.
+ * @param array $task A hash with overwriting task information.
+ */
+ public function updateTask($tasklist, $id, $task)
+ {
+ require_once dirname(__FILE__) . '/base.php';
+
+ if (!Horde_Auth::isAdmin() &&
+ !array_key_exists($tasklist,
+ Nag::listTasklists(false, PERMS_EDIT))) {
+ return PEAR::raiseError(_("Permission Denied"));
+ }
+
+ $storage = Nag_Driver::singleton($tasklist);
+ $existing = $storage->get($id);
+ if (is_a($existing, 'PEAR_Error')) {
+ return $existing;
+ }
+
+ return $storage->modify(
+ $id,
+ isset($task['name']) ? $task['name'] : $existing->name,
+ isset($task['desc']) ? $task['desc'] : $existing->desc,
+ isset($task['start']) ? $task['start'] : $existing->start,
+ isset($task['due']) ? $task['due'] : $existing->due,
+ isset($task['priority']) ? $task['priority'] : $existing->priority,
+ isset($task['estimate']) ? $task['estimate'] : $existing->estimate,
+ isset($task['completed']) ? (int)$task['completed'] : $existing->completed,
+ isset($task['category']) ? $task['category'] : $existing->category,
+ isset($task['alarm']) ? $task['alarm'] : $existing->alarm,
+ isset($task['parent_id']) ? $task['parent_id'] : $existing->parent_id,
+ isset($task['private']) ? $task['private'] : $existing->private,
+ isset($task['owner']) ? $task['owner'] : $existing->owner,
+ isset($task['assignee']) ? $task['assignee'] : $existing->assignee,
+ $task['completed'] && !$existing->completed ? date() : $existing->completed_date,
+ isset($task['tasklist']) ? $task['tasklist'] : $existing->tasklist);
+ }
+
+ /**
* Lists active tasks as cost objects.
*
* @todo Implement $criteria parameter.