plugins/tasklist

Thomas Brüderli bruederli at kolabsys.com
Mon Oct 13 18:42:32 CEST 2014


 plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php |   19 ++++
 plugins/tasklist/drivers/tasklist_driver.php             |   18 +++-
 plugins/tasklist/skins/larry/buttons.png                 |binary
 plugins/tasklist/skins/larry/tasklist.css                |   40 ++++++++
 plugins/tasklist/tasklist.js                             |   21 ++++
 plugins/tasklist/tasklist.php                            |   67 ++++++++++++++-
 plugins/tasklist/tasklist_base.js                        |   28 ++++++
 plugins/tasklist/tasklist_ui.php                         |   17 +++
 8 files changed, 204 insertions(+), 6 deletions(-)

New commits:
commit adc41ebf61bdac6c59beb9796a6881beaad9392c
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Mon Oct 13 18:40:39 2014 +0200

    - List linked tasks in mail view, like notes
    - Deep-links into the tasks view opening the linked task
    - Mark tasks as complete directly from mail view

diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index e44b2c6..3ee1100 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -1238,6 +1238,25 @@ class tasklist_kolab_driver extends tasklist_driver
     }
 
     /**
+     * Find tasks assigned to a specified message
+     *
+     * @see tasklist_driver::get_message_related_tasks()
+     */
+    public function get_message_related_tasks($headers, $folder)
+    {
+        $config = kolab_storage_config::get_instance();
+        $result = $config->get_message_relations($headers, $folder, 'task');
+
+        foreach ($result as $idx => $rec) {
+            $task = $this->_to_rcube_task($rec);
+            $task['list'] = kolab_storage::folder_id($rec['_mailbox']);
+            $result[$idx] = $task;
+        }
+
+        return $result;
+    }
+
+    /**
      * 
      */
     public function tasklist_edit_form($action, $list, $fieldprop)
diff --git a/plugins/tasklist/drivers/tasklist_driver.php b/plugins/tasklist/drivers/tasklist_driver.php
index 2102d21..791d2ab 100644
--- a/plugins/tasklist/drivers/tasklist_driver.php
+++ b/plugins/tasklist/drivers/tasklist_driver.php
@@ -290,8 +290,8 @@ abstract class tasklist_driver
     /**
      * Build a URI representing the given message reference
      *
-     * @param object rcube_message_header Instance holding the message headers
-     * @param string IMAP folder the message resides in
+     * @param object $headers rcube_message_header instance holding the message headers
+     * @param string $folder  IMAP folder the message resides in
      *
      * @return string An URI referencing the given IMAP message
      */
