2 commits - plugins/libkolab plugins/tasklist

Thomas Brüderli bruederli at kolabsys.com
Fri Aug 3 14:07:48 CEST 2012


 plugins/libkolab/lib/kolab_format_journal.php                  |    5 
 plugins/libkolab/lib/kolab_format_note.php                     |    3 
 plugins/libkolab/lib/kolab_format_xcal.php                     |    1 
 plugins/tasklist/drivers/database/tasklist_database_driver.php |   46 ++
 plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php       |    4 
 plugins/tasklist/localization/en_US.inc                        |    6 
 plugins/tasklist/skins/larry/tasklist.css                      |    4 
 plugins/tasklist/skins/larry/templates/mainview.html           |    4 
 plugins/tasklist/skins/larry/templates/taskedit.html           |   46 +-
 plugins/tasklist/tasklist.js                                   |  190 ++++++++--
 plugins/tasklist/tasklist.php                                  |    7 
 plugins/tasklist/tasklist_ui.php                               |   61 ++-
 12 files changed, 292 insertions(+), 85 deletions(-)

New commits:
commit 627f970dea5f741dfa667c5c1a9e9c1913ae8982
Author: Thomas Bruederli <thomas at roundcube.net>
Date:   Fri Aug 3 14:07:58 2012 +0200

    Make task alarm properties available in the UI (no triggering yet); use globally unique identifiers for form elements

diff --git a/plugins/tasklist/drivers/database/tasklist_database_driver.php b/plugins/tasklist/drivers/database/tasklist_database_driver.php
index acc8fa0..9bd0625 100644
--- a/plugins/tasklist/drivers/database/tasklist_database_driver.php
+++ b/plugins/tasklist/drivers/database/tasklist_database_driver.php
@@ -26,6 +26,7 @@ class tasklist_database_driver extends tasklist_driver
 {
     public $undelete = true; // yes, we can
     public $sortable = false;
+    public $alarm_types = array('DISPLAY','EMAIL');
 
     private $rc;
     private $plugin;
@@ -367,14 +368,15 @@ class tasklist_database_driver extends tasklist_driver
         if (!$this->lists[$list_id] || $this->lists[$list_id]['readonly'])
             return false;
 
-        foreach (array('parent_id', 'date', 'time') as $col) {
+        foreach (array('parent_id', 'date', 'time', 'startdate', 'starttime', 'alarms') as $col) {
             if (empty($prop[$col]))
                 $prop[$col] = null;
         }
 
+        $notify_at = $this->_get_notification($prop);
         $result = $this->rc->db->query(sprintf(
             "INSERT INTO " . $this->db_tasks . "
-             (tasklist_id, uid, parent_id, created, changed, title, date, time, description, tags)
+             (tasklist_id, uid, parent_id, created, changed, title, date, time, starttime, starttime, description, tags, alarms, notify)
              VALUES (?, ?, ?, %s, %s, ?, ?, ?, ?, ?)",
              $this->rc->db->now(),
              $this->rc->db->now()
@@ -385,8 +387,12 @@ class tasklist_database_driver extends tasklist_driver
             $prop['title'],
             $prop['date'],
             $prop['time'],
+            $prop['startdate'],
+            $prop['starttime'],
             strval($prop['description']),
-            join(',', (array)$prop['tags'])
+            join(',', (array)$prop['tags']),
+            $prop['alarms'],
+            $notify_at
         );
 
         if ($result)
@@ -409,13 +415,18 @@ 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', 'startdate', 'starttime') as $col) {
+        foreach (array('parent_id', 'date', 'time', 'startdate', 'starttime', 'alarms') as $col) {
             if (isset($prop[$col]))
                 $sql_set[] = $this->rc->db->quote_identifier($col) . '=' . (empty($prop[$col]) ? 'NULL' : $this->rc->db->quote($prop[$col]));
         }
         if (isset($prop['tags']))
             $sql_set[] = $this->rc->db->quote_identifier('tags') . '=' . $this->rc->db->quote(join(',', (array)$prop['tags']));
 
+        if (isset($prop['date']) || isset($prop['time']) || isset($prop['alarms'])) {
+            $notify_at = $this->_get_notification($prop);
+            $sql_set[] = $this->rc->db->quote_identifier('notify') . '=' . (empty($notify_at) ? 'NULL' : $this->rc->db->quote($notify_at));
+        }
+
         // moved from another list
         if ($prop['_fromlist'] && ($newlist = $prop['list'])) {
             $sql_set[] = 'tasklist_id=' . $this->rc->db->quote($newlist);
@@ -495,4 +506,31 @@ class tasklist_database_driver extends tasklist_driver
         return $this->rc->db->affected_rows($query);
     }
 
+    /**
+     * Compute absolute time to notify the user
+     */
+    private function _get_notification($task)
+    {
+        // fake object properties to suit the expectations of calendar::get_next_alarm()
+        // TODO: move all that to libcalendaring plugin
+        if ($task['date'])
+            $task['start'] = new DateTime($task['date'] . ' ' . ($task['time'] ?: '23:00'), $this->plugin->timezone);
+        if ($task['startdate'])
+            $task['end'] = new DateTime($task['startdate'] . ' ' . ($task['starttime'] ?: '06:00'), $this->plugin->timezone);
+        else
+            $task['end'] = $tast['start'];
+
+        if (!$task['start'])
+            $task['end'] = $task['start'];
+
+        if ($task['alarms'] && $task['start'] > new DateTime() || strpos($task['alarms'], '@') !== false) {
+            $alarm = calendar::get_next_alarm($task);
+
+        if ($alarm['time'] && $alarm['action'] == 'DISPLAY')
+          return date('Y-m-d H:i:s', $alarm['time']);
+      }
+
+      return null;
+    }
+
 }
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index 13f51fa..25d4c08 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -347,6 +347,10 @@ class tasklist_kolab_driver extends tasklist_driver
             $task['changed'] = $record['dtstamp'];
         }
 
+        if ($record['alarms']) {
+            $task['alarms'] = $record['alarms'];
+        }
+
         if (!empty($record['_attachments'])) {
             foreach ($record['_attachments'] as $key => $attachment) {
                 if ($attachment !== false) {
diff --git a/plugins/tasklist/localization/en_US.inc b/plugins/tasklist/localization/en_US.inc
index ba7be2e..35bae10 100644
--- a/plugins/tasklist/localization/en_US.inc
+++ b/plugins/tasklist/localization/en_US.inc
@@ -41,9 +41,9 @@ $labels['tabrecurrence'] = 'Recurrence';
 $labels['tabattachments'] = 'Attachments';
 $labels['tabsharing'] = 'Sharing';
 
-$labels['editlist'] = 'Edit resource';
-$labels['createlist'] = 'Add resource';
-$labels['listactions'] = 'Resource options...';
+$labels['editlist'] = 'Edit list';
+$labels['createlist'] = 'Add list';
+$labels['listactions'] = 'List options...';
 $labels['listname'] = 'Name';
 $labels['showalarms'] = 'Show alarms';
 $labels['import'] = 'Import';
diff --git a/plugins/tasklist/skins/larry/tasklist.css b/plugins/tasklist/skins/larry/tasklist.css
index 32eee74..df82cc7 100644
--- a/plugins/tasklist/skins/larry/tasklist.css
+++ b/plugins/tasklist/skins/larry/tasklist.css
@@ -616,7 +616,7 @@ label.block {
 	margin-bottom: 0.3em;
 }
 
-#edit-completeness-slider {
+#taskedit-completeness-slider {
 	display: inline-block;
 	margin-left: 2em;
 	width: 30em;
@@ -624,7 +624,7 @@ label.block {
 	border: 1px solid #ccc;
 }
 
-#edit-tagline {
+#taskedit-tagline {
 	width: 97%;
 }
 
diff --git a/plugins/tasklist/skins/larry/templates/mainview.html b/plugins/tasklist/skins/larry/templates/mainview.html
index 773badf..b347a0c 100644
--- a/plugins/tasklist/skins/larry/templates/mainview.html
+++ b/plugins/tasklist/skins/larry/templates/mainview.html
@@ -112,6 +112,10 @@
 		<span class="task-text"></span>
 		<span id="task-starttime"></span>
 	</div>
+	<div id="task-alarm" class="form-section">
+		<label><roundcube:label name="calendar.alarms" /></label>
+		<span class="task-text"></span>
+	</div>
 	<div id="task-list" class="form-section">
 		<label><roundcube:label name="tasklist.list" /></label>
 		<span class="task-text"></span>
diff --git a/plugins/tasklist/skins/larry/templates/taskedit.html b/plugins/tasklist/skins/larry/templates/taskedit.html
index 8cad89b..1773fea 100644
--- a/plugins/tasklist/skins/larry/templates/taskedit.html
+++ b/plugins/tasklist/skins/larry/templates/taskedit.html
@@ -6,48 +6,52 @@
 		<!-- basic info -->
 		<div id="taskedit-tab-1">
 			<div class="form-section">
-				<label for="edit-title"><roundcube:label name="tasklist.title" /></label>
+				<label for="taskedit-title"><roundcube:label name="tasklist.title" /></label>
 				<br />
-				<input type="text" class="text" name="title" id="edit-title" size="60" tabindex="1" />
+				<input type="text" class="text" name="title" id="taskedit-title" size="60" tabindex="1" />
 			</div>
 			<div class="form-section">
-				<label for="edit-description"><roundcube:label name="tasklist.description" /></label>
+				<label for="taskedit-description"><roundcube:label name="tasklist.description" /></label>
 				<br />
-				<textarea name="description" id="edit-description" class="text" rows="5" cols="60" tabindex="2"></textarea>
+				<textarea name="description" id="taskedit-description" class="text" rows="5" cols="60" tabindex="2"></textarea>
 			</div>
 			<div class="form-section">
-				<label for="edit-tags"><roundcube:label name="tasklist.tags" /></label>
-				<roundcube:object name="plugin.tags_editline" id="edit-tagline" class="tagedit" tabindex="3" />
+				<label for="taskedit-tags"><roundcube:label name="tasklist.tags" /></label>
+				<roundcube:object name="plugin.tags_editline" id="taskedit-tagline" class="tagedit" tabindex="3" />
 			</div>
 			<div class="form-section">
-				<label for="edit-date"><roundcube:label name="tasklist.datetime" /></label>
-				<input type="text" name="date" size="10" id="edit-date" tabindex="20" />  
-				<input type="text" name="time" size="6" id="edit-time" tabindex="21" />
-				<a href="#nodate" style="margin-left:1em" class="edit-nodate" rel="#edit-date,#edit-time"><roundcube:label name="tasklist.nodate" /></a>
+				<label for="taskedit-date"><roundcube:label name="tasklist.datetime" /></label>
+				<input type="text" name="date" size="10" id="taskedit-date" tabindex="20" />  
+				<input type="text" name="time" size="6" id="taskedit-time" tabindex="21" />
+				<a href="#nodate" style="margin-left:1em" class="edit-nodate" rel="#taskedit-date,#taskedit-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" />  
-				<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>
+				<label for="taskedit-startdate"><roundcube:label name="tasklist.start" /></label>
+				<input type="text" name="startdate" size="10" id="taskedit-startdate" tabindex="23" />  
+				<input type="text" name="starttime" size="6" id="taskedit-starttime" tabindex="24" />
+				<a href="#nodate" style="margin-left:1em" class="edit-nodate" rel="#taskedit-startdate,#taskedit-starttime"><roundcube:label name="tasklist.nodate" /></a>
+			</div>
+			<div class="form-section" id="taskedit-alarms">
+				<label for="taskedit-alarm"><roundcube:label name="calendar.alarms" /></label>
+				<roundcube:object name="plugin.alarm_select" />
 			</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="25" /> %
-				<div id="edit-completeness-slider"></div>
+				<label for="taskedit-completeness"><roundcube:label name="tasklist.complete" /></label>
+				<input type="text" name="title" id="taskedit-completeness" size="3"  tabindex="25" /> %
+				<div id="taskedit-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="26" />
+				<label for="taskedit-tasklist"><roundcube:label name="tasklist.list" /></label>
+				<roundcube:object name="plugin.tasklist_select" id="taskedit-tasklist" tabindex="26" />
 			</div>
 		</div>
 		<!-- attachments list (with upload form) -->
 		<div id="taskedit-tab-2">
 			<div id="taskedit-attachments">
-				<roundcube:object name="plugin.attachments_list" id="attachment-list" class="attachmentslist" />
+				<roundcube:object name="plugin.attachments_list" id="taskedit-attachment-list" class="attachmentslist" />
 			</div>
 			<div id="taskedit-attachments-form">
-				<roundcube:object name="plugin.attachments_form" id="tasklist-attachment-form" attachmentFieldSize="30" />
+				<roundcube:object name="plugin.attachments_form" id="taskedit-attachment-form" attachmentFieldSize="30" />
 			</div>
 			<roundcube:object name="plugin.filedroparea" id="taskedit-tab-2" />
 		</div>
diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index 2457b44..f393c46 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -60,6 +60,7 @@ function rcube_tasklist_ui(settings)
     var draghelper;
     var search_request;
     var search_query;
+    var completeness_slider;
     var me = this;
 
     // general datepicker settings
@@ -93,22 +94,6 @@ function rcube_tasklist_ui(settings)
     this.unlock_saving = unlock_saving;
 
 
-    /* basic initializations */
-
-    $('#taskedit').tabs();
-
-    var completeness_slider = $('#edit-completeness-slider').slider({
-        range: 'min',
-        slide: function(e, ui){
-            var v = completeness_slider.slider('value');
-            if (v >= 98) v = 100;
-            if (v <= 2)  v = 0;
-            $('#edit-completeness').val(v);
-        }
-    });
-    $('#edit-completeness').change(function(e){ completeness_slider.slider('value', parseInt(this.value)) });
-
-
     /**
      * initialize the tasks UI
      */
@@ -313,6 +298,45 @@ function rcube_tasklist_ui(settings)
     }
 
     /**
+     * initialize task edit form elements
+     */
+    function init_taskedit()
+    {
+        $('#taskedit').tabs();
+
+        completeness_slider = $('#taskedit-completeness-slider').slider({
+            range: 'min',
+            slide: function(e, ui){
+                var v = completeness_slider.slider('value');
+                if (v >= 98) v = 100;
+                if (v <= 2)  v = 0;
+                $('#taskedit-completeness').val(v);
+            }
+        });
+        $('#taskedit-completeness').change(function(e){
+            completeness_slider.slider('value', parseInt(this.value))
+        });
+
+        // register events on alarm fields
+        $('#taskedit select.edit-alarm-type').change(function(){
+            $(this).parent().find('span.edit-alarm-values')[(this.selectedIndex>0?'show':'hide')]();
+        });
+        $('#taskedit select.edit-alarm-offset').change(function(){
+            var mode = $(this).val() == '@' ? 'show' : 'hide';
+            $(this).parent().find('.edit-alarm-date, .edit-alarm-time')[mode]();
+            $(this).parent().find('.edit-alarm-value').prop('disabled', mode == 'show');
+        });
+
+        $('#taskedit-date, #taskedit-startdate, #taskedit .edit-alarm-date').datepicker(datepicker_settings);
+
+        $('a.edit-nodate').click(function(){
+            var sel = $(this).attr('rel');
+            if (sel) $(sel).val('');
+            return false;
+        });
+    }
+
+    /**
      * Request counts from the server
      */
     function fetch_counts()
@@ -725,6 +749,7 @@ function rcube_tasklist_ui(settings)
         $('#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-alarm')[(rec.alarms_text ? 'show' : 'hide')]().children('.task-text').html(Q(rec.alarms_text));
         $('#task-completeness .task-text').html(((rec.complete || 0) * 100) + '%');
         $('#task-list .task-text').html(Q(me.tasklists[rec.list] ? me.tasklists[rec.list].name : ''));
 
@@ -793,16 +818,19 @@ function rcube_tasklist_ui(settings)
         if (!me.selected_task.id)
             me.selected_task.id = -(++idcount);
 
+        // reset dialog first
+        $('#taskeditform').get(0).reset();
+
         // fill form data
-        var title = $('#edit-title').val(rec.title || '');
-        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);
+        var title = $('#taskedit-title').val(rec.title || '');
+        var description = $('#taskedit-description').val(rec.description || '');
+        var recdate = $('#taskedit-date').val(rec.date || '');
+        var rectime = $('#taskedit-time').val(rec.time || '');
+        var recstartdate = $('#taskedit-startdate').val(rec.startdate || '');
+        var recstarttime = $('#taskedit-starttime').val(rec.starttime || '');
+        var complete = $('#taskedit-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);
+        var tasklist = $('#taskedit-tasklist').val(rec.list || 0).prop('disabled', rec.parent_id ? true : false);
 
         // tag-edit line
         var tagline = $(rcmail.gui_objects.edittagline).empty();
@@ -823,11 +851,32 @@ function rcube_tasklist_ui(settings)
             texts: { removeLinkTitle: rcmail.gettext('removetag', 'tasklist') }
         });
 
