Page MenuHomePhorge

D165.1775272612.diff
No OneTemporary

Authored By
Unknown
Size
17 KB
Referenced Files
None
Subscribers
None

D165.1775272612.diff

diff --git a/plugins/tasklist/drivers/database/tasklist_database_driver.php b/plugins/tasklist/drivers/database/tasklist_database_driver.php
--- a/plugins/tasklist/drivers/database/tasklist_database_driver.php
+++ b/plugins/tasklist/drivers/database/tasklist_database_driver.php
@@ -332,6 +332,10 @@
$sql_add .= ' AND changed >= ' . $this->rc->db->quote(date('Y-m-d H:i:s', $filter['since']));
}
+ if ($filter['uid']) {
+ $sql_add .= ' AND `uid` IN (' . implode(',', array_map(array($this->rc->db, 'quote'), $filter['uid'])) . ')');
+ }
+
$tasks = array();
if (!empty($list_ids)) {
$result = $this->rc->db->query(sprintf(
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -550,6 +550,7 @@
* - from: Date range start as string (Y-m-d)
* - to: Date range end as string (Y-m-d)
* - search: Search query string
+ * - uid: Task UIDs
* @param array List of lists to get tasks from
* @return array List of tasks records matchin the criteria
*/
@@ -585,6 +586,10 @@
$query[] = array('changed', '>=', $filter['since']);
}
+ if ($filter['uid']) {
+ $query[] = array('uid', '=', (array) $filter['uid']);
+ }
+
foreach ($lists as $list_id) {
if (!$folder = $this->get_folder($list_id)) {
continue;
diff --git a/plugins/tasklist/localization/en_US.inc b/plugins/tasklist/localization/en_US.inc
--- a/plugins/tasklist/localization/en_US.inc
+++ b/plugins/tasklist/localization/en_US.inc
@@ -13,6 +13,10 @@
$labels['lists'] = 'Tasklists';
$labels['list'] = 'Tasklist';
$labels['tags'] = 'Tags';
+$labels['export'] = 'Export';
+$labels['exporttitle'] = 'Export to iCalendar';
+$labels['exportattachments'] = 'With attachments';
+$labels['currentview'] = 'current view';
$labels['tasklistsubscribe'] = 'List permanently';
$labels['listsearchresults'] = 'Available Tasklists';
$labels['findlists'] = 'Find tasklists...';
diff --git a/plugins/tasklist/skins/larry/buttons.png b/plugins/tasklist/skins/larry/buttons.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/plugins/tasklist/skins/larry/images/buttons.png b/plugins/tasklist/skins/larry/images/buttons.png
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/plugins/tasklist/skins/larry/sprites.png b/plugins/tasklist/skins/larry/images/sprites.png
rename from plugins/tasklist/skins/larry/sprites.png
rename to plugins/tasklist/skins/larry/images/sprites.png
diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css
--- a/plugins/tasklist/skins/larry/tasklist.css
+++ b/plugins/tasklist/skins/larry/tasklist.css
@@ -11,7 +11,7 @@
*/
#taskbar a.button-tasklist span.button-inner {
- background-image: url(buttons.png);
+ background-image: url(images/buttons.png);
background-position: 0 0;
}
@@ -22,10 +22,22 @@
ul.toolbarmenu li span.icon.taskadd,
#attachmentmenu li a.tasklistlink span.icon.taskadd {
- background-image: url(buttons.png);
+ background-image: url(images/buttons.png);
background-position: -4px -90px;
}
+#taskstoolbar a.button.export {
+ background-image: url(images/buttons.png);
+ background-position: center -179px;
+ min-width: 50px;
+ max-width: 70px;
+}
+
+#taskstoolbar a.button.import {
+ background-image: url(images/buttons.png);
+ background-position: center -139px;
+}
+
#taskedit.uidialog,
.tasklistview div.uidialog {
display: none;
@@ -296,7 +308,7 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- background: url(sprites.png) right 20px no-repeat;
+ background: url(images/sprites.png) right 20px no-repeat;
}
.quickview-active #tasklistsbox .treelist li input,
@@ -341,7 +353,7 @@
height: 16px;
padding: 0;
margin-right: 4px;
- background: url(sprites.png) -200px 0 no-repeat;
+ background: url(images/sprites.png) -200px 0 no-repeat;
overflow: hidden;
text-indent: -5000px;
cursor: pointer;
@@ -461,7 +473,7 @@
}
#taskstoolbar a.button.newtask {
- background-image: url(buttons.png);
+ background-image: url(images/buttons.png);
background-position: center -53px;
}
@@ -547,7 +559,7 @@
.buttonbar-right a.iconbutton {
padding: 0;
- background-image: url(sprites.png);
+ background-image: url(images/sprites.png);
background-position: 0 -238px;
}
@@ -599,7 +611,7 @@
width: 14px;
height: 14px;
- background: url(sprites.png) -2px -80px no-repeat;
+ background: url(images/sprites.png) -2px -80px no-repeat;
text-indent: -1000px;
overflow: hidden;
}
@@ -648,7 +660,7 @@
display: inline-block;
width: 16px;
height: 16px;
- background: url(sprites.png) 1000px -3px no-repeat;
+ background: url(images/sprites.png) 1000px -3px no-repeat;
margin: -3px 1em 0 0;
vertical-align: middle;
cursor: pointer;
@@ -730,7 +742,7 @@
right: 6px;
width: 18px;
height: 18px;
- background: url(sprites.png) 1000px -80px no-repeat;
+ background: url(images/sprites.png) 1000px -80px no-repeat;
text-indent: -5000px;
overflow: hidden;
cursor: pointer;
@@ -772,7 +784,7 @@
ul.toolbarmenu li span.collapse,
ul.toolbarmenu li span.history,
ul.toolbarmenu.iconized .selected span.icon {
- background-image: url(sprites.png);
+ background-image: url(images/sprites.png);
}
ul.toolbarmenu li span.add {
@@ -1162,7 +1174,7 @@
#taskedit-links .attachmentslist li.message.eml,
#task-links .attachmentslist li.message.eml {
- background-image: url(sprites.png);
+ background-image: url(images/sprites.png);
background-position: -2px -388px;
}
@@ -1411,7 +1423,7 @@
left: 8px;
width: 18px;
height: 18px;
- background: url(buttons.png) -6px -115px no-repeat;
+ background: url(images/buttons.png) -6px -115px no-repeat;
}
div.messagetasklinks ul.tasklist {
diff --git a/plugins/tasklist/skins/larry/templates/mainview.html b/plugins/tasklist/skins/larry/templates/mainview.html
--- a/plugins/tasklist/skins/larry/templates/mainview.html
+++ b/plugins/tasklist/skins/larry/templates/mainview.html
@@ -17,6 +17,7 @@
<div id="taskstoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
<roundcube:button command="newtask" type="link" class="button newtask disabled" classAct="button newtask" classSel="button newtask pressed" label="tasklist.newtask" title="tasklist.newtask" />
<roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="print" title="tasklist.printtitle" />
+ <roundcube:button command="export" type="link" class="button export disabled" classAct="button export" classSel="button export pressed" label="tasklist.export" title="tasklist.exporttitle" />
<roundcube:container name="toolbar" id="taskstoolbar" />
</div>
@@ -320,6 +321,10 @@
<roundcube:container name="tasklistform" id="tasklistform" />
</div>
+<div id="tasksexport" class="uidialog">
+ <roundcube:object name="plugin.tasks_export_form" id="tasks-export-form" />
+</div>
+
<script type="text/javascript">
// UI startup
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -820,6 +820,92 @@
loadstate.lists = active_lists();
}
+ // open a tasks export dialog
+ this.export_tasks = function()
+ {
+ // close show dialog first
+ var $dialog = $("#tasksexport"),
+ form = rcmail.gui_objects.exportform,
+ buttons = {};
+
+ if (!form)
+ return;
+
+ if ($dialog.is(':ui-dialog'))
+ $dialog.dialog('close');
+
+ $("#task-export-list").val('');
+
+ buttons[rcmail.gettext('export', 'tasklist')] = function() {
+ var source = $('#task-export-list option:selected').val();
+
+ // "current view" export, use hidden form to POST task IDs
+ if (source === '') {
+ var cache = {}, tasks = [], inputs = [],
+ postform = $('#tasks-export-form-post');
+
+ $.each(listindex || [], function() {
+ var rec = listdata[this];
+ if (match_filter(rec, cache)) {
+ tasks.push(rec.id);
+ }
+ });
+
+ // copy form inputs, there may be controls added by other plugins
+ $('#tasksexport select, #tasksexport input').each(function() {
+ if (this.type != 'checkbox' || this.checked)
+ inputs.push($('<input>').attr({type: 'hidden', name: this.name, value: this.value}));
+ });
+
+ inputs.push($('<input>').attr({type: 'hidden', name: '_token', value: rcmail.env.request_token}));
+ inputs.push($('<input>').attr({type: 'hidden', name: 'id', value: tasks.join(',')}));
+
+ if (!postform.length)
+ postform = $('<form>')
+ .attr({style: 'display: none', method: 'POST', action: '?_task=tasks&_action=export'})
+ .appendTo('body');
+
+ postform.html('').append(inputs).submit();
+ }
+ // otherwise we can use simple GET
+ else {
+ rcmail.goto_url('export', {source: source, attachments: attach});
+ }
+
+ $dialog.dialog("close");
+ };
+
+ buttons[rcmail.gettext('cancel', 'tasklist')] = function() {
+ $dialog.dialog("close");
+ };
+
+ // open jquery UI dialog
+ $dialog.dialog({
+ modal: true,
+ resizable: false,
+ closeOnEscape: false,
+ title: rcmail.gettext('exporttitle', 'tasklist'),
+ open: function() {
+ $dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
+ },
+ close: function() {
+ $('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
+ $dialog.dialog("destroy").hide();
+ },
+ buttons: buttons,
+ width: 520
+ }).show();
+ };
+/*
+ // download the selected task as iCal
+ this.task_download = function(task)
+ {
+ if (task && task.id) {
+ rcmail.goto_url('export', {source: task.list, id: task.id, attachments: 1});
+ }
+ };
+*/
+
/**
* Modify query parameters for refresh requests
*/
@@ -3367,6 +3453,7 @@
rcmail.register_command('list-remove', function(){ rctasks.list_remove(rctasks.selected_list); }, false);
rcmail.register_command('list-showurl', function(){ rctasks.list_showurl(rctasks.selected_list); }, false);
+ rcmail.register_command('export', function(){ rctasks.export_tasks(); }, true);
rcmail.register_command('search', function(){ rctasks.quicksearch(); }, true);
rcmail.register_command('reset-search', function(){ rctasks.reset_search(); }, true);
rcmail.register_command('expand-all', function(){ rctasks.expand_collapse(true); }, true);
diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php
--- a/plugins/tasklist/tasklist.php
+++ b/plugins/tasklist/tasklist.php
@@ -119,6 +119,7 @@
$this->register_action('mail2task', array($this, 'mail_message2task'));
$this->register_action('get-attachment', array($this, 'attachment_get'));
$this->register_action('upload', array($this, 'attachment_upload'));
+ $this->register_action('export', array($this, 'export_tasks'));
$this->register_action('mailimportitip', array($this, 'mail_import_itip'));
$this->register_action('mailimportattach', array($this, 'mail_import_attachment'));
$this->register_action('itip-status', array($this, 'task_itip_status'));
@@ -1578,6 +1579,79 @@
return $p;
}
+ /**
+ * Construct the ics file for exporting tasks to iCalendar format
+ */
+ function export_tasks()
+ {
+ $source = rcube_utils::get_input_value('source', rcube_utils::INPUT_GPC);
+ $task_id = rcube_utils::get_input_value('id', rcube_utils::INPUT_GPC);
+ $attachments = (bool) rcube_utils::get_input_value('attachments', rcube_utils::INPUT_GPC);
+
+ $this->load_driver();
+
+ $browser = new rcube_browser;
+ $lists = $this->driver->get_lists();
+ $tasks = array();
+ $filter = array();
+
+ // get message UIDs for filter
+ if ($source && ($list = $lists[$source])) {
+ $filename = html_entity_decode($list['name']) ?: $sorce;
+ $filter = array($source => true);
+ }
+ else if ($task_id) {
+ $filename = 'tasks';
+ foreach (explode(',', $task_id) as $id) {
+ list($list_id, $task_id) = explode(':', $id, 2);
+ if ($list_id && $task_id) {
+ $filter[$list_id][] = $task_id;
+ }
+ }
+ }
+
+ // Get tasks
+ foreach ($filter as $list_id => $uids) {
+ $_filter = is_array($uids) ? array('uid' => $uids) : null;
+ $_tasks = $this->driver->list_tasks($_filter, $list_id);
+ if (!empty($_tasks)) {
+ $tasks = array_merge($tasks, $_tasks);
+ }
+ }
+
+ // Set file name
+ if ($source && count($tasks) == 1) {
+ $filename = $tasks[0]['title'] ?: 'task';
+ }
+ $filename .= '.ics';
+ $filename = $browser->ie ? rawurlencode($filename) : addcslashes($filename, '"');
+
+ $tasks = array_map(array($this, 'to_libcal'), $tasks);
+
+ // Give plugins a possibility to implement other output formats or modify the result
+ $plugin = $this->rc->plugins->exec_hook('tasks_export', array(
+ 'result' => $tasks,
+ 'attachments' => $attachments,
+ 'filename' => $filename,
+ 'plugin' => $this,
+ ));
+
+ if ($plugin['abort']) {
+ exit;
+ }
+
+ $this->rc->output->nocacheing_headers();
+
+ // don't kill the connection if download takes more than 30 sec.
+ @set_time_limit(0);
+ header("Content-Type: text/calendar");
+ header("Content-Disposition: inline; filename=\"". $plugin['filename'] ."\"");
+
+ $this->get_ical()->export($plugin['tasks'], '', true,
+ $plugins['attachments'] ? array($this->driver, 'get_attachment_body') : null);
+ exit;
+ }
+
/******* Attachment handling *******/
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -161,6 +161,7 @@
$this->plugin->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
$this->plugin->register_handler('plugin.task_rsvp_buttons', array($this->plugin->itip, 'itip_rsvp_buttons'));
$this->plugin->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table'));
+ $this->plugin->register_handler('plugin.tasks_export_form', array($this, 'tasks_export_form'));
jqueryui::tagedit();
@@ -310,11 +311,18 @@
*/
function tasklist_select($attrib = array())
{
- $attrib['name'] = 'list';
+ if (empty($attrib['name'])) {
+ $attrib['name'] = 'list';
+ }
+
$attrib['is_escaped'] = true;
$select = new html_select($attrib);
$default = null;
+ foreach ((array) $attrib['extra'] as $id => $name) {
+ $select->add($name, $id);
+ }
+
foreach ((array)$this->plugin->driver->get_lists() as $id => $prop) {
if ($prop['editable'] || strpos($prop['rights'], 'i') !== false) {
$select->add($prop['name'], $id);
@@ -526,6 +534,38 @@
}
/**
+ * Form to select options for exporting tasks
+ */
+ function tasks_export_form($attrib = array())
+ {
+ if (!$attrib['id']) {
+ $attrib['id'] = 'rcmTaskExportForm';
+ }
+
+ $html .= html::div('form-section',
+ html::label('task-export-list', $this->plugin->gettext('list')) .
+ $this->tasklist_select(array(
+ 'name' => 'source',
+ 'id' => 'task-export-list',
+ 'extra' => array('' => '- ' . $this->plugin->gettext('currentview') . ' -'),
+ ))
+ );
+
+ $checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'task-export-attachments', 'value' => 1));
+ $html .= html::div('form-section',
+ html::label('task-export-attachments', $this->plugin->gettext('exportattachments')) .
+ $checkbox->show(1)
+ );
+
+ $this->register_gui_object('exportform', $attrib['id']);
+
+ return html::tag('form', array('action' => $this->rc->url(array('task' => 'tasklist', 'action' => 'export')),
+ 'method' => "post", 'id' => $attrib['id']),
+ $html
+ );
+ }
+
+ /**
* Wrapper for rcube_output_html::add_gui_object()
*/
function register_gui_object($name, $id)
diff --git a/source/tasklist_buttons.psd b/source/tasklist_buttons.psd
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/source/tasklist_sprites.psd b/source/tasklist_sprites.psd
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 4, 3:16 AM (15 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18824330
Default Alt Text
D165.1775272612.diff (17 KB)

Event Timeline