3 commits - plugins/calendar plugins/libcalendaring

Thomas Brüderli bruederli at kolabsys.com
Wed Mar 6 12:30:52 CET 2013


 plugins/calendar/calendar.php                           |   46 ++++++-
 plugins/calendar/calendar_ui.js                         |  100 ++++++++++------
 plugins/calendar/skins/classic/templates/calendar.html  |    4 
 plugins/calendar/skins/classic/templates/eventedit.html |    4 
 plugins/calendar/skins/larry/calendar.css               |    8 +
 plugins/calendar/skins/larry/templates/calendar.html    |    7 -
 plugins/calendar/skins/larry/templates/eventedit.html   |    6 
 plugins/libcalendaring/libcalendaring.js                |    6 
 8 files changed, 132 insertions(+), 49 deletions(-)

New commits:
commit 12533fbed3797a56c14af6ebe197baa90e0d1f99
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Mar 6 12:30:12 2013 +0100

    Minor calendar UI improvements: make date fields wide enough; display client's current timezone name

diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index eed008d..1835409 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -275,6 +275,7 @@ class calendar extends rcube_plugin
     // initialize attendees autocompletion
     rcube_autocomplete_init();
 
+    $this->rc->output->set_env('timezone', $this->timezone->getName());
     $this->rc->output->set_env('calendar_driver', $this->rc->config->get('calendar_driver'), false);
     $this->rc->output->set_env('mscolors', $this->driver->get_color_values());
     $this->rc->output->set_env('identities-selector', $this->ui->identity_select(array('id' => 'edit-identities-list')));
diff --git a/plugins/calendar/skins/classic/templates/calendar.html b/plugins/calendar/skins/classic/templates/calendar.html
index 6e70a16..0725987 100644
--- a/plugins/calendar/skins/classic/templates/calendar.html
+++ b/plugins/calendar/skins/classic/templates/calendar.html
@@ -106,12 +106,12 @@
   <div style="float:left; width:28em">
     <div class="form-section">
       <label for="schedule-startdate"><roundcube:label name="calendar.start" /></label>
-      <input type="text" name="startdate" size="10" id="schedule-startdate" disabled="true" />  
+      <input type="text" name="startdate" size="11" id="schedule-startdate" disabled="true" />  
       <input type="text" name="starttime" size="6" id="schedule-starttime" disabled="true" />
     </div>
     <div class="form-section">
       <label for="schedule-enddate"><roundcube:label name="calendar.end" /></label>
-      <input type="text" name="enddate" size="10" id="schedule-enddate" disabled="true" />  
+      <input type="text" name="enddate" size="11" id="schedule-enddate" disabled="true" />  
       <input type="text" name="endtime" size="6"  id="schedule-endtime" disabled="true" />
     </div>
   </div>
diff --git a/plugins/calendar/skins/classic/templates/eventedit.html b/plugins/calendar/skins/classic/templates/eventedit.html
index 3548478..a5ace0d 100644
--- a/plugins/calendar/skins/classic/templates/eventedit.html
+++ b/plugins/calendar/skins/classic/templates/eventedit.html
@@ -26,12 +26,12 @@
       <div class="event-section">
         <label style="float:right;padding-right:0.5em"><input type="checkbox" name="allday" id="edit-allday" value="1" /><roundcube:label name="calendar.all-day" /></label>
         <label for="edit-startdate"><roundcube:label name="calendar.start" /></label>
-        <input type="text" name="startdate" size="10" id="edit-startdate" />  
+        <input type="text" name="startdate" size="11" id="edit-startdate" />  
         <input type="text" name="starttime" size="6" id="edit-starttime" />
       </div>
       <div class="event-section">
         <label for="edit-enddate"><roundcube:label name="calendar.end" /></label>
