').attr(attr));
+
+ // also update total row if all data was loaded
+ if (!freebusy_ui.loading && freebusy_data.all[ts] && all_cell) {
+ var all_status = freebusy_data.all[ts][2] ? 'busy' : 'unknown',
+ req_status = freebusy_data.required[ts][2] ? 'busy' : 'free';
+
+ for (j=1; 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];
+ }
+
+ attr['class'] = req_status + ' all-' + all_status;
+
+ // these elements use some specific styling, so we want to minimize their number
+ if (last && last.attr('class') == attr['class'])
+ last.css('width', (percent + parseFloat(last.css('width').replace('%', ''))).toFixed(2) + '%');
+ else {
+ last = $('
').attr(attr);
+ all_slots.push(last);
+ }
}
-
- cell.className = (workinghours ? 'workinghours ' : 'offhours ') + req_status + ' all-' + all_status;
+
+ t += freebusy_ui.interval * 60000;
}
-
- t += freebusy_ui.interval * 60000;
+
+ $(cell).html('').append(slots);
+ if (all_slots.length)
+ $(all_cell).html('').append(all_slots);
});
}
};
@@ -1716,17 +1718,20 @@ function rcube_calendar_ui(settings)
sinterval = freebusy_data.interval * 60000,
intvlslots = 1,
numslots = Math.ceil(duration / sinterval),
- checkdate, slotend, email, ts, slot, slotdate = new Date();
+ fb_start = freebusy_data.start.getTime(),
+ fb_end = freebusy_data.end.getTime(),
+ checkdate, slotend, email, ts, slot, slotdate = new Date(),
+ candidatecount = 0, candidatestart = false, success = false;
// shift event times to next possible slot
eventstart += sinterval * intvlslots * dir;
eventend += sinterval * intvlslots * dir;
// iterate through free-busy slots and find candidates
- var candidatecount = 0, candidatestart = candidateend = success = false;
- 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) {
+ for (slot = dir > 0 ? fb_start : fb_end - sinterval;
+ (dir > 0 && slot < fb_end) || (dir < 0 && slot >= fb_start);
+ slot += sinterval * dir
+ ) {
slotdate.setTime(slot);
// fix slot if just crossed a DST change
if (event.allDay) {
@@ -1738,10 +1743,10 @@ function rcube_calendar_ui(settings)
if ((dir > 0 && slotend <= eventstart) || (dir < 0 && slot >= eventend)) // skip
continue;
- // respect workingours setting
+ // respect workinghours setting
if (freebusy_ui.workinhoursonly) {
if (is_weekend(slotdate) || (freebusy_data.interval <= 60 && !is_workinghour(slotdate))) { // skip off-hours
- candidatestart = candidateend = false;
+ candidatestart = false;
candidatecount = 0;
continue;
}
@@ -1750,11 +1755,12 @@ function rcube_calendar_ui(settings)
if (!candidatestart)
candidatestart = slot;
- // check freebusy data for all attendees
ts = date2timestring(slotdate, freebusy_data.interval > 60);
+
+ // check freebusy data for all attendees
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][ts] > 1) {
- candidatestart = candidateend = false;
+ candidatestart = false;
break;
}
}
@@ -1765,22 +1771,15 @@ function rcube_calendar_ui(settings)
candidatecount = 0;
continue;
}
+ else if (dir < 0)
+ candidatestart = slot;
- // set candidate end to slot end time
candidatecount++;
- if (dir < 0 && !candidateend)
- candidateend = slotend;
// if candidate is big enough, this is it!
if (candidatecount == numslots) {
- if (dir > 0) {
- event.start.setTime(candidatestart);
- event.end.setTime(candidatestart + duration);
- }
- else {
- event.end.setTime(candidateend);
- event.start.setTime(candidateend - duration);
- }
+ event.start.setTime(candidatestart);
+ event.end.setTime(candidatestart + duration);
success = true;
break;
}
@@ -1810,7 +1809,6 @@ function rcube_calendar_ui(settings)
}
};
-
// update event properties and attendees availability if event times have changed
var event_times_changed = function()
{
@@ -1825,7 +1823,6 @@ function rcube_calendar_ui(settings)
}
};
-
// add the given list of participants
var add_attendees = function(names, params)
{
@@ -1914,9 +1911,9 @@ function rcube_calendar_ui(settings)
+ (!data.noreply && settings.itip_notify & 1 ? 'checked="checked" ' : '') + '/>';
if (data['delegated-to'])
- tooltip = rcmail.gettext('delegatedto', 'calendar') + data['delegated-to'];
+ tooltip = rcmail.gettext('libcalendaring.delegatedto') + ' ' + data['delegated-to'];
else if (data['delegated-from'])
- tooltip = rcmail.gettext('delegatedfrom', 'calendar') + data['delegated-from'];
+ tooltip = rcmail.gettext('libcalendaring.delegatedfrom') + ' ' + data['delegated-from'];
else if (status)
tooltip = status_label;
@@ -2512,25 +2509,15 @@ function rcube_calendar_ui(settings)
if (!data) data = event;
var decline = false, notify = false, html = '', cal = me.calendars[event.calendar],
- _has_attendees = has_attendees(event), _is_organizer = is_organizer(event);
+ _has_attendees = me.has_attendees(event),
+ _is_attendee = _has_attendees && me.is_attendee(event),
+ _is_organizer = me.is_organizer(event);
// event has attendees, ask whether to notify them
if (_has_attendees) {
var checked = (settings.itip_notify & 1 ? ' checked="checked"' : '');
- if (_is_organizer) {
- notify = true;
- if (settings.itip_notify & 2) {
- html += '
' +
- '
';
- }
- else {
- data._notify = settings.itip_notify;
- }
- }
- else if (action == 'remove' && is_attendee(event)) {
+ if (action == 'remove' && cal.group != 'shared' && !_is_organizer && _is_attendee) {
decline = true;
checked = event.status != 'CANCELLED' ? checked : '';
html += '
' +
@@ -2538,8 +2525,17 @@ function rcube_calendar_ui(settings)
rcmail.gettext('itipdeclineevent', 'calendar') +
'
';
}
- else {
- html += '
' + rcmail.gettext('localchangeswarning', 'calendar') + '
';
+ else if (_is_organizer) {
+ notify = true;
+ if (settings.itip_notify & 2) {
+ html += '
' +
+ '
';
+ }
+ else {
+ data._notify = settings.itip_notify;
+ }
}
}
@@ -2549,7 +2545,7 @@ function rcube_calendar_ui(settings)
// disable the 'future' savemode if I'm an attendee
// reason: no calendaring system supports the thisandfuture range parameter in iTip REPLY
- if (action == 'remove' && _has_attendees && !_is_organizer && is_attendee(event)) {
+ if (action == 'remove' && !_is_organizer && _is_attendee) {
future_disabled = ' disabled';
}
@@ -3149,28 +3145,6 @@ function rcube_calendar_ui(settings)
}
};
- // display the edit dialog, request 'new' action and pass the selected event
- this.event_copy = function(event) {
- if (event && event.id) {
- var copy = $.extend(true, {}, event);
-
- delete copy.id;
- delete copy._id;
- delete copy.created;
- delete copy.changed;
- delete copy.recurrence_id;
- delete copy.attachments; // @TODO
-
- $.each(copy.attendees, function (k, v) {
- if (v.role != 'ORGANIZER') {
- v.status = 'NEEDS-ACTION';
- }
- })
-
- event_edit_dialog('new', copy);
- }
- };
-
// show URL of the given calendar in a dialog box
this.showurl = function(calendar)
{
@@ -3490,13 +3464,6 @@ function rcube_calendar_ui(settings)
this.fisheye_view(this.fisheye_date);
};
- // resize and reposition (center) the dialog window
- this.dialog_resize = function(id, height, width)
- {
- var win = $(window), w = win.width(), h = win.height();
- $(id).dialog('option', { height: Math.min(h-20, height+130), width: Math.min(w-20, width+50) });
- };
-
// adjust calendar view size
this.view_resize = function()
{
@@ -3514,6 +3481,8 @@ function rcube_calendar_ui(settings)
rcmail.triggerEvent('selectfolder', { folder:id, prefix:'rcmlical' });
this.selected_calendar = id;
+
+ rcmail.update_state({source: id});
};
// register the given calendar to the current view
@@ -3552,7 +3521,7 @@ function rcube_calendar_ui(settings)
// insert to #calendar-select options if writeable
select = $('#edit-calendar');
- if (fc && has_permission(cal, 'i') && select.length && !select.find('option[value="'+id+'"]').length) {
+ if (fc && me.has_permission(cal, 'i') && select.length && !select.find('option[value="'+id+'"]').length) {
$('
diff --git a/skins/larry/calendar.css b/skins/larry/calendar.css
index 71b2575..2383f65 100644
--- a/skins/larry/calendar.css
+++ b/skins/larry/calendar.css
@@ -115,6 +115,7 @@ body.calendarmain #mainscreen {
width: 6px;
top: 40px !important;
bottom: 0;
+ height: auto;
background: url(images/toggle.gif) -1px 48% no-repeat transparent;
}
@@ -453,8 +454,7 @@ pre {
#calendars .searchresults .boxtitle {
background: none;
- padding: 2px 8px;
- border-radius: 0;
+ padding: 2px 8px 2px 8px;
}
#calendars .searchresults .listing li {
@@ -539,7 +539,6 @@ body.calendarmain #searchmenulink {
width: 15px;
}
-#eventedit.uidialog,
.calendarmain div.uidialog {
display: none;
}
@@ -642,7 +641,7 @@ a.miniColors-trigger {
border-top: 2px solid #fafafa;
}
-#edit-attachments-form .buttons {
+#edit-attachments-form .formbuttons {
margin: 0.5em 0;
}
@@ -683,7 +682,7 @@ a.miniColors-trigger {
}
.event-attendees span.attendee {
- padding: 1px 18px 1px 0;
+ padding-right: 18px;
margin-right: 0.5em;
background: url(images/attendee-status.png) right 0 no-repeat;
}
@@ -1139,7 +1138,7 @@ td.topalign {
#eventedit .edit-attendees-table th.invite,
#eventedit .edit-attendees-table td.invite {
- width: 50px;
+ width: 44px;
padding: 2px;
}
@@ -1239,51 +1238,50 @@ td.topalign {
height: 14px;
border-radius: 4px;
-moz-border-radius: 4px;
- vertical-align: middle;
}
.availability img.availabilityicon.loading {
background: url(images/loading_blue.gif) center no-repeat;
}
-#schedule-freebusy-times td.unknown,
+#schedule-freebusy-times td div.unknown,
.availability img.availabilityicon.unknown {
background: #ddd;
}
-#schedule-freebusy-times td.free,
+#schedule-freebusy-times td div.free,
.availability img.availabilityicon.free {
background: #abd640;
}
-#schedule-freebusy-times td.busy,
+#schedule-freebusy-times td div.busy,
.availability img.availabilityicon.busy {
background: #e26569;
}
-#schedule-freebusy-times td.tentative,
+#schedule-freebusy-times td div.tentative,
.availability img.availabilityicon.tentative {
background: #8383fc;
}
-#schedule-freebusy-times td.out-of-office,
+#schedule-freebusy-times td div.out-of-office,
.availability img.availabilityicon.out-of-office {
background: #fbaa68;
}
-#schedule-freebusy-times td.all-busy,
-#schedule-freebusy-times td.all-tentative,
-#schedule-freebusy-times td.all-out-of-office {
+#schedule-freebusy-times td div.all-busy,
+#schedule-freebusy-times td div.all-tentative,
+#schedule-freebusy-times td div.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 {
+#schedule-freebusy-times td div.all-tentative {
background-position: right -40px;
}
-#schedule-freebusy-times td.all-out-of-office {
+#schedule-freebusy-times td div.all-out-of-office {
background-position: right -80px;
}
@@ -1297,6 +1295,10 @@ td.topalign {
white-space: nowrap;
}
+#edit-attendees-legend img.availabilityicon {
+ vertical-align: middle;
+}
+
.edit-attendees-table tbody td.confirmstate {
overflow: hidden;
white-space: nowrap;
@@ -1310,27 +1312,22 @@ td.topalign {
}
.edit-attendees-table td.confirmstate span.needs-action {
- height: 14px;
}
.edit-attendees-table td.confirmstate span.accepted {
background-position: 5px -20px;
- height: 14px;
}
.edit-attendees-table td.confirmstate span.declined {
background-position: 5px -40px;
- height: 14px;
}
.edit-attendees-table td.confirmstate span.tentative {
background-position: 5px -60px;
- height: 14px;
}
.edit-attendees-table td.confirmstate span.delegated {
background-position: 5px -180px;
- height: 14px;
}
#attendees-freebusy-table {
@@ -1411,7 +1408,8 @@ td.topalign {
.attendees-list .spacer,
#schedule-freebusy-times tr.spacer td {
background: 0;
- font-size: 50%;
+ padding: 0;
+ height: 10px;
}
#schedule-freebusy-times {
@@ -1424,6 +1422,15 @@ td.topalign {
border: 1px solid #ccc;
}
+#schedule-freebusy-times tbody td {
+ padding: 0;
+ height: 20px;
+}
+
+#schedule-freebusy-times tbody td div {
+ height: 100%;
+}
+
#attendees-freebusy-table div.timesheader,
#schedule-freebusy-times tr.times td {
min-width: 30px;
@@ -1441,6 +1448,10 @@ td.topalign {
cursor: pointer;
}
+#schedule-freebusy-times #fbrowall td {
+ border-bottom: none;
+}
+
#schedule-event-time {
position: absolute;
border: 2px solid #333;
@@ -2207,6 +2218,11 @@ div.calendar-invitebox td em {
font-weight: bold;
}
+div.calendar-invitebox td.date.modified {
+ font-weight: bold;
+ color: red;
+}
+
#event-rsvp .rsvp-buttons,
div.calendar-invitebox .itip-buttons div {
margin-top: 0.5em;
diff --git a/skins/larry/templates/calendar.html b/skins/larry/templates/calendar.html
index adb291c..fe3593b 100644
--- a/skins/larry/templates/calendar.html
+++ b/skins/larry/templates/calendar.html
@@ -164,7 +164,6 @@