-        $('a.edit-nodate').unbind('click').click(function(){
-            var sel = $(this).attr('rel');
-            if (sel) $(sel).val('');
-            return false;
-        })
+        // set alarm(s)
+        if (rec.alarms) {
+            if (typeof rec.alarms == 'string')
+                rec.alarms = rec.alarms.split(';');
+
+          for (var alarm, i=0; i < rec.alarms.length; i++) {
+              alarm = String(rec.alarms[i]).split(':');
+              if (!alarm[1] && alarm[0]) alarm[1] = 'DISPLAY';
+              $('#taskedit select.edit-alarm-type').val(alarm[1]);
+
+              if (alarm[0].match(/@(\d+)/)) {
+                  var ondate = fromunixtime(parseInt(RegExp.$1));
+                  $('#taskedit select.edit-alarm-offset').val('@');
+                  $('#taskedit input.edit-alarm-date').val(format_datetime(ondate, 1));
+                  $('#taskedit input.edit-alarm-time').val(format_datetime(ondate, 2));
+              }
+              else if (alarm[0].match(/([-+])(\d+)([MHD])/)) {
+                  $('#taskedit input.edit-alarm-value').val(RegExp.$2);
+                  $('#taskedit select.edit-alarm-offset').val(''+RegExp.$1+RegExp.$3);
+              }
+
+              break; // only one alarm is currently supported
+          }
+        }
+        // set correct visibility by triggering onchange handlers
+        $('#taskedit select.edit-alarm-type, #taskedit select.edit-alarm-offset').change();
 
         // attachments
         rcmail.enable_command('remove-attachment', !list.readonly);
@@ -874,6 +923,16 @@ function rcube_tasklist_ui(settings)
                     me.selected_task.tags.push(elem.value);
             });
 
+            // serialize alarm settings
+            var alarm = $('#taskedit select.edit-alarm-type').val();
+            if (alarm) {
+                var val, offset = $('#taskedit select.edit-alarm-offset').val();
+                if (offset == '@')
+                    me.selected_task.alarms = '@' + date2unixtime(parse_datetime($('#taskedit input.edit-alarm-time').val(), $('#taskedit input.edit-alarm-date').val())) + ':' + alarm;
+              else if ((val = parseInt($('#taskedit input.edit-alarm-value').val())) && !isNaN(val) && val >= 0)
+                    me.selected_task.alarms = offset[0] + val + offset[1] + ':' + alarm;
+            }
+
             // uploaded attachments list
             for (var i in rcmail.env.attachments) {
                 if (i.match(/^rcmfile(.+)/))
@@ -1069,9 +1128,9 @@ function rcube_tasklist_ui(settings)
             list = { name:'', editable:true, showalarms:true };
 
         // fill edit form
-        var name = $('#edit-tasklistame').prop('disabled', !list.editable).val(list.editname || list.name),
-            alarms = $('#edit-showalarms').prop('checked', list.showalarms).get(0),
-            parent = $('#edit-parentfolder').val(list.parentfolder);
+        var name = $('#taskedit-tasklistame').prop('disabled', !list.editable).val(list.editname || list.name),
+            alarms = $('#taskedit-showalarms').prop('checked', list.showalarms).get(0),
+            parent = $('#taskedit-parentfolder').val(list.parentfolder);
 
         // dialog buttons
         var buttons = {};
@@ -1351,6 +1410,73 @@ function rcube_tasklist_ui(settings)
       })
       .data('id', id);
     }