@@ -302,6 +302,20 @@ abstract class tasklist_driver
     }
 
     /**
+     * Find tasks assigned to a specified message
+     *
+     * @param object $message rcube_message_header instance
+     * @param string $folder  IMAP folder the message resides in
+     *
+     * @param array List of linked task objects
+     */
+    public function get_message_related_tasks($headers, $folder)
+    {
+        // to be implemented by the derived classes
+        return array();
+    }
+
+    /**
      * Helper method to determine whether the given task is considered "complete"
      *
      * @param array  $task  Hash array with event properties:
diff --git a/plugins/tasklist/skins/larry/buttons.png b/plugins/tasklist/skins/larry/buttons.png
index 62baed6..7f1a2b6 100644
Binary files a/plugins/tasklist/skins/larry/buttons.png and b/plugins/tasklist/skins/larry/buttons.png differ
diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css
index bf53e6b..832197d 100644
--- a/plugins/tasklist/skins/larry/tasklist.css
+++ b/plugins/tasklist/skins/larry/tasklist.css
@@ -1337,6 +1337,46 @@ div.tasklist-invitebox .rsvp-status.accepted,
 	background-position: 2px -220px;
 }
 
+div.messagetasklinks {
+	margin: 8px 8px;
+	padding: 4px 8px;
+	border: 1px solid #dfdfdf;
+	background: #fafafa;
+	border-radius: 4px;
+}
+
+div.messagetasklinks span.messagetaskref {
+	position: relative;
+	display: inline-block;
+	margin-right: 1em;
+	padding-right: 24px;
+}
+
+div.messagetasklinks a.messagetasklink {
+	position: relative;
+	display: inline-block;
+	color: #333;
+	font-weight: bold;
+	padding: 3px 0 2px 22px;
+	text-shadow: 0px 1px 1px #fff;
+	text-decoration: none;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	max-width: 16em;
+	background: url(buttons.png) -6px -115px no-repeat;
+}
+
+div.messagetasklinks span.messagetaskref.complete a.messagetasklink {
+	text-decoration: line-through;
+}
+
+div.messagetasklinks span.messagetaskref input.complete {
+	position: absolute;
+	top: 1px;
+	right: 2px;
+}
+
 
 /** Special hacks for IE7 **/
 /** They need to be in this file to also affect the task-create dialog embedded in mail view **/
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index 3cadd57..5ec467d 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -137,6 +137,11 @@ function rcube_tasklist_ui(settings)
     {
         // initialize task list selectors
         for (var id in me.tasklists) {
+            if (settings.selected_list && me.tasklists[settings.selected_list] && !me.tasklists[settings.selected_list].active) {
+                me.tasklists[settings.selected_list].active = true;
+                me.selected_list = settings.selected_list;
+                $(rcmail.gui_objects.tasklistslist).find("input[value='"+settings.selected_list+"']").prop('checked', true);
+            }
             if (me.tasklists[id].editable && (!me.selected_list || me.tasklists[id].default || (me.tasklists[id].active && !me.tasklists[me.selected_list].active))) {
                 me.selected_list = id;
             }
@@ -269,10 +274,9 @@ function rcube_tasklist_ui(settings)
         $('#taskviewsortmenu .by-' + (settings.sort_col || 'auto')).attr('aria-checked', 'true').addClass('selected');
         $('#taskviewsortmenu .sortorder.' + (settings.sort_order || 'asc')).attr('aria-checked', 'true').addClass('selected');
 
-
         // start loading tasks
         fetch_counts();
-        list_tasks();
+        list_tasks(settings.selected_filter);
 
         // register event handlers for UI elements
         $('#taskselector a').click(function(e) {
@@ -769,6 +773,19 @@ function rcube_tasklist_ui(settings)
         append_tags(response.tags || []);
         render_tasklist();
 
+        // show selected task dialog
+        if (settings.selected_id) {
+            if (listdata[settings.selected_id]) {
+                task_show_dialog(settings.selected_id);
+                delete settings.selected_id;
+            }
+
+            // remove _id from window location
+            if (window.history.replaceState) {
+                window.history.replaceState({}, document.title, rcmail.url('', { _list: me.selected_list }));
+            }
+        }
+
         rcmail.set_busy(false, 'loading', ui_loading);
     }
 
diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php
index 9acded6..82b3634 100644
--- a/plugins/tasklist/tasklist.php
+++ b/plugins/tasklist/tasklist.php
@@ -61,6 +61,7 @@ class tasklist extends rcube_plugin
     public $home;  // declare public to be used in other classes
 
     private $collapsed_tasks = array();
+    private $message_tasks = array();
     private $itip;
     private $ical;
 
@@ -125,6 +126,9 @@ class tasklist extends rcube_plugin
         }
         else if ($args['task'] == 'mail') {
             if ($args['action'] == 'show' || $args['action'] == 'preview') {
+                if ($this->rc->config->get('tasklist_mail_embed', true)) {
+                    $this->add_hook('message_load', array($this, 'mail_message_load'));
+                }
                 $this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html'));
             }
 
@@ -204,7 +208,8 @@ class tasklist extends rcube_plugin
         $success = $refresh = false;
 
         // force notify if hidden + active
-        if ((int)$this->rc->config->get('calendar_itip_send_option', 3) === 1 && empty($rec['_reportpartstat']))
+        $itip_send_option = (int)$this->rc->config->get('calendar_itip_send_option', 3);
+        if ($itip_send_option === 1 && empty($rec['_reportpartstat']))
             $rec['_notify'] = 1;
 
         switch ($action) {
@@ -220,6 +225,24 @@ class tasklist extends rcube_plugin
             }
             break;
 
+        case 'complete':
+            $complete = intval(rcube_utils::get_input_value('complete', rcube_utils::INPUT_POST));
+            if (!($rec = $this->driver->get_task($rec))) {
+                break;
+            }
+
+            $rec['status'] = $complete ? 'COMPLETED' : ($rec['complete'] > 0 ? 'IN-PROCESS' : 'NEEDS-ACTION');
+
+            // sent itip notifications if enabled (no user interaction here)
+            if (($itip_send_option & 1)) {
+                if ($this->is_attendee($rec)) {
+                    $rec['_reportpartstat'] = $rec['status'];
+                }
+                else if ($this->is_organizer($rec)) {
+                    $rec['_notify'] = 1;
+                }
+            }
+
         case 'edit':
             $rec = $this->prepare_task($rec);
             $clone = $this->handle_recurrence($rec, $this->driver->get_task($rec));
@@ -1437,7 +1460,36 @@ class tasklist extends rcube_plugin
             }
         }
 
-        // prepend event boxes to message body
+        // list linked tasks
+        $links = array();
+        foreach ($this->message_tasks as $task) {
+            $checkbox = new html_checkbox(array(
+                'name' => 'completed',
+                'class' => 'complete',
+                'title' => $this->gettext('complete'),
+                'data-list' => $task['list'],
+            ));
+            $complete = $this->driver->is_complete($task);
+            $links[] = html::span('messagetaskref' . ($complete ? ' complete' : ''),
+                $checkbox->show($complete ? $task['uid'] : null, array('value' => $task['uid'])) . ' ' .
+                html::a(array(
+                    'href' => $this->rc->url(array(
+                        'task' => 'tasks',
+                        'list' => $task['list'],
+                        'id' => $task['uid'],
+                        'complete' => $complete?1:null,
+                    )),
+                    'class' => 'messagetasklink',
+                    'rel' => $task['uid'] . '@' . $task['list'],
+                    'target' => '_blank',
+                ), Q($task['title']))
+            );
+        }
+        if (count($links)) {
+            $html .= html::div('messagetasklinks', join("\n", $links));
+        }
+
+        // prepend iTip/relation boxes to message body
         if ($html) {
             $this->load_ui();
             $this->ui->init();
@@ -1466,6 +1518,17 @@ class tasklist extends rcube_plugin
     }
 
     /**
+     * Lookup backend storage and find notes associated with the given message
+     */
+    public function mail_message_load($p)
+    {
+        if (!$p['object']->headers->others['x-kolab-type']) {
+            $this->load_driver();
+            $this->message_tasks = $this->driver->get_message_related_tasks($p['object']->headers, $p['object']->folder);
+        }
+    }
+
+    /**
      * Load iCalendar functions
      */
     public function get_ical()
diff --git a/plugins/tasklist/tasklist_base.js b/plugins/tasklist/tasklist_base.js
index e399c53..b5ea06e 100644
--- a/plugins/tasklist/tasklist_base.js
+++ b/plugins/tasklist/tasklist_base.js
@@ -30,6 +30,7 @@ function rcube_tasklist(settings)
     /* private vars */
     var ui_loaded = false;
     var me = this;
+    var mywin = window;
 
     /*  public members  */
     this.ui;
@@ -79,6 +80,18 @@ function rcube_tasklist(settings)
     function mail2task_dialog(prop)
     {
         this.ui.edit_task(null, 'new', prop);
+        rcmail.addEventListener('responseaftertask', refresh_mailview);
+    }
+
+    /**
+     * Reload the mail view/preview to update the tasks listing
+     */
+    function refresh_mailview(e)
+    {
+        var win = rcmail.env.contentframe ? rcmail.get_frame_window(rcmail.env.contentframe) : mywin;
+        if (win && e.response.action == 'task') {
+            win.location.reload();
+        }
     }
 
     // handler for attachment-save-tasklist commands
@@ -95,6 +108,21 @@ function rcube_tasklist(settings)
       }
     }
 
