Improve free/busy UI according to inputs from Georg
This commit is contained in:
parent
8b8142db53
commit
322f649d77
8 changed files with 99 additions and 7 deletions
|
@ -1395,8 +1395,8 @@ class calendar extends rcube_plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// let this information be cached for 15min
|
// let this information be cached for 5min
|
||||||
send_future_expire_header(900);
|
send_future_expire_header(300);
|
||||||
|
|
||||||
echo $status;
|
echo $status;
|
||||||
exit;
|
exit;
|
||||||
|
@ -1441,6 +1441,9 @@ class calendar extends rcube_plugin
|
||||||
$t = $t_end;
|
$t = $t_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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' => intval($start), 'end' => intval($t_end), 'interval' => $interval, 'slots' => $slots));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -673,7 +673,7 @@ function rcube_calendar_ui(settings)
|
||||||
fb_start.setHours(0); fb_start.setMinutes(0); fb_start.setSeconds(0); fb_start.setMilliseconds(0);
|
fb_start.setHours(0); fb_start.setMinutes(0); fb_start.setSeconds(0); fb_start.setMilliseconds(0);
|
||||||
fb_end.setTime(fb_start.getTime() + DAY_MS);
|
fb_end.setTime(fb_start.getTime() + DAY_MS);
|
||||||
|
|
||||||
freebusy_data = {};
|
freebusy_data = { required:{}, all:{} };
|
||||||
freebusy_ui.loading = 1; // prevent render_freebusy_grid() to load data yet
|
freebusy_ui.loading = 1; // prevent render_freebusy_grid() to load data yet
|
||||||
freebusy_ui.numdays = allday.checked ? 7 : Math.ceil(duration * 2 / 86400);
|
freebusy_ui.numdays = allday.checked ? 7 : Math.ceil(duration * 2 / 86400);
|
||||||
freebusy_ui.interval = allday.checked ? 360 : 60;
|
freebusy_ui.interval = allday.checked ? 360 : 60;
|
||||||
|
@ -690,6 +690,10 @@ function rcube_calendar_ui(settings)
|
||||||
list_html += '<div class="attendee ' + String(data.role).toLowerCase() + '" id="rcmli' + domid + '">' + dispname + '</div>';
|
list_html += '<div class="attendee ' + String(data.role).toLowerCase() + '" id="rcmli' + domid + '">' + dispname + '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add total row
|
||||||
|
list_html += '<div class="attendee spacer"> </div>';
|
||||||
|
list_html += '<div class="attendee total">' + rcmail.gettext('reqallattendees','calendar') + '</div>';
|
||||||
|
|
||||||
$('#schedule-attendees-list').html(list_html);
|
$('#schedule-attendees-list').html(list_html);
|
||||||
|
|
||||||
// enable/disable buttons
|
// enable/disable buttons
|
||||||
|
@ -781,6 +785,10 @@ function rcube_calendar_ui(settings)
|
||||||
times_html += '<tr id="fbrow' + domid + '">' + slots_row + '</tr>';
|
times_html += '<tr id="fbrow' + domid + '">' + slots_row + '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add line for all/required attendees
|
||||||
|
times_html += '<tr class="spacer"><td colspan="' + (dayslots * freebusy_ui.numdays) + '"> </td>';
|
||||||
|
times_html += '<tr id="fbrowall">' + slots_row + '</tr>';
|
||||||
|
|
||||||
var table = $('#schedule-freebusy-times');
|
var table = $('#schedule-freebusy-times');
|
||||||
table.children('thead').html(dates_row + times_row);
|
table.children('thead').html(dates_row + times_row);
|
||||||
table.children('tbody').html(times_html);
|
table.children('tbody').html(times_html);
|
||||||
|
@ -905,9 +913,10 @@ function rcube_calendar_ui(settings)
|
||||||
{
|
{
|
||||||
var start = new Date(from.getTime() - DAY_MS * 2); // start 1 days before event
|
var start = new Date(from.getTime() - DAY_MS * 2); // start 1 days before event
|
||||||
var end = new Date(start.getTime() + DAY_MS * 14); // load 14 days
|
var end = new Date(start.getTime() + DAY_MS * 14); // load 14 days
|
||||||
|
freebusy_ui.numrequired = 0;
|
||||||
|
|
||||||
// load free-busy information for every attendee
|
// load free-busy information for every attendee
|
||||||
var domid, email
|
var domid, email;
|
||||||
for (var i=0; i < event_attendees.length; i++) {
|
for (var i=0; i < event_attendees.length; i++) {
|
||||||
if ((email = event_attendees[i].email)) {
|
if ((email = event_attendees[i].email)) {
|
||||||
domid = String(email).replace(rcmail.identifier_expr, '');
|
domid = String(email).replace(rcmail.identifier_expr, '');
|
||||||
|
@ -918,16 +927,37 @@ function rcube_calendar_ui(settings)
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
url: rcmail.url('freebusy-times'),
|
url: rcmail.url('freebusy-times'),
|
||||||
data: { email:email, start:date2unixtime(start), end:date2unixtime(end), interval:interval, _remote: 1 },
|
data: { email:email, start:date2unixtime(start), end:date2unixtime(end), interval:interval, _remote:1 },
|
||||||
success: function(data){
|
success: function(data) {
|
||||||
freebusy_ui.loading--;
|
freebusy_ui.loading--;
|
||||||
|
|
||||||
|
// find attendee
|
||||||
|
var attendee = null;
|
||||||
|
for (var i=0; i < event_attendees.length; i++) {
|
||||||
|
if (event_attendees[i].email == data.email) {
|
||||||
|
attendee = event_attendees[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// copy data to member var
|
// copy data to member var
|
||||||
|
var req = attendee.role != 'OPT-PARTICIPANT';
|
||||||
var ts = data.start - 0;
|
var ts = data.start - 0;
|
||||||
freebusy_data.start = ts;
|
freebusy_data.start = ts;
|
||||||
freebusy_data[data.email] = {};
|
freebusy_data[data.email] = {};
|
||||||
for (var i=0; i < data.slots.length; i++) {
|
for (var i=0; i < data.slots.length; i++) {
|
||||||
freebusy_data[data.email][ts] = data.slots[i];
|
freebusy_data[data.email][ts] = data.slots[i];
|
||||||
|
|
||||||
|
// set totals
|
||||||
|
if (!freebusy_data.required[ts])
|
||||||
|
freebusy_data.required[ts] = [0,0,0,0];
|
||||||
|
if (req)
|
||||||
|
freebusy_data.required[ts][data.slots[i]]++;
|
||||||
|
|
||||||
|
if (!freebusy_data.all[ts])
|
||||||
|
freebusy_data.all[ts] = [0,0,0,0];
|
||||||
|
freebusy_data.all[ts][data.slots[i]]++;
|
||||||
|
|
||||||
ts += data.interval * 60;
|
ts += data.interval * 60;
|
||||||
}
|
}
|
||||||
freebusy_data.end = ts;
|
freebusy_data.end = ts;
|
||||||
|
@ -941,6 +971,10 @@ function rcube_calendar_ui(settings)
|
||||||
update_freebusy_display(data.email);
|
update_freebusy_display(data.email);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// count required attendees
|
||||||
|
if (event_attendees[i].role != 'OPT-PARTICIPANT')
|
||||||
|
freebusy_ui.numrequired++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -951,12 +985,28 @@ function rcube_calendar_ui(settings)
|
||||||
var status_classes = ['unknown','free','busy','tentative','out-of-office'];
|
var status_classes = ['unknown','free','busy','tentative','out-of-office'];
|
||||||
var domid = String(email).replace(rcmail.identifier_expr, '');
|
var domid = String(email).replace(rcmail.identifier_expr, '');
|
||||||
var row = $('#fbrow' + domid);
|
var row = $('#fbrow' + domid);
|
||||||
|
var rowall = $('#fbrowall').children();
|
||||||
var ts = date2unixtime(freebusy_ui.start);
|
var ts = date2unixtime(freebusy_ui.start);
|
||||||
var fbdata = freebusy_data[email];
|
var fbdata = freebusy_data[email];
|
||||||
|
|
||||||
if (fbdata && fbdata[ts] && row.length) {
|
if (fbdata && fbdata[ts] && row.length) {
|
||||||
row.children().each(function(i, cell){
|
row.children().each(function(i, cell){
|
||||||
cell.className = cell.className.replace('unknown', fbdata[ts] ? status_classes[fbdata[ts]] : 'unknown');
|
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 all_status = freebusy_data.all[ts][2] ? 'busy' : 'unknown';
|
||||||
|
req_status = freebusy_data.required[ts][2] ? 'busy' : 'free';
|
||||||
|
for (var j=0; j < status_classes.length; j++) {
|
||||||
|
if (freebusy_ui.numrequired && freebusy_data.required[ts][j] >= freebusy_ui.numrequired)
|
||||||
|
req_status = status_classes[j];
|
||||||
|
if (freebusy_data.all[ts][j] == event_attendees.length)
|
||||||
|
all_status = status_classes[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.className = cell.className.replace('unknown', req_status + ' all-' + all_status);
|
||||||
|
}
|
||||||
|
|
||||||
ts += freebusy_ui.interval * 60;
|
ts += freebusy_ui.interval * 60;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -806,6 +806,10 @@ class kolab_driver extends calendar_driver
|
||||||
if (($fbstart = $fb->getStart()) && $start < $fbstart) {
|
if (($fbstart = $fb->getStart()) && $start < $fbstart) {
|
||||||
array_unshift($result, array($start, $fbstart, calendar::FREEBUSY_UNKNOWN));
|
array_unshift($result, array($start, $fbstart, calendar::FREEBUSY_UNKNOWN));
|
||||||
}
|
}
|
||||||
|
// pad period till $end with status 'unknown'
|
||||||
|
if (($fbend = $fb->getEnd()) && $fbend < $end) {
|
||||||
|
$result[] = array($fbend, $end, calendar::FREEBUSY_UNKNOWN);
|
||||||
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ $labels['scheduletime'] = 'Find availability';
|
||||||
$labels['sendinvitations'] = 'Send invitations';
|
$labels['sendinvitations'] = 'Send invitations';
|
||||||
$labels['sendnotifications'] = 'Notify attendees about modifications';
|
$labels['sendnotifications'] = 'Notify attendees about modifications';
|
||||||
$labels['onlyworkinghours'] = 'Find availability within my working hours';
|
$labels['onlyworkinghours'] = 'Find availability within my working hours';
|
||||||
|
$labels['reqallattendees'] = 'Required/all participants';
|
||||||
$labels['prevslot'] = 'Previous Slot';
|
$labels['prevslot'] = 'Previous Slot';
|
||||||
$labels['nextslot'] = 'Next Slot';
|
$labels['nextslot'] = 'Next Slot';
|
||||||
$labels['noslotfound'] = 'Unable to find a free time slot';
|
$labels['noslotfound'] = 'Unable to find a free time slot';
|
||||||
|
|
|
@ -602,6 +602,22 @@ td.topalign {
|
||||||
background: #f0b400;
|
background: #f0b400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#schedule-freebusy-times td.all-busy,
|
||||||
|
#schedule-freebusy-times td.all-tentative,
|
||||||
|
#schedule-freebusy-times td.all-out-of-office {
|
||||||
|
background-image: url('images/freebusy-colors.png');
|
||||||
|
background-position: top right;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#schedule-freebusy-times td.all-tentative {
|
||||||
|
background-position: right -40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#schedule-freebusy-times td.all-out-of-office {
|
||||||
|
background-position: right -80px;
|
||||||
|
}
|
||||||
|
|
||||||
#edit-attendees-legend {
|
#edit-attendees-legend {
|
||||||
margin-top: 3em;
|
margin-top: 3em;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
@ -704,6 +720,18 @@ td.topalign {
|
||||||
background: url('images/loading-small.gif') 1px 50% no-repeat;
|
background: url('images/loading-small.gif') 1px 50% no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.attendees-list .total {
|
||||||
|
background: none;
|
||||||
|
padding-left: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attendees-list .spacer,
|
||||||
|
#schedule-freebusy-times tr.spacer td {
|
||||||
|
background: 0;
|
||||||
|
font-size: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
#schedule-freebusy-times {
|
#schedule-freebusy-times {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,3 +52,9 @@ html #calendartoolbar a.buttonPas {
|
||||||
#edit-attendees-form #edit-attendee-schedule {
|
#edit-attendees-form #edit-attendee-schedule {
|
||||||
right: 0.6em;
|
right: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#schedule-freebusy-times td.all-busy,
|
||||||
|
#schedule-freebusy-times td.all-tentative,
|
||||||
|
#schedule-freebusy-times td.all-out-of-office {
|
||||||
|
background-image: url('images/freebusy-colors.gif');
|
||||||
|
}
|
||||||
|
|
BIN
plugins/calendar/skins/default/images/freebusy-colors.gif
Normal file
BIN
plugins/calendar/skins/default/images/freebusy-colors.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 408 B |
BIN
plugins/calendar/skins/default/images/freebusy-colors.png
Normal file
BIN
plugins/calendar/skins/default/images/freebusy-colors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 631 B |
Loading…
Add table
Reference in a new issue