+
+
+    /****  calendaring utility functions  *****/
+    /*  TO BE MOVED TO libcalendaring plugin  */
+
+    var gmt_offset = (new Date().getTimezoneOffset() / -60) - (rcmail.env.calendar_settings.timezone || 0) - (rcmail.env.calendar_settings.dst || 0);
+    var client_timezone = new Date().getTimezoneOffset();
+
+    /**
+     * from time and date strings to a real date object
+     */
+    function parse_datetime(time, date)
+    {
+        // we use the utility function from datepicker to parse dates
+        var date = date ? $.datepicker.parseDate(datepicker_settings.dateFormat, date, datepicker_settings) : new Date();
+
+        var time_arr = time.replace(/\s*[ap][.m]*/i, '').replace(/0([0-9])/g, '$1').split(/[:.]/);
+        if (!isNaN(time_arr[0])) {
+            date.setHours(time_arr[0]);
+        if (time.match(/p[.m]*/i) && date.getHours() < 12)
+            date.setHours(parseInt(time_arr[0]) + 12);
+        else if (time.match(/a[.m]*/i) && date.getHours() == 12)
+            date.setHours(0);
+      }
+      if (!isNaN(time_arr[1]))
+            date.setMinutes(time_arr[1]);
+
+      return date;
+    }
+
+    /**
+     * Format the given date object according to user's prefs
+     */
+    function format_datetime(date, mode)
+    {
+        var format =
+             mode == 2 ?  rcmail.env.calendar_settings['time_format'] :
+            (mode == 1 ? rcmail.env.calendar_settings['date_format'] :
+             rcmail.env.calendar_settings['date_format'] + '  '+ rcmail.env.calendar_settings['time_format']);
+
+        return $.fullCalendar.formatDate(date, format);
+    }
+
+    /**
+     * convert the given Date object into a unix timestamp respecting browser's and user's timezone settings
+     */
+    function date2unixtime(date)
+    {
+        var dst_offset = (client_timezone - date.getTimezoneOffset()) * 60;  // adjust DST offset
+        return Math.round(date.getTime()/1000 + gmt_offset * 3600 + dst_offset);
+    }
+
+    /**
+     *
+     */
+    function fromunixtime(ts)
+    {
+        ts -= gmt_offset * 3600;
+        var date = new Date(ts * 1000),
+            dst_offset = (client_timezone - date.getTimezoneOffset()) * 60;
+        if (dst_offset)  // adjust DST offset
+            date.setTime((ts + 3600) * 1000);
+        return date;
+    }
+
+    // init dialog by default
+    init_taskedit();
 }
 
 
diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php
index e1559d6..13635a7 100644
--- a/plugins/tasklist/tasklist.php
+++ b/plugins/tasklist/tasklist.php
@@ -301,6 +301,10 @@ class tasklist extends rcube_plugin
             }
         }
 
+        // alarms cannot work without a date
+        if ($rec['alarms'] && !$rec['date'] && !$rec['startdate'] && strpos($task['alarms'], '@') === false)
+            $rec['alarms'] = '';
+
         $attachments = array();
         $taskid = $rec['id'];
         if (is_array($_SESSION['tasklist_session']) && $_SESSION['tasklist_session']['id'] == $taskid) {
@@ -501,6 +505,9 @@ class tasklist extends rcube_plugin
             }
         }
 
+        if ($rec['alarms'])
+            $rec['alarms_text'] = calendar::alarms_text($rec['alarms']);
+
         foreach ((array)$rec['attachments'] as $k => $attachment) {
             $rec['attachments'][$k]['classname'] = rcmail_filetype2classname($attachment['mimetype'], $attachment['name']);
         }
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
index 370237e..330e7a6 100644
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -81,6 +81,7 @@ class tasklist_ui
         $this->plugin->register_handler('plugin.tasks', array($this, 'tasks_resultview'));
         $this->plugin->register_handler('plugin.tagslist', array($this, 'tagslist'));
         $this->plugin->register_handler('plugin.tags_editline', array($this, 'tags_editline'));
