From: Jan Schneider Date: Sat, 12 Jun 2010 15:13:10 +0000 (+0200) Subject: Add links to edit and delete tasks from the traditional calendar interface. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=7e3440b207db90c35549d3fc9a76a0ef82887fa3;p=horde.git Add links to edit and delete tasks from the traditional calendar interface. Allow to change task due dates from the ajax interface. --- diff --git a/kronolith/js/kronolith.js b/kronolith/js/kronolith.js index f2ac0418c..165fe14e3 100644 --- a/kronolith/js/kronolith.js +++ b/kronolith/js/kronolith.js @@ -1676,16 +1676,23 @@ KronolithCore = { } var midnight = this.parseDate(date), + resizable = event.value.pe && (Object.isUndefined(event.value.vl) || event.value.vl), innerDiv = new Element('div', { className: 'kronolithEventInfo' }), minHeight = 0, height, draggerTop, draggerBottom; if (event.value.fi) { - draggerTop = new Element('div', { id: event.value.nodeId + 'top', className: 'kronolithDragger kronolithDraggerTop' }).setStyle(style); + if (resizable) { + draggerTop = new Element('div', { id: event.value.nodeId + 'top', className: 'kronolithDragger kronolithDraggerTop' }).setStyle(style); + div.addClassName('kronolithFirst'); + } } else { innerDiv.setStyle({ top: 0 }); } if (event.value.la) { - draggerBottom = new Element('div', { id: event.value.nodeId + 'bottom', className: 'kronolithDragger kronolithDraggerBottom' }).setStyle(style); + if (resizable) { + draggerBottom = new Element('div', { id: event.value.nodeId + 'bottom', className: 'kronolithDragger kronolithDraggerBottom' }).setStyle(style); + div.addClassName('kronolithLast'); + } } else { innerDiv.setStyle({ bottom: 0 }); } @@ -1708,6 +1715,11 @@ KronolithCore = { if (draggerBottom) { minHeight += draggerBottom.getHeight(); } + if (!minHeight) { + minHeight = parseInt(innerDiv.getStyle('lineHeight')) + + (parseInt(innerDiv.getStyle('paddingTop')) || 0) + + (parseInt(innerDiv.getStyle('paddingBottom')) || 0); + } div.setStyle({ height: Math.max(Math.round(event.value.start.getElapsed(event.value.end) / 60000) * this[storage].height / 60 - this[storage].spacing | 0, minHeight) + 'px' }); if (event.value.pe) { diff --git a/kronolith/lib/Ajax/Application.php b/kronolith/lib/Ajax/Application.php index 224af8d9e..8c0f6e439 100644 --- a/kronolith/lib/Ajax/Application.php +++ b/kronolith/lib/Ajax/Application.php @@ -830,7 +830,7 @@ class Kronolith_Ajax_Application extends Horde_Ajax_Application_Base */ protected function _saveEvent($event) { - $result = $this->_signedResponse($event->calendarType . '|' . $event->calendar); + $result = $this->_signedResponse($this->_vars->cal ? $this->_vars->cal : ($event->calendarType . '|' . $event->calendar)); try { $event->save(); $end = new Horde_Date($this->_vars->view_end); diff --git a/kronolith/lib/Driver/Horde.php b/kronolith/lib/Driver/Horde.php index ac75d66b5..8921b0e9f 100644 --- a/kronolith/lib/Driver/Horde.php +++ b/kronolith/lib/Driver/Horde.php @@ -107,6 +107,22 @@ class Kronolith_Driver_Horde extends Kronolith_Driver } /** + * Saves an (existing) event in the backend. + * + * @param Kronolith_Event_Horde $event The event to save. + * + * @return integer The event id. + * @throws Horde_Exception + */ + public function saveEvent($event) + { + if (!isset($this->api)) { + list($this->api, $category) = explode('/', $this->calendar, 2); + } + $this->_params['registry']->call($this->api . '/saveTimeObject', array($event->timeobject)); + } + + /** * @todo: implement getTimeObject in timeobjects API. * @throws Kronolith_Exception * @throws Horde_Exception_NotFound diff --git a/kronolith/lib/Event.php b/kronolith/lib/Event.php index da7dbfbb2..6c5868a6f 100644 --- a/kronolith/lib/Event.php +++ b/kronolith/lib/Event.php @@ -379,7 +379,7 @@ abstract class Kronolith_Event */ public function getDriver() { - return Kronolith::getDriver(null, $this->calendar); + return Kronolith::getDriver(str_replace('Kronolith_Event_', '', get_class($this)), $this->calendar); } /** @@ -501,6 +501,23 @@ abstract class Kronolith_Event } /** + * Imports a backend specific event object. + * + * @param mixed $eventObject Backend specific event object that this + * object will represent. + */ + public function fromDriver($event) + { + } + + /** + * Prepares this event to be saved to the backend. + */ + public function toDriver() + { + } + + /** * Exports this event in iCalendar format. * * @param Horde_iCalendar &$calendar A Horde_iCalendar object that acts as @@ -1490,6 +1507,7 @@ abstract class Kronolith_Event * - fg: foreground color * - pe: edit permissions? * - pd: delete permissions? + * - vl: variable, i.e. editable length? * - a: alarm text or minutes * - r: recurrence type (Horde_Date_Recurrence::RECUR_* constant) or json * representation of Horde_Date_Recurrence object. @@ -2606,24 +2624,28 @@ abstract class Kronolith_Event if (!$this->private || $this->creator == $GLOBALS['registry']->getAuth()) { - $link .= $this->getEditUrl( + $url = $this->getEditUrl( array('datetime' => $datetime->strftime('%Y%m%d%H%M%S'), - 'url' => $from_url)) - ->link(array('title' => sprintf(_("Edit %s"), $event_title), - 'class' => 'iconEdit')) - . Horde::fullSrcImg('edit-' . $icon_color . '.png', - array('attr' => array('alt' => _("Edit")))) - . ''; + 'url' => $from_url)); + if ($url) { + $link .= $url->link(array('title' => sprintf(_("Edit %s"), $event_title), + 'class' => 'iconEdit')) + . Horde::fullSrcImg('edit-' . $icon_color . '.png', + array('attr' => array('alt' => _("Edit")))) + . ''; + } } if ($this->hasPermission(Horde_Perms::DELETE)) { - $link .= $this->getDeleteUrl( + $url = $this->getDeleteUrl( array('datetime' => $datetime->strftime('%Y%m%d%H%M%S'), - 'url' => $from_url)) - ->link(array('title' => sprintf(_("Delete %s"), $event_title), - 'class' => 'iconDelete')) - . Horde::fullSrcImg('delete-' . $icon_color . '.png', - array('attr' => array('alt' => _("Delete")))) - . ''; + 'url' => $from_url)); + if ($url) { + $link .= $url->link(array('title' => sprintf(_("Delete %s"), $event_title), + 'class' => 'iconDelete')) + . Horde::fullSrcImg('delete-' . $icon_color . '.png', + array('attr' => array('alt' => _("Delete")))) + . ''; + } } } diff --git a/kronolith/lib/Event/Horde.php b/kronolith/lib/Event/Horde.php index 231b47ec9..27ad2eba8 100644 --- a/kronolith/lib/Event/Horde.php +++ b/kronolith/lib/Event/Horde.php @@ -32,11 +32,25 @@ class Kronolith_Event_Horde extends Kronolith_Event protected $_link; /** + * The link to edit this event. + * + * @var string + */ + protected $_editLink; + + /** + * The link to delete this event. + * + * @var string + */ + protected $_deleteLink; + + /** * The link to this event in the ajax interface. * * @var string */ - protected $_ajax_link; + protected $_ajaxLink; /** * Any parameters to identify the object in the other Horde application. @@ -46,6 +60,27 @@ class Kronolith_Event_Horde extends Kronolith_Event protected $_params; /** + * A bitmask of permissions the current user has on this object. + * + * @var integer + */ + protected $_permissions; + + /** + * Whether this event has a variable length. + * + * @boolean + */ + protected $_variableLength; + + /** + * Time object hash. + * + * @array + */ + public $timeobject; + + /** * Constructor. * * @param Kronolith_Driver $driver The backend driver that this event is @@ -59,6 +94,12 @@ class Kronolith_Event_Horde extends Kronolith_Event parent::__construct($driver, $eventObject); } + /** + * Imports a backend specific event object. + * + * @param array $event Backend specific event object that this object + * will represent. + */ public function fromDriver($event) { $eventStart = new Horde_Date($event['start']); @@ -72,7 +113,9 @@ class Kronolith_Event_Horde extends Kronolith_Event $this->status = Kronolith::STATUS_FREE; $this->_params = $event['params']; $this->_link = !empty($event['link']) ? $event['link'] : null; - $this->_ajax_link = !empty($event['ajax_link']) ? $event['ajax_link'] : null; + $this->_editLink = !empty($event['edit_link']) ? $event['edit_link'] : null; + $this->_deleteLink = !empty($event['delete_link']) ? $event['delete_link'] : null; + $this->_ajaxLink = !empty($event['ajax_link']) ? $event['ajax_link'] : null; $this->_backgroundColor = Kronolith::backgroundColor($event); $this->_foregroundColor = Kronolith::foregroundColor($event); @@ -81,7 +124,7 @@ class Kronolith_Event_Horde extends Kronolith_Event $recurrence->setRecurType($event['recurrence']['type']); if (isset($event['recurrence']['end'])) { - $recurrence->setRecurEnd($event['recurrence']['end']); + $recurrence->setRecurEnd(new Horde_Date($event['recurrence']['end'])); } if (isset($event['recurrence']['interval'])) { $recurrence->setRecurInterval($event['recurrence']['interval']); @@ -94,17 +137,65 @@ class Kronolith_Event_Horde extends Kronolith_Event } if (isset($event['recurrence']['exceptions'])) { foreach ($event['recurrence']['exceptions'] as $exception) { - $recurrence->addException(new Horde_Date($exception)); + $recurrence->addException($exception); } } $this->recurrence = $recurrence; } + + if (isset($event['permissions'])) { + $this->_permissions = $event['permissions']; + } + if (isset($event['variable_length'])) { + $this->_variableLength = $event['variable_length']; + } + $this->initialized = true; $this->stored = true; } /** + * Prepares this event to be saved to the backend. + */ + public function toDriver() + { + $this->timeobject = array( + 'id' => substr($this->id, strlen($this->_api) + 1), + 'icon' => $this->icon, + 'title' => $this->title, + 'description' => $this->description, + 'start' => $this->start->format('Y-m-d\TH:i:s'), + 'end' => $this->end->format('Y-m-d\TH:i:s'), + 'params' => $this->_params, + 'link' => $this->_link, + 'ajax_link' => $this->_ajaxLink, + 'permissions' => $this->_permissions, + 'variable_length' => $this->_variableLength); + if ($this->recurs()) { + $this->timeobject['recurrence'] = array('type' => $this->recurrence->getRecurType()); + if ($end = $this->recurrence->getRecurEnd()) { + $this->timeobject['recurrence']['end'] = $end->format('Y-m-d\TH:i:s'); + } + if ($interval = $this->recurrence->getRecurInterval()) { + $this->timeobject['recurrence']['interval'] = $interval; + } + if ($count = $this->recurrence->getRecurCount()) { + $this->timeobject['recurrence']['count'] = $count; + } + if ($days = $this->recurrence->getRecurOnDays()) { + $this->timeobject['recurrence']['days'] = $days; + } + if ($count = $this->recurrence->getRecurCount()) { + $this->timeobject['recurrence']['count'] = $count; + } + if ($exceptions = $this->recurrence->getExceptions()) { + $this->timeobject['recurrence']['exceptions'] = $exceptions; + } + } + } + + /** * Encapsulates permissions checking. * * @param integer $permission The permission to check for. @@ -114,6 +205,10 @@ class Kronolith_Event_Horde extends Kronolith_Event */ public function hasPermission($permission, $user = null) { + if (isset($this->_permissions)) { + return (bool)($this->_permissions & $permission); + } + switch ($permission) { case Horde_Perms::SHOW: case Horde_Perms::READ: @@ -147,7 +242,41 @@ class Kronolith_Event_Horde extends Kronolith_Event return null; } $url = clone $this->_link; - return $this->_link->setRaw($full); + return $url->setRaw($full); + } + + /** + * @param array $params + * + * @return Horde_Url + */ + public function getEditUrl($params = array(), $full = false) + { + if (empty($this->_editLink)) { + return null; + } + $url = clone $this->_editLink; + if (isset($params['url'])) { + $url->add('url', $params['url']); + } + return $url->setRaw($full); + } + + /** + * @param array $params + * + * @return Horde_Url + */ + public function getDeleteUrl($params = array(), $full = false) + { + if (empty($this->_deleteLink)) { + return null; + } + $url = clone $this->_deleteLink; + if (isset($params['url'])) { + $url->add('url', $params['url']); + } + return $url->setRaw($full); } /** @@ -164,11 +293,14 @@ class Kronolith_Event_Horde extends Kronolith_Event public function toJson($allDay = null, $full = false, $time_format = 'H:i') { $json = parent::toJson($allDay, $full, $time_format); - if ($this->_ajax_link) { - $json->aj = $this->_ajax_link; + if ($this->_ajaxLink) { + $json->aj = $this->_ajaxLink; } else { $json->ln = (string)$this->getViewUrl(array(), true); } + if (isset($this->_variableLength)) { + $json->vl = $this->_variableLength; + } return $json; } diff --git a/kronolith/lib/Event/Ical.php b/kronolith/lib/Event/Ical.php index fd945e3fa..1c4084917 100644 --- a/kronolith/lib/Event/Ical.php +++ b/kronolith/lib/Event/Ical.php @@ -18,6 +18,12 @@ class Kronolith_Event_Ical extends Kronolith_Event */ public $calendarType = 'remote'; + /** + * Imports a backend specific event object. + * + * @param Horde_iCalendar_vEvent Backend specific event object that this + * object will represent. + */ public function fromDriver($vEvent) { $this->fromiCalendar($vEvent); @@ -25,6 +31,9 @@ class Kronolith_Event_Ical extends Kronolith_Event $this->stored = true; } + /** + * Prepares this event to be saved to the backend. + */ public function toDriver() { return $this->toiCalendar(); diff --git a/kronolith/lib/Event/Kolab.php b/kronolith/lib/Event/Kolab.php index aef65d97b..44e2182e5 100644 --- a/kronolith/lib/Event/Kolab.php +++ b/kronolith/lib/Event/Kolab.php @@ -42,6 +42,12 @@ class Kronolith_Event_Kolab extends Kronolith_Event $this->_tags = Kronolith::getTagger()->getTags($this->uid, 'event'); } + /** + * Imports a backend specific event object. + * + * @param array $event Backend specific event object that this object + * will represent. + */ public function fromDriver($event) { $this->id = $event['uid']; @@ -158,6 +164,9 @@ class Kronolith_Event_Kolab extends Kronolith_Event $this->stored = true; } + /** + * Prepares this event to be saved to the backend. + */ public function toDriver() { $event = array(); diff --git a/kronolith/lib/Event/Resource.php b/kronolith/lib/Event/Resource.php index bc059c79f..a5c478deb 100644 --- a/kronolith/lib/Event/Resource.php +++ b/kronolith/lib/Event/Resource.php @@ -26,6 +26,12 @@ class Kronolith_Event_Resource extends Kronolith_Event */ private $_properties = array(); + /** + * Imports a backend specific event object. + * + * @param array $event Backend specific event object that this object + * will represent. + */ public function fromDriver($SQLEvent) { $driver = $this->getDriver(); @@ -112,6 +118,9 @@ class Kronolith_Event_Resource extends Kronolith_Event $this->stored = true; } + /** + * Prepares this event to be saved to the backend. + */ public function toDriver() { $driver = $this->getDriver(); diff --git a/kronolith/lib/Event/Sql.php b/kronolith/lib/Event/Sql.php index 57c898836..e95b9f99a 100644 --- a/kronolith/lib/Event/Sql.php +++ b/kronolith/lib/Event/Sql.php @@ -52,6 +52,12 @@ class Kronolith_Event_Sql extends Kronolith_Event } } + /** + * Imports a backend specific event object. + * + * @param array $event Backend specific event object that this object + * will represent. + */ public function fromDriver($SQLEvent) { $driver = $this->getDriver(); @@ -148,6 +154,9 @@ class Kronolith_Event_Sql extends Kronolith_Event $this->stored = true; } + /** + * Prepares this event to be saved to the backend. + */ public function toDriver() { $driver = $this->getDriver(); diff --git a/kronolith/themes/screen.css b/kronolith/themes/screen.css index a9e3fe2d0..8c6253361 100644 --- a/kronolith/themes/screen.css +++ b/kronolith/themes/screen.css @@ -1494,9 +1494,12 @@ div.kronolithEvent .kronolithEventInfo { overflow: hidden; line-height: 16px; } -div.kronolithEditable:hover .kronolithEventInfo, -div.kronolithEvent.kronolithSelected .kronolithEventInfo { +div.kronolithEditable.kronolithFirst:hover .kronolithEventInfo, +div.kronolithEvent.kronolithFirst.kronolithSelected .kronolithEventInfo { top: 7px; +} +div.kronolithEditable.kronolithLast:hover .kronolithEventInfo, +div.kronolithEvent.kronolithLast.kronolithSelected .kronolithEventInfo { bottom: 7px; } div.kronolithEditable:hover .kronolithDragger, diff --git a/nag/lib/Api.php b/nag/lib/Api.php index bd95ff970..7d0d80ad5 100644 --- a/nag/lib/Api.php +++ b/nag/lib/Api.php @@ -1351,9 +1351,13 @@ class Nag_Api extends Horde_Registry_Api 'end' => $due_date, 'category' => $task->category, 'color' => $allowed_tasklists[$task->tasklist]->get('color'), + 'permissions' => $GLOBALS['nag_shares']->getPermissions($task->tasklist, $GLOBALS['registry']->getAuth()), + 'variable_length' => false, 'params' => array('task' => $task->id, 'tasklist' => $task->tasklist), - 'link' => Horde_Util::addParameter(Horde::applicationUrl('view.php', true), array('tasklist' => $task->tasklist, 'task' => $task->id)), + 'link' => Horde::applicationUrl('view.php', true)->add(array('tasklist' => $task->tasklist, 'task' => $task->id)), + 'edit_link' => Horde::applicationUrl('task.php', true)->add(array('tasklist' => $task->tasklist, 'task' => $task->id, 'actionID' => 'modify_task')), + 'delete_link' => Horde::applicationUrl('task.php', true)->add(array('tasklist' => $task->tasklist, 'task' => $task->id, 'actionID' => 'delete_task')), 'ajax_link' => 'task:' . $task->tasklist . ':' . $task->id); } @@ -1361,6 +1365,54 @@ class Nag_Api extends Horde_Registry_Api } /** + * Saves properties of a time object back to the task that it represents. + * + * At the moment only the title, description and due date are saved. + * + * @param array $timeobject A time object hash. + */ + public function saveTimeObject($timeobject) + { + Horde::logMessage(print_r($timeobject, true)); + $storage = Nag_Driver::singleton(); + $existing = $storage->get($timeobject['id']); + if (is_a($existing, 'PEAR_Error')) { + return $existing; + } + if (!array_key_exists($existing->tasklist, + Nag::listTasklists(false, Horde_Perms::EDIT))) { + return PEAR::raiseError(_("Permission Denied")); + } + $storage = Nag_Driver::singleton($existing->tasklist); + + if (isset($timeobject['start'])) { + $due = new Horde_Date($timeobject['start']); + $due = $due->timestamp(); + } else { + $due = $existing->due; + } + + return $storage->modify( + $timeobject['id'], + isset($timeobject['title']) ? $timeobject['title'] : $existing->name, + isset($timeobject['description']) ? $timeobject['description'] : $existing->desc, + $existing->start, + $due, + $existing->priority, + $existing->estimate, + $existing->completed, + $existing->category, + $existing->alarm, + $existing->methods, + $existing->parent_id, + $existing->private, + $existing->owner, + $existing->assignee, + $existing->completed_date, + $existing->tasklist); + } + + /** * Lists alarms for a given moment. * * @param integer $time The time to retrieve alarms for. diff --git a/nag/lib/Driver/Sql.php b/nag/lib/Driver/Sql.php index 6eb18aa33..7d6b1fd21 100644 --- a/nag/lib/Driver/Sql.php +++ b/nag/lib/Driver/Sql.php @@ -74,9 +74,9 @@ class Nag_Driver_Sql extends Nag_Driver { function get($taskId) { /* Build the SQL query. */ - $query = sprintf('SELECT * FROM %s WHERE task_owner = ? and task_id = ?', + $query = sprintf('SELECT * FROM %s WHERE task_id = ?', $this->_params['table']); - $values = array($this->_tasklist, $taskId); + $values = array($taskId); /* Log the query at a DEBUG log level. */ Horde::logMessage(sprintf('Nag_Driver_Sql::get(): %s VALUES: %s', $query, print_r($values, true)), 'DEBUG'); diff --git a/nag/lib/Forms/task.php b/nag/lib/Forms/task.php index 0b8aa9ee4..4dc5a0634 100644 --- a/nag/lib/Forms/task.php +++ b/nag/lib/Forms/task.php @@ -74,6 +74,7 @@ class Nag_TaskForm extends Horde_Form { $this->addHidden('', 'actionID', 'text', true); $this->addHidden('', 'task_id', 'text', false); $this->addHidden('', 'old_tasklist', 'text', false); + $this->addHidden('', 'url', 'text', false); $this->addVariable(_("Name"), 'name', 'text', true); if (!$GLOBALS['prefs']->isLocked('default_tasklist') && diff --git a/nag/lib/Task.php b/nag/lib/Task.php index 2a6a9a8ed..33595e5e6 100644 --- a/nag/lib/Task.php +++ b/nag/lib/Task.php @@ -528,7 +528,7 @@ class Nag_Task { $task_url_task = Horde_Util::addParameter($task_url_list[$this->tasklist], 'task', $this->id); $this->complete_link = Horde_Util::addParameter($task_url_task, 'actionID', 'complete_task'); $this->edit_link = Horde_Util::addParameter($task_url_task, 'actionID', 'modify_task'); - $this->delete_link = Horde_Util::addParameter($task_url_task, 'actionID', 'delete_tasks'); + $this->delete_link = Horde_Util::addParameter($task_url_task, 'actionID', 'delete_task'); } /** diff --git a/nag/task.php b/nag/task.php index 21d0d1c0c..51bf747b4 100644 --- a/nag/task.php +++ b/nag/task.php @@ -41,8 +41,12 @@ function _delete($task_id, $tasklist_id) } } - /* Return to the task list. */ - header('Location: ' . Horde::applicationUrl('list.php', true)); + /* Return to the last page or to the task list. */ + if ($url = Horde_Util::getFormData('url')) { + header('Location: ' . $url); + } else { + header('Location: ' . Horde::applicationUrl('list.php', true)); + } exit; } @@ -103,6 +107,7 @@ case 'modify_task': $vars = new Horde_Variables($task->toHash()); $vars->set('actionID', 'save_task'); $vars->set('old_tasklist', $task->tasklist); + $vars->set('url', Horde_Util::getFormData('url')); $form = new Nag_TaskForm($vars, sprintf(_("Edit: %s"), $task->name), $share->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::DELETE)); break; } @@ -187,14 +192,18 @@ case 'save_task': $notification->push(sprintf(_("There was a problem saving the task: %s."), $result->getMessage()), 'horde.error'); } else { $notification->push(sprintf(_("Saved %s."), $info['name']), 'horde.success'); - /* Return to the task list. */ - header('Location: ' . Horde::applicationUrl('list.php', true)); + /* Return to the last page or to the task list. */ + if ($url = Horde_Util::getFormData('url')) { + header('Location: ' . $url); + } else { + header('Location: ' . Horde::applicationUrl('list.php', true)); + } exit; } break; -case 'delete_tasks': +case 'delete_task': /* Delete the task if we're provided with a valid task ID. */ _delete(Horde_Util::getFormData('task'), Horde_Util::getFormData('tasklist')); diff --git a/nag/view.php b/nag/view.php index 84627fcdf..8cecc65e3 100644 --- a/nag/view.php +++ b/nag/view.php @@ -114,7 +114,7 @@ if ($share->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::EDIT)) { } } if ($share->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::DELETE)) { - $links[] = Horde::widget(Horde::applicationUrl(Horde_Util::addParameter($taskurl, 'actionID', 'delete_tasks')), _("Delete"), 'smallheader', '', $prefs->getValue('delete_opt') ? 'return window.confirm(\'' . addslashes(_("Really delete this task?")) . '\');' : '', _("_Delete")); + $links[] = Horde::widget(Horde::applicationUrl(Horde_Util::addParameter($taskurl, 'actionID', 'delete_task')), _("Delete"), 'smallheader', '', $prefs->getValue('delete_opt') ? 'return window.confirm(\'' . addslashes(_("Really delete this task?")) . '\');' : '', _("_Delete")); } require NAG_TEMPLATES . '/common-header.inc';