-        <input type="text" name="enddate" size="10" id="edit-enddate" />  
+        <input type="text" name="enddate" size="11" id="edit-enddate" />  
         <input type="text" name="endtime" size="6"  id="edit-endtime" />
       </div>
       <div class="event-section" id="edit-alarms">
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index 282db50..f7278a6 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -125,6 +125,14 @@ div.sidebarclosed {
 	border-bottom-color: #ababab;
 }
 
+#calendar .timezonedisplay {
+	position: absolute;
+	bottom: 9px;
+	right: 8px;
+	font-size: 0.85em;
+	color: #666;
+}
+
 #print {
 	width: 680px;
 }
diff --git a/plugins/calendar/skins/larry/templates/calendar.html b/plugins/calendar/skins/larry/templates/calendar.html
index 5b46d4f..54e7cb8 100644
--- a/plugins/calendar/skins/larry/templates/calendar.html
+++ b/plugins/calendar/skins/larry/templates/calendar.html
@@ -41,6 +41,7 @@
 	<div id="calendar">
 		<roundcube:object name="plugin.angenda_options" class="boxfooter" id="agendaoptions" />
 		<roundcube:object name="message" id="message" class="statusbar" />
+		<div class="timezonedisplay"><roundcube:var name="env:timezone" /></div>
 	</div>
 </div>
 
@@ -119,13 +120,13 @@
 	<div style="float:left; width:28em">
 		<div class="form-section">
 			<label for="schedule-startdate"><roundcube:label name="calendar.start" /></label>
-			<input type="text" name="startdate" size="10" id="schedule-startdate" disabled="true" />  
+			<input type="text" name="startdate" size="11" id="schedule-startdate" disabled="true" />  
 			<input type="text" name="starttime" size="6" id="schedule-starttime" disabled="true" />
 		</div>
 		<div class="form-section">
 			<label for="schedule-enddate"><roundcube:label name="calendar.end" /></label>
-			<input type="text" name="enddate" size="10" id="schedule-enddate" disabled="true" />  
-			<input type="text" name="endtime" size="6"	id="schedule-endtime" disabled="true" />
+			<input type="text" name="enddate" size="11" id="schedule-enddate" disabled="true" />  
+			<input type="text" name="endtime" size="6" id="schedule-endtime" disabled="true" />
 		</div>
 	</div>
 	<div style="float:left">
diff --git a/plugins/calendar/skins/larry/templates/eventedit.html b/plugins/calendar/skins/larry/templates/eventedit.html
index 841baf7..6784891 100644
--- a/plugins/calendar/skins/larry/templates/eventedit.html
+++ b/plugins/calendar/skins/larry/templates/eventedit.html
@@ -23,13 +23,13 @@
 			<div class="event-section">
 				<label style="float:right;padding-right:0.5em"><input type="checkbox" name="allday" id="edit-allday" value="1" /><roundcube:label name="calendar.all-day" /></label>
 				<label for="edit-startdate"><roundcube:label name="calendar.start" /></label>
-				<input type="text" name="startdate" size="10" id="edit-startdate" />  
+				<input type="text" name="startdate" size="11" id="edit-startdate" />  
 				<input type="text" name="starttime" size="6" id="edit-starttime" />
 			</div>
 			<div class="event-section">
 				<label for="edit-enddate"><roundcube:label name="calendar.end" /></label>
-				<input type="text" name="enddate" size="10" id="edit-enddate" />  
-				<input type="text" name="endtime" size="6"	id="edit-endtime" />
+				<input type="text" name="enddate" size="11" id="edit-enddate" />  
+				<input type="text" name="endtime" size="6" id="edit-endtime" />
 			</div>
 			<div class="event-section" id="edit-alarms">
 				<label for="edit-alarm"><roundcube:label name="calendar.alarms" /></label>


commit 7678954ba3b41babbdd84eef6e1ff77546cfb075
Author: Thomas Bruederli <thomas at roundcube.net>
Date:   Wed Mar 6 11:45:40 2013 +0100

    Fix free/busy finder for all-day events

diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 036e1ca..19698fb 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -1232,10 +1232,10 @@ function rcube_calendar_ui(settings)
     {
       // fix all-day evebt times
       if (me.selected_event.allDay) {
+        var numdays = Math.floor((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / DAY_MS);
         start.setHours(12);
         start.setMinutes(0);
-        if (end.getHours() == 0)
-          end.setHours(-1);
+        end.setTime(start.getTime() + numdays * DAY_MS);
         end.setHours(13);
         end.setMinutes(0);
       }
@@ -1252,13 +1252,13 @@ function rcube_calendar_ui(settings)
     var freebusy_find_slot = function(dir)
     {
       var event = me.selected_event,
-        eventstart = event.start.getTime(),  // calculate with integers
-        eventend = event.end.getTime(),
-        duration = eventend - eventstart,
+        eventstart = clone_date(event.start, event.allDay ? 1 : 0).getTime(),  // calculate with integers
+        eventend = clone_date(event.end, event.allDay ? 2 : 0).getTime(),
+        duration = eventend - eventstart - (event.allDay ? HOUR_MS : 0),  // make sure we don't cross day borders on DST change
         sinterval = freebusy_data.interval * 60000,
         intvlslots = 1,
         numslots = Math.ceil(duration / sinterval),
-        checkdate, slotend, email, ts, slot, slotdate = new Date(), slotenddate = new Date();
+        checkdate, slotend, email, ts, slot, slotdate = new Date();
 
       // shift event times to next possible slot
       eventstart += sinterval * intvlslots * dir;
@@ -1269,9 +1269,13 @@ function rcube_calendar_ui(settings)
       for (slot = dir > 0 ? freebusy_data.start.getTime() : freebusy_data.end.getTime() - sinterval;
             (dir > 0 && slot < freebusy_data.end.getTime()) || (dir < 0 && slot >= freebusy_data.start.getTime());
             slot += sinterval * dir) {
-        slotend = slot + sinterval;
         slotdate.setTime(slot);
-        slotenddate.setTime(slotend);
+        // fix slot if just crossed a DST change
+        if (event.allDay) {
+          fix_date(slotdate);
+          slot = slotdate.getTime();
+        }
+        slotend = slot + sinterval;
 
         if ((dir > 0 && slotend <= eventstart) || (dir < 0 && slot >= eventend))  // skip
           continue;


commit 7e4b581b4e31b6512ba656a3a05acd30175edc19
Author: Thomas Bruederli <thomas at roundcube.net>
Date:   Wed Mar 6 10:57:56 2013 +0100

    Make free/busy finder DST aware (#1676)

diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 058b801..eed008d 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -1383,6 +1383,16 @@ class calendar extends rcube_plugin
     $start = get_input_value('start', RCUBE_INPUT_GPC);
     $end = get_input_value('end', RCUBE_INPUT_GPC);
     
+    // convert dates into unix timestamps
+    if (!empty($start) && !is_numeric($start)) {
+      $dts = new DateTime($start, $this->timezone);
+      $start = $dts->format('U');
+    }
+    if (!empty($end) && !is_numeric($end)) {
+      $dte = new DateTime($end, $this->timezone);
+      $end = $dte->format('U');
+    }
+    
     if (!$start) $start = time();
     if (!$end) $end = $start + 3600;
     
@@ -1420,11 +1430,27 @@ class calendar extends rcube_plugin
     $start = get_input_value('start', RCUBE_INPUT_GPC);
     $end = get_input_value('end', RCUBE_INPUT_GPC);
     $interval = intval(get_input_value('interval', RCUBE_INPUT_GPC));
-    
+    $strformat = $interval > 60 ? 'Ymd' : 'YmdHis';
+
+    // convert dates into unix timestamps
+    if (!empty($start) && !is_numeric($start)) {
+      $dts = new DateTime($start, $this->timezone);
+      $start = $dts->format('U');
+    }
+    if (!empty($end) && !is_numeric($end)) {
+      $dte = new DateTime($end, $this->timezone);
+      $end = $dte->format('U');
+    }
+
     if (!$start) $start = time();
     if (!$end)   $end = $start + 86400 * 30;
     if (!$interval) $interval = 60;  // 1 hour
     
+    if (!$dte) {
+      $dts = new DateTime('@'.$start);
+      $dts->setTimezone($this->timezone);
+    }
+    
     $fblist = $this->driver->get_freebusy_list($email, $start, $end);
     $slots = array();
     
@@ -1432,7 +1458,9 @@ class calendar extends rcube_plugin
     for ($s = 0, $t = $start; $t <= $end; $s++) {
       $status = self::FREEBUSY_UNKNOWN;
       $t_end = $t + $interval * 60;
-        
+      $dt = new DateTime('@'.$t);
+      $dt->setTimezone($this->timezone);
+
       // determine attendee's status
       if (is_array($fblist)) {
         $status = self::FREEBUSY_FREE;
@@ -1447,13 +1475,24 @@ class calendar extends rcube_plugin
       }
       
       $slots[$s] = $status;
+      $times[$s] = intval($dt->format($strformat));
       $t = $t_end;
     }
     
+    $dte = new DateTime('@'.$t_end);
+    $dte->setTimezone($this->timezone);
+    
     // let this information be cached for 5min
     send_future_expire_header(300);
     
-    echo json_encode(array('email' => $email, 'start' => intval($start), 'end' => intval($t_end), 'interval' => $interval, 'slots' => $slots));
+    echo json_encode(array(
+      'email' => $email,
+      'start' => $dts->format('c'),
+      'end'   => $dte->format('c'),
+      'interval' => $interval,
+      'slots' => $slots,
+      'times' => $times,
+    ));
     exit;
   }
   
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index f4c7749..036e1ca 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -74,6 +74,7 @@ function rcube_calendar_ui(settings)
     var parse_datetime = this.parse_datetime;
     var date2unixtime = this.date2unixtime;
     var fromunixtime = this.fromunixtime;
+    var parseISO8601 = this.parseISO8601;
     var init_alarms_edit = this.init_alarms_edit;
 
 
@@ -122,6 +123,15 @@ function rcube_calendar_ui(settings)
       return d;
     };
 
+    // fix date if jumped over a DST change
+    var fix_date = function(date)
+    {
+      if (date.getHours() == 23)
+        date.setTime(date.getTime() + HOUR_MS);
+      else if (date.getHours() > 0)
+        date.setHours(0);
+    };
+
     // turn the given date into an ISO 8601 date string understandable by PHPs strtotime()
     var date2servertime = function(date)
     {
@@ -129,6 +139,11 @@ function rcube_calendar_ui(settings)
           + 'T'+zeropad(date.getHours())+':'+zeropad(date.getMinutes())+':'+zeropad(date.getSeconds());
     }
 
+    var date2timestring = function(date, dateonly)
+    {
+      return date2servertime(date).replace(/[^0-9]/g, '').substr(0, (dateonly ? 8 : 14));
+    }
+
     var zeropad = function(num)
     {
         return (num < 10 ? '0' : '') + num;
@@ -469,7 +484,7 @@ function rcube_calendar_ui(settings)
         recurrence = $('#edit-recurrence-frequency').val(event.recurrence ? event.recurrence.FREQ : '').change();
         interval = $('#eventedit select.edit-recurrence-interval').val(event.recurrence ? event.recurrence.INTERVAL : 1);
         rrtimes = $('#edit-recurrence-repeat-times').val(event.recurrence ? event.recurrence.COUNT : 1);
-        rrenddate = $('#edit-recurrence-enddate').val(event.recurrence && event.recurrence.UNTIL ? $.fullCalendar.formatDate($.fullCalendar.parseISO8601(event.recurrence.UNTIL), settings['date_format']) : '');
+        rrenddate = $('#edit-recurrence-enddate').val(event.recurrence && event.recurrence.UNTIL ? $.fullCalendar.formatDate(parseISO8601(event.recurrence.UNTIL), settings['date_format']) : '');
         $('#eventedit input.edit-recurrence-until:checked').prop('checked', false);
       
         var weekdays = ['SU','MO','TU','WE','TH','FR','SA'];
@@ -894,10 +909,13 @@ function rcube_calendar_ui(settings)
     {
       if (delta) {
         freebusy_ui.start.setTime(freebusy_ui.start.getTime() + DAY_MS * delta);
+        fix_date(freebusy_ui.start);
+        
         // skip weekends if in workinhoursonly-mode
         if (Math.abs(delta) == 1 && freebusy_ui.workinhoursonly) {
           while (is_weekend(freebusy_ui.start))
             freebusy_ui.start.setTime(freebusy_ui.start.getTime() + DAY_MS * delta);
+          fix_date(freebusy_ui.start);
         }
         
         freebusy_ui.end = new Date(freebusy_ui.start.getTime() + DAY_MS * freebusy_ui.numdays);
@@ -966,7 +984,7 @@ function rcube_calendar_ui(settings)
       
       // if we have loaded free-busy data, show it
       if (!freebusy_ui.loading) {
-        if (date2unixtime(freebusy_ui.start) < freebusy_data.start || date2unixtime(freebusy_ui.end) > freebusy_data.end || freebusy_ui.interval != freebusy_data.interval) {
+        if (freebusy_ui.start < freebusy_data.start || freebusy_ui.end > freebusy_data.end || freebusy_ui.interval != freebusy_data.interval) {
           load_freebusy_data(freebusy_ui.start, freebusy_ui.interval);
         }
         else {
@@ -1070,12 +1088,13 @@ function rcube_calendar_ui(settings)
     // fetch free-busy information for each attendee from server
     var load_freebusy_data = function(from, interval)
     {
-      var start = new Date(from.getTime() - DAY_MS * 2);  // start 1 days before event
+      var start = new Date(from.getTime() - DAY_MS * 2);  // start 2 days before event
+      fix_date(start);
       var end = new Date(start.getTime() + DAY_MS * Math.max(14, freebusy_ui.numdays + 7));   // load min. 14 days
       freebusy_ui.numrequired = 0;
       freebusy_data.all = [];
       freebusy_data.required = [];
-      
+
       // load free-busy information for every attendee
       var domid, email;
       for (var i=0; i < event_attendees.length; i++) {
@@ -1088,7 +1107,7 @@ function rcube_calendar_ui(settings)
             type: 'GET',
             dataType: 'json',
             url: rcmail.url('freebusy-times'),
-            data: { email:email, start:date2unixtime(clone_date(start, 1)), end:date2unixtime(clone_date(end, 2)), interval:interval, _remote:1 },
+            data: { email:email, start:date2servertime(clone_date(start, 1)), end:date2servertime(clone_date(end, 2)), interval:interval, _remote:1 },
             success: function(data) {
               freebusy_ui.loading--;
               
@@ -1102,11 +1121,11 @@ function rcube_calendar_ui(settings)
               }
               
               // copy data to member var
-              var req = attendee.role != 'OPT-PARTICIPANT';
-              var ts = data.start - 0;
-              freebusy_data.start = ts;
+              var ts, req = attendee.role != 'OPT-PARTICIPANT';
+              freebusy_data.start = parseISO8601(data.start);
               freebusy_data[data.email] = {};
               for (var i=0; i < data.slots.length; i++) {
+                ts = data.times[i] + '';
                 freebusy_data[data.email][ts] = data.slots[i];
                 
                 // set totals
@@ -1118,10 +1137,8 @@ function rcube_calendar_ui(settings)
                 if (!freebusy_data.all[ts])
                   freebusy_data.all[ts] = [0,0,0,0];
                 freebusy_data.all[ts][data.slots[i]]++;
-                
-                ts += data.interval * 60;
               }
-              freebusy_data.end = ts;
+              freebusy_data.end = parseISO8601(data.end);
               freebusy_data.interval = data.interval;
 
               // hide loading indicator
@@ -1178,13 +1195,18 @@ function rcube_calendar_ui(settings)
       var domid = String(email).replace(rcmail.identifier_expr, '');
       var row = $('#fbrow' + domid);
       var rowall = $('#fbrowall').children();
-      var ts = date2unixtime(freebusy_ui.start);
-      var fbdata = freebusy_data[email];
-      
+      var dateonly = freebusy_ui.interval > 60,
+        t, ts = date2timestring(freebusy_ui.start, dateonly),
+        curdate = new Date(),
+        fbdata = freebusy_data[email];
+
       if (fbdata && fbdata[ts] !== undefined && row.length) {
+        t = freebusy_ui.start.getTime();
         row.children().each(function(i, cell){
+          curdate.setTime(t);
+          ts = date2timestring(curdate, dateonly);
           cell.className = cell.className.replace('unknown', fbdata[ts] ? status_classes[fbdata[ts]] : 'unknown');
-          
+
           // also update total row if all data was loaded
           if (freebusy_ui.loading == 0 && freebusy_data.all[ts] && (cell = rowall.get(i))) {
             var workinghours = cell.className.indexOf('workinghours') >= 0;
@@ -1200,7 +1222,7 @@ function rcube_calendar_ui(settings)
             cell.className = (workinghours ? 'workinghours ' : 'offhours ') + req_status +  ' all-' + all_status;
           }
           
-          ts += freebusy_ui.interval * 60;
+          t += freebusy_ui.interval * 60000;
         });
       }
     };
@@ -1208,9 +1230,12 @@ function rcube_calendar_ui(settings)
     // write changed event date/times back to form fields
     var update_freebusy_dates = function(start, end)
     {
+      // fix all-day evebt times
       if (me.selected_event.allDay) {
         start.setHours(12);
         start.setMinutes(0);
+        if (end.getHours() == 0)
+          end.setHours(-1);
         end.setHours(13);
         end.setMinutes(0);
       }
@@ -1227,13 +1252,13 @@ function rcube_calendar_ui(settings)
     var freebusy_find_slot = function(dir)
     {
       var event = me.selected_event,
-        eventstart = date2unixtime(event.start),  // calculate with unixtimes
-        eventend = date2unixtime(event.end),
+        eventstart = event.start.getTime(),  // calculate with integers
+        eventend = event.end.getTime(),
         duration = eventend - eventstart,
-        sinterval = freebusy_data.interval * 60,
+        sinterval = freebusy_data.interval * 60000,
         intvlslots = 1,
         numslots = Math.ceil(duration / sinterval),
-        checkdate, slotend, email, curdate;
+        checkdate, slotend, email, ts, slot, slotdate = new Date(), slotenddate = new Date();
 
       // shift event times to next possible slot
       eventstart += sinterval * intvlslots * dir;
@@ -1241,27 +1266,32 @@ function rcube_calendar_ui(settings)
 
       // iterate through free-busy slots and find candidates
       var candidatecount = 0, candidatestart = candidateend = success = false;
-      for (var slot = dir > 0 ? freebusy_data.start : freebusy_data.end - sinterval; (dir > 0 && slot < freebusy_data.end) || (dir < 0 && slot >= freebusy_data.start); slot += sinterval * dir) {
+      for (slot = dir > 0 ? freebusy_data.start.getTime() : freebusy_data.end.getTime() - sinterval;
+            (dir > 0 && slot < freebusy_data.end.getTime()) || (dir < 0 && slot >= freebusy_data.start.getTime());
+            slot += sinterval * dir) {
         slotend = slot + sinterval;
+        slotdate.setTime(slot);
+        slotenddate.setTime(slotend);
+
         if ((dir > 0 && slotend <= eventstart) || (dir < 0 && slot >= eventend))  // skip
           continue;
-        
+
         // respect workingours setting
         if (freebusy_ui.workinhoursonly) {
-          curdate = fromunixtime(dir > 0 || !candidateend ? slot : (candidateend - duration));
-          if (is_weekend(curdate) || (freebusy_data.interval <= 60 && !is_workinghour(curdate))) {  // skip off-hours
+          if (is_weekend(slotdate) || (freebusy_data.interval <= 60 && !is_workinghour(slotdate))) {  // skip off-hours
             candidatestart = candidateend = false;
             candidatecount = 0;
             continue;
           }
         }
-        
+
         if (!candidatestart)
           candidatestart = slot;
-        
+
         // check freebusy data for all attendees
+        ts = date2timestring(slotdate, freebusy_data.interval > 60);
         for (var i=0; i < event_attendees.length; i++) {
-          if (freebusy_ui.attendees[i].role != 'OPT-PARTICIPANT' && (email = freebusy_ui.attendees[i].email) && freebusy_data[email] && freebusy_data[email][slot] > 1) {
+          if (freebusy_ui.attendees[i].role != 'OPT-PARTICIPANT' && (email = freebusy_ui.attendees[i].email) && freebusy_data[email] && freebusy_data[email][ts] > 1) {
             candidatestart = candidateend = false;
             break;
           }
@@ -1282,12 +1312,12 @@ function rcube_calendar_ui(settings)
         // if candidate is big enough, this is it!
         if (candidatecount == numslots) {
           if (dir > 0) {
-            event.start = fromunixtime(candidatestart);
-            event.end = fromunixtime(candidatestart + duration);
+            event.start.setTime(candidatestart);
+            event.end.setTime(candidatestart + duration);
           }
           else {
-            event.end = fromunixtime(candidateend);
-            event.start = fromunixtime(candidateend - duration);
+            event.end.setTime(candidateend);
+            event.start.setTime(candidateend - duration);
           }
           success = true;
           break;
@@ -1457,7 +1487,7 @@ function rcube_calendar_ui(settings)
         type: 'GET',
         dataType: 'html',
         url: rcmail.url('freebusy-status'),
-        data: { email:email, start:date2unixtime(clone_date(event.start, event.allDay?1:0)), end:date2unixtime(clone_date(event.end, event.allDay?2:0)), _remote: 1 },
+        data: { email:email, start:date2servertime(clone_date(event.start, event.allDay?1:0)), end:date2servertime(clone_date(event.end, event.allDay?2:0)), _remote: 1 },
         success: function(status){
           icon.removeClass('loading').addClass(String(status).toLowerCase());
         },
diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js
index 35897d7..b2ae597 100644
--- a/plugins/libcalendaring/libcalendaring.js
+++ b/plugins/libcalendaring/libcalendaring.js
@@ -110,7 +110,7 @@ function rcube_libcalendaring(settings)
      * Convert an ISO 8601 formatted date string from the server into a Date object.
      * Timezone information will be ignored, the server already provides dates in user's timezone.
      */
-    function parseISO8601(s)
+    this.parseISO8601 = function(s)
     {
         // force d to be on check's YMD, for daylight savings purposes
         var fixDate = function(d, check) {
@@ -319,8 +319,8 @@ function rcube_libcalendaring(settings)
         var actions, adismiss, asnooze, alarm, html, event_ids = [];
         for (var i=0; i < alarms.length; i++) {
             alarm = alarms[i];
-            alarm.start = parseISO8601(alarm.start);
-            alarm.end = parseISO8601(alarm.end);
+            alarm.start = this.parseISO8601(alarm.start);
+            alarm.end = this.parseISO8601(alarm.end);
             event_ids.push(alarm.id);
 
             html = '<h3 class="event-title">' + Q(alarm.title) + '</h3>';





More information about the commits mailing list