+        $this->plugin->register_handler('plugin.alarm_select', array($this, 'alarm_select'));
         $this->plugin->register_handler('plugin.attachments_form', array($this, 'attachments_form'));
         $this->plugin->register_handler('plugin.attachments_list', array($this, 'attachments_list'));
         $this->plugin->register_handler('plugin.filedroparea', array($this, 'file_drop_area'));
@@ -156,22 +157,22 @@ class tasklist_ui
     {
         $fields = array(
             'name' => array(
-                'id' => 'edit-tasklistame',
+                'id' => 'taskedit-tasklistame',
                 'label' => $this->plugin->gettext('listname'),
-                'value' => html::tag('input', array('id' => 'edit-tasklistame', 'name' => 'name', 'type' => 'text', 'class' => 'text', 'size' => 40)),
+                'value' => html::tag('input', array('id' => 'taskedit-tasklistame', 'name' => 'name', 'type' => 'text', 'class' => 'text', 'size' => 40)),
             ),
 /*
             'color' => array(
-                'id' => 'edit-color',
+                'id' => 'taskedit-color',
                 'label' => $this->plugin->gettext('color'),
-                'value' => html::tag('input', array('id' => 'edit-color', 'name' => 'color', 'type' => 'text', 'class' => 'text colorpicker', 'size' => 6)),
+                'value' => html::tag('input', array('id' => 'taskedit-color', 'name' => 'color', 'type' => 'text', 'class' => 'text colorpicker', 'size' => 6)),
             ),
+*/
             'showalarms' => array(
-                'id' => 'edit-showalarms',
+                'id' => 'taskedit-showalarms',
                 'label' => $this->plugin->gettext('showalarms'),
-                'value' => html::tag('input', array('id' => 'edit-showalarms', 'name' => 'color', 'type' => 'checkbox')),
+                'value' => html::tag('input', array('id' => 'taskedit-showalarms', 'name' => 'color', 'type' => 'checkbox')),
             ),
-*/
         );
 
         return html::tag('form', array('action' => "#", 'method' => "post", 'id' => 'tasklisteditform'),
@@ -180,18 +181,38 @@ class tasklist_ui
     }
 
     /**
-     * Render a HTML select box to select a task category
+     * Render HTML form for alarm configuration
      */
-    function category_select($attrib = array())
+    function alarm_select($attrib = array())
     {
-        $attrib['name'] = 'categories';
-        $select = new html_select($attrib);
-        $select->add('---', '');
-        foreach ((array)$this->plugin->driver->list_categories() as $cat => $color) {
-            $select->add($cat, $cat);
-        }
+        unset($attrib['name']);
+        $select_type = new html_select(array('name' => 'alarmtype[]', 'class' => 'edit-alarm-type'));
+        $select_type->add(rcube_label('none'), '');
+        foreach ($this->plugin->driver->alarm_types as $type)
+            $select_type->add(rcube_label(strtolower("calendar.alarm{$type}option")), $type);
+
+        $input_value = new html_inputfield(array('name' => 'alarmvalue[]', 'class' => 'edit-alarm-value', 'size' => 3));
+        $input_date = new html_inputfield(array('name' => 'alarmdate[]', 'class' => 'edit-alarm-date', 'size' => 10));
+        $input_time = new html_inputfield(array('name' => 'alarmtime[]', 'class' => 'edit-alarm-time', 'size' => 6));
+
+        $select_offset = new html_select(array('name' => 'alarmoffset[]', 'class' => 'edit-alarm-offset'));
+        foreach (array('-M','-H','-D','+M','+H','+D','@') as $trigger)
+            $select_offset->add(rcube_label('calendar.trigger' . $trigger), $trigger);
+
+        // pre-set with default values from user settings
+        $preset = calendar::parse_alaram_value($this->rc->config->get('calendar_default_alarm_offset', '-15M'));
+        $hidden = array('style' => 'display:none');
+        $html = html::span('edit-alarm-set',
+            $select_type->show($this->rc->config->get('calendar_default_alarm_type', '')) . ' ' .
+            html::span(array('class' => 'edit-alarm-values', 'style' => 'display:none'),
+            $input_value->show($preset[0]) . ' ' .
+            $select_offset->show($preset[1]) . ' ' .
+            $input_date->show('', $hidden) . ' ' .
+            $input_time->show('', $hidden)
+            )
+        );
 
-        return $select->show(null);
+      return $html;
     }
 
     /**
@@ -226,7 +247,7 @@ class tasklist_ui
      */
     function tagslist($attrib)
     {
-        $attrib += array('id' => 'rcmtagslist');
+        $attrib += array('id' => 'rcmtasktagslist');
         unset($attrib['name']);
 
         $this->rc->output->add_gui_object('tagslist', $attrib['id']);
@@ -238,7 +259,7 @@ class tasklist_ui
      */
     function tags_editline($attrib)
     {
-        $attrib += array('id' => 'rcmtagsedit');
+        $attrib += array('id' => 'rcmtasktagsedit');
         $this->rc->output->add_gui_object('edittagline', $attrib['id']);
 
         $input = new html_inputfield(array('name' => 'tags[]', 'class' => 'tag', 'size' => $attrib['size'], 'tabindex' => $attrib['tabindex']));
@@ -251,7 +272,7 @@ class tasklist_ui
     function attachments_list($attrib = array())
     {
         if (!$attrib['id'])
-            $attrib['id'] = 'rcmAttachmentList';
+            $attrib['id'] = 'rcmtaskattachmentlist';
 
         $this->rc->output->add_gui_object('attachmentlist', $attrib['id']);
 
@@ -265,7 +286,7 @@ class tasklist_ui
     {
         // add ID if not given
         if (!$attrib['id'])
-            $attrib['id'] = 'rcmUploadForm';
+            $attrib['id'] = 'rcmtaskuploadform';
 
         // Get max filesize, enable upload progress bar
         $max_filesize = rcube_upload_init();


commit 0fc3c6f288f01172609fdc24c8564cf602e87543
Author: Thomas Bruederli <thomas at roundcube.net>
Date:   Fri Aug 3 14:05:22 2012 +0200

    Expose the libkolabxml object's created date/time (where available)

diff --git a/plugins/libkolab/lib/kolab_format_journal.php b/plugins/libkolab/lib/kolab_format_journal.php
index 3be3813..5869af0 100644
--- a/plugins/libkolab/lib/kolab_format_journal.php
+++ b/plugins/libkolab/lib/kolab_format_journal.php
@@ -97,8 +97,9 @@ class kolab_format_journal extends kolab_format
 
         // read object properties
         $object = array(
-            'uid'       => $this->obj->uid(),
-            'changed'   => $this->obj->lastModified(),
+            'uid'     => $this->obj->uid(),
+            'created' => self::php_datetime($this->obj->created()),
+            'changed' => self::php_datetime($this->obj->lastModified()),
         );
 
 
diff --git a/plugins/libkolab/lib/kolab_format_note.php b/plugins/libkolab/lib/kolab_format_note.php
index 9abf5f4..1c88a8b 100644
--- a/plugins/libkolab/lib/kolab_format_note.php
+++ b/plugins/libkolab/lib/kolab_format_note.php
@@ -97,7 +97,8 @@ class kolab_format_note extends kolab_format
         // read object properties
         $object = array(
             'uid'       => $this->obj->uid(),
-            'changed'   => $this->obj->lastModified(),
+            'created'   => self::php_datetime($this->obj->created()),
+            'changed'   => self::php_datetime($this->obj->lastModified()),
         );
 
 
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index e1bfdd7..1191df5 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -97,6 +97,7 @@ abstract class kolab_format_xcal extends kolab_format
 
         $object = array(
             'uid'         => $this->obj->uid(),
+            'created'     => self::php_datetime($this->obj->created()),
             'changed'     => self::php_datetime($this->obj->lastModified()),
             'title'       => $this->obj->summary(),
             'location'    => $this->obj->location(),





More information about the commits mailing list