+    // register event handlers on linked task items in message view
+    // the checkbox allows to mark a task as complete 
+    if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') {
+        $('div.messagetasklinks input.complete').click(function(e) {
+            var $this = $(this);
+            $(this).closest('.messagetaskref').toggleClass('complete');
+
+            // submit change to server
+            rcmail.http_post('tasks/task', {
+                action: 'complete',
+                t: { id:this.value, list:$this.attr('data-list') },
+                complete: this.checked?1:0
+            }, rcmail.set_busy(true, 'tasklist.savingdata'));
+        });
+    }
 }
 
 /* tasklist plugin initialization (for email task) */
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
index b7bb4d4..5451e2c 100644
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -92,6 +92,23 @@ class tasklist_ui
             'emails' => ';' . strtolower(join(';', $identity['emails']))
         );
 
+        if ($list = rcube_utils::get_input_value('_list', rcube_utils::INPUT_GPC)) {
+            $settings['selected_list'] = $list;
+        }
+        if ($list && ($id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC))) {
+            $settings['selected_id'] = $id;
+
+            // check if the referenced task is completed
+            $task = $this->plugin->driver->get_task(array('id' => $id, 'list' => $list));
+            console($id, $task);
+            if ($task && $this->plugin->driver->is_complete($task)) {
+                $settings['selected_filter'] = 'complete';
+            }
+        }
+        else if ($filter = rcube_utils::get_input_value('_filter', rcube_utils::INPUT_GPC)) {
+            $settings['selected_filter'] = $filter;
+        }
+
         return $settings;
     }
 




More information about the commits mailing list