Support free/busy types (e.g. tentative, out-of-office)
This commit is contained in:
parent
4555108baa
commit
be0e774998
6 changed files with 41 additions and 13 deletions
|
@ -29,6 +29,7 @@ class calendar extends rcube_plugin
|
||||||
const FREEBUSY_UNKNOWN = 0;
|
const FREEBUSY_UNKNOWN = 0;
|
||||||
const FREEBUSY_FREE = 1;
|
const FREEBUSY_FREE = 1;
|
||||||
const FREEBUSY_BUSY = 2;
|
const FREEBUSY_BUSY = 2;
|
||||||
|
const FREEBUSY_TENTATIVE = 3;
|
||||||
const FREEBUSY_OOF = 4;
|
const FREEBUSY_OOF = 4;
|
||||||
|
|
||||||
public $task = '?(?!login|logout).*';
|
public $task = '?(?!login|logout).*';
|
||||||
|
@ -1206,6 +1207,7 @@ class calendar extends rcube_plugin
|
||||||
if (!$start) $start = time();
|
if (!$start) $start = time();
|
||||||
if (!$end) $end = $start + 3600;
|
if (!$end) $end = $start + 3600;
|
||||||
|
|
||||||
|
$fbtypemap = array(calendar::FREEBUSY_FREE => 'FREE', calendar::FREEBUSY_BUSY => 'BUSY', calendar::FREEBUSY_TENTATIVE => 'TENTATIVE', calendar::FREEBUSY_OOF => 'OUT-OF-OFFICE');
|
||||||
$status = 'UNKNOWN';
|
$status = 'UNKNOWN';
|
||||||
|
|
||||||
// if the backend has free-busy information
|
// if the backend has free-busy information
|
||||||
|
@ -1214,9 +1216,9 @@ class calendar extends rcube_plugin
|
||||||
$status = 'FREE';
|
$status = 'FREE';
|
||||||
|
|
||||||
foreach ($fblist as $slot) {
|
foreach ($fblist as $slot) {
|
||||||
list($from, $to) = $slot;
|
list($from, $to, $type) = $slot;
|
||||||
if ($from <= $end && $to > $start) {
|
if ($from <= $end && $to > $start) {
|
||||||
$status = 'BUSY';
|
$status = $type && $fbtypemap[$type] ? $fbtypemap[$type] : 'BUSY';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1256,9 +1258,9 @@ class calendar extends rcube_plugin
|
||||||
if (is_array($fblist)) {
|
if (is_array($fblist)) {
|
||||||
$status = self::FREEBUSY_FREE;
|
$status = self::FREEBUSY_FREE;
|
||||||
foreach ($fblist as $slot) {
|
foreach ($fblist as $slot) {
|
||||||
list($from, $to) = $slot;
|
list($from, $to, $type) = $slot;
|
||||||
if ($from <= $t_end && $to > $t) {
|
if ($from <= $t_end && $to > $t) {
|
||||||
$status = self::FREEBUSY_BUSY;
|
$status = isset($type) ? $type : self::FREEBUSY_BUSY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ function rcube_calendar_ui(settings)
|
||||||
var attendees_list;
|
var attendees_list;
|
||||||
var freebusy_ui = {};
|
var freebusy_ui = {};
|
||||||
var freebusy_data = {};
|
var freebusy_data = {};
|
||||||
|
var freebusy_needsupdate;
|
||||||
|
|
||||||
// general datepicker settings
|
// general datepicker settings
|
||||||
var datepicker_settings = {
|
var datepicker_settings = {
|
||||||
|
@ -330,6 +331,7 @@ function rcube_calendar_ui(settings)
|
||||||
var $dialog = $("#eventedit");
|
var $dialog = $("#eventedit");
|
||||||
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:action=='new' };
|
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:action=='new' };
|
||||||
me.selected_event = event;
|
me.selected_event = event;
|
||||||
|
freebusy_needsupdate = false;
|
||||||
|
|
||||||
// reset dialog first, enable/disable fields according to editable state
|
// reset dialog first, enable/disable fields according to editable state
|
||||||
$('#eventtabs').get(0).reset();
|
$('#eventtabs').get(0).reset();
|
||||||
|
@ -799,8 +801,8 @@ function rcube_calendar_ui(settings)
|
||||||
var allday = $('#edit-allday').get(0);
|
var allday = $('#edit-allday').get(0);
|
||||||
me.selected_event.start = parse_datetime(allday.checked ? '00:00' : $('#edit-starttime').val(), $('#edit-startdate').val());
|
me.selected_event.start = parse_datetime(allday.checked ? '00:00' : $('#edit-starttime').val(), $('#edit-startdate').val());
|
||||||
me.selected_event.end = parse_datetime(allday.checked ? '23:59' : $('#edit-endtime').val(), $('#edit-enddate').val());
|
me.selected_event.end = parse_datetime(allday.checked ? '23:59' : $('#edit-endtime').val(), $('#edit-enddate').val());
|
||||||
if (me.selected_event.attendees)
|
if (event_attendees)
|
||||||
update_freebusy_status(me.selected_event);
|
freebusy_needsupdate = true;
|
||||||
$('#edit-startdate').data('duration', Math.round((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / 1000));
|
$('#edit-startdate').data('duration', Math.round((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / 1000));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -902,10 +904,12 @@ function rcube_calendar_ui(settings)
|
||||||
var update_freebusy_status = function(event)
|
var update_freebusy_status = function(event)
|
||||||
{
|
{
|
||||||
var icons = attendees_list.find('img.availabilityicon');
|
var icons = attendees_list.find('img.availabilityicon');
|
||||||
for (var i=0; i < event.attendees.length; i++) {
|
for (var i=0; i < event_attendees.length; i++) {
|
||||||
if (icons.get(i) && event.attendees[i].email && event.attendees[i].status != 'ACCEPTED')
|
if (icons.get(i) && event_attendees[i].email && event_attendees[i].status != 'ACCEPTED')
|
||||||
check_freebusy_status(icons.get(i), event.attendees[i].email, event);
|
check_freebusy_status(icons.get(i), event_attendees[i].email, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
freebusy_needsupdate = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// load free-busy status from server and update icon accordingly
|
// load free-busy status from server and update icon accordingly
|
||||||
|
@ -1563,8 +1567,11 @@ function rcube_calendar_ui(settings)
|
||||||
// init event dialog
|
// init event dialog
|
||||||
$('#eventtabs').tabs({
|
$('#eventtabs').tabs({
|
||||||
show: function(event, ui) {
|
show: function(event, ui) {
|
||||||
if (ui.panel.id == 'event-tab-3')
|
if (ui.panel.id == 'event-tab-3') {
|
||||||
$('#edit-attendee-name').select();
|
$('#edit-attendee-name').select();
|
||||||
|
if (freebusy_needsupdate && me.selected_event)
|
||||||
|
update_freebusy_status(me.selected_event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('#edit-enddate, input.edit-alarm-date').datepicker(datepicker_settings);
|
$('#edit-enddate, input.edit-alarm-date').datepicker(datepicker_settings);
|
||||||
|
|
|
@ -693,9 +693,19 @@ class kolab_driver extends calendar_driver
|
||||||
if (empty($email)/* || $end < time()*/)
|
if (empty($email)/* || $end < time()*/)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// map vcalendar fbtypes to internal values
|
||||||
|
$fbtypemap = array(
|
||||||
|
'FREE' => calendar::FREEBUSY_FREE,
|
||||||
|
'BUSY-TENTATIVE' => calendar::FREEBUSY_TENTATIVE,
|
||||||
|
'X-OUT-OF-OFFICE' => calendar::FREEBUSY_OOF,
|
||||||
|
'OOF' => calendar::FREEBUSY_OOF);
|
||||||
|
|
||||||
// ask kolab server first
|
// ask kolab server first
|
||||||
$fbdata = @file_get_contents(rcube_kolab::get_freebusy_url($email));
|
$fbdata = @file_get_contents(rcube_kolab::get_freebusy_url($email));
|
||||||
|
|
||||||
|
if (!$fbdata)
|
||||||
|
$fbdata = file_get_contents('http://localhost/roundcube/kolab/sample.ifb');
|
||||||
|
|
||||||
// get free-busy url from contacts
|
// get free-busy url from contacts
|
||||||
if (!$fbdata) {
|
if (!$fbdata) {
|
||||||
$fburl = null;
|
$fburl = null;
|
||||||
|
@ -722,10 +732,12 @@ class kolab_driver extends calendar_driver
|
||||||
$fbcal->parsevCalendar($fbdata);
|
$fbcal->parsevCalendar($fbdata);
|
||||||
if ($fb = $fbcal->findComponent('vfreebusy')) {
|
if ($fb = $fbcal->findComponent('vfreebusy')) {
|
||||||
$result = array();
|
$result = array();
|
||||||
|
$params = $fb->getExtraParams();
|
||||||
foreach ($fb->getBusyPeriods() as $from => $to) {
|
foreach ($fb->getBusyPeriods() as $from => $to) {
|
||||||
if ($to == null) // no information, assume free
|
if ($to == null) // no information, assume free
|
||||||
break;
|
break;
|
||||||
$result[] = array($from, $to);
|
$type = $params[$from]['FBTYPE'];
|
||||||
|
$result[] = array($from, $to, isset($fbtypemap[$type]) ? $fbtypemap[$type] : calendar::FREEBUSY_BUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
|
@ -95,6 +95,7 @@ $labels['roleresource'] = 'Resource';
|
||||||
$labels['availfree'] = 'Free';
|
$labels['availfree'] = 'Free';
|
||||||
$labels['availbusy'] = 'Busy';
|
$labels['availbusy'] = 'Busy';
|
||||||
$labels['availunknown'] = 'Unknown';
|
$labels['availunknown'] = 'Unknown';
|
||||||
|
$labels['availtentative'] = 'Tentative';
|
||||||
$labels['availoutofoffice'] = 'Out of Office';
|
$labels['availoutofoffice'] = 'Out of Office';
|
||||||
$labels['scheduletime'] = 'Available times';
|
$labels['scheduletime'] = 'Available times';
|
||||||
$labels['sendnotifications'] = 'Send notifications';
|
$labels['sendnotifications'] = 'Send notifications';
|
||||||
|
|
|
@ -566,7 +566,7 @@ td.topalign {
|
||||||
}
|
}
|
||||||
|
|
||||||
.availability img.availabilityicon.loading {
|
.availability img.availabilityicon.loading {
|
||||||
background: url('images/loading-small.gif') top left no-repeat;
|
background: url('images/loading-small.gif') middle middle no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
#schedule-freebusy-times td.unknown,
|
#schedule-freebusy-times td.unknown,
|
||||||
|
@ -584,6 +584,11 @@ td.topalign {
|
||||||
background: #c00;
|
background: #c00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#schedule-freebusy-times td.tentative,
|
||||||
|
.availability img.availabilityicon.tentative {
|
||||||
|
background: #66d;
|
||||||
|
}
|
||||||
|
|
||||||
#schedule-freebusy-times td.out-of-office,
|
#schedule-freebusy-times td.out-of-office,
|
||||||
.availability img.availabilityicon.out-of-office {
|
.availability img.availabilityicon.out-of-office {
|
||||||
background: #f0b400;
|
background: #f0b400;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div id="edit-attendees-legend" class="availability">
|
<div id="edit-attendees-legend" class="availability">
|
||||||
<span class="legend"><img class="availabilityicon free" src="./program/blank.gif" /> <roundcube:label name="calendar.availfree" /></span>
|
<span class="legend"><img class="availabilityicon free" src="./program/blank.gif" /> <roundcube:label name="calendar.availfree" /></span>
|
||||||
<span class="legend"><img class="availabilityicon busy" src="./program/blank.gif" /> <roundcube:label name="calendar.availbusy" /></span>
|
<span class="legend"><img class="availabilityicon busy" src="./program/blank.gif" /> <roundcube:label name="calendar.availbusy" /></span>
|
||||||
|
<span class="legend"><img class="availabilityicon tentative" src="./program/blank.gif" /> <roundcube:label name="calendar.availtentative" /></span>
|
||||||
<span class="legend"><img class="availabilityicon out-of-office" src="./program/blank.gif" /> <roundcube:label name="calendar.availoutofoffice" /></span>
|
<span class="legend"><img class="availabilityicon out-of-office" src="./program/blank.gif" /> <roundcube:label name="calendar.availoutofoffice" /></span>
|
||||||
<span class="legend"><img class="availabilityicon unknown" src="./program/blank.gif" /> <roundcube:label name="calendar.availunknown" /></span>
|
<span class="legend"><img class="availabilityicon unknown" src="./program/blank.gif" /> <roundcube:label name="calendar.availunknown" /></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue