diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index b691d31c..ed0318e4 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -330,7 +330,7 @@ function rcube_calendar_ui(settings)
var $dialog = $("#eventedit");
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:action=='new' };
- me.selected_event = event;
+ me.selected_event = $.extend({}, event); // clone event object
freebusy_needsupdate = false;
// reset dialog first, enable/disable fields according to editable state
@@ -635,7 +635,7 @@ function rcube_calendar_ui(settings)
fb_end.setTime(fb_start.getTime() + 86400000);
freebusy_data = {};
- freebusy_ui.loading = 1; // prevent render_freebusy_grid() to load data
+ freebusy_ui.loading = 1; // prevent render_freebusy_grid() to load data yet
freebusy_ui.numdays = allday.checked ? 7 : 1;
freebusy_ui.interval = allday.checked ? 360 : 60;
freebusy_ui.start = fb_start;
@@ -673,6 +673,14 @@ function rcube_calendar_ui(settings)
width: 850
}).show();
+ // adjust dialog size to fit grid without scrolling
+ var gridw = $('#schedule-freebusy-times').width();
+ var overflow = gridw - $('#attendees-freebusy-table td.times').width() + 1;
+ if (overflow > 0) {
+ $dialog.dialog('option', 'width', Math.min((window.innerWidth || document.documentElement.clientWidth) - 40, 850 + overflow));
+ $dialog.dialog('option', 'position', ['center', 'center']);
+ }
+
// fetch data from server
freebusy_ui.loading = 0;
load_freebusy_data(freebusy_ui.start, freebusy_ui.interval);
@@ -714,21 +722,72 @@ function rcube_calendar_ui(settings)
times_html += '
' + slots_row + '
';
}
- $('#schedule-freebusy-times > thead').html(dates_row + times_row);
- $('#schedule-freebusy-times > tbody').html(times_html);
+ var table = $('#schedule-freebusy-times');
+ table.children('thead').html(dates_row + times_row);
+ table.children('tbody').html(times_html);
// 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) {
- load_freebusy_data(freebusy_ui.start, freebusy_ui.interval)
- return;
+ load_freebusy_data(freebusy_ui.start, freebusy_ui.interval);
}
-
- for (var email, i=0; i < event_attendees.length; i++) {
- if ((email = event_attendees[i].email))
- update_freebusy_display(email);
+ else {
+ for (var email, i=0; i < event_attendees.length; i++) {
+ if ((email = event_attendees[i].email))
+ update_freebusy_display(email);
+ }
}
}
+
+ // render current event date/time selection over grid table
+ // use timeout to let the dom attributes (width/height/offset) be set first
+ window.setTimeout(function(){ render_freebusy_overlay(); }, 10);
+ };
+
+ // render overlay element over the grid to visiualize the current event date/time
+ var render_freebusy_overlay = function()
+ {
+ var overlay = $('#schedule-event-time');
+ if (me.selected_event.end.getTime() < freebusy_ui.start.getTime() || me.selected_event.start.getTime() > freebusy_ui.end.getTime()) {
+ overlay.hide();
+ }
+ else {
+ var table = $('#schedule-freebusy-times'),
+ width = 0,
+ pos = { top:table.children('thead').height(), left:0 },
+ eventstart = Math.floor(me.selected_event.start.getTime() / 1000),
+ eventend = Math.floor(me.selected_event.end.getTime() / 1000),
+ slotstart = Math.floor(freebusy_ui.start.getTime() / 1000),
+ slotsize = freebusy_ui.interval * 60,
+ slotend, fraction, $cell;
+
+ // iterate through slots to determine position and size of the overlay
+ table.children('thead').find('td').each(function(i, cell){
+ slotend = slotstart + slotsize - 60;
+ // event starts in this slot: compute left
+ if (eventstart >= slotstart && eventstart <= slotend) {
+ fraction = 1 - (slotend - eventstart) / slotsize;
+ pos.left = Math.round(cell.offsetLeft + cell.offsetWidth * fraction);
+ }
+ // event ends in this slot: compute width
+ else if (eventend >= slotstart && eventend <= slotend) {
+ fraction = 1 - (slotend - eventend) / slotsize;
+ width = Math.round(cell.offsetLeft + cell.offsetWidth * fraction) - pos.left;
+ }
+
+ slotstart = slotstart + slotsize;
+ });
+
+ if (!width)
+ width = table.width() - pos.left;
+
+ // overlay is visible
+ if (width > 0)
+ overlay.css({ width: (width-5)+'px', height:(table.children('tbody').height() - 4)+'px', left:pos.left+'px', top:pos.top+'px' }).show();
+ else
+ overlay.hide();
+ }
+
};
// fetch free-busy information for each attendee from server
@@ -1376,8 +1435,10 @@ function rcube_calendar_ui(settings)
// callback for clicks in all-day box
dayClick: function(date, allDay, e, view) {
var now = new Date().getTime();
- if (now - day_clicked_ts < 400 && day_clicked == date.getTime()) // emulate double-click on day
- return event_edit_dialog('new', { start:date, end:date, allDay:allDay, calendar:me.selected_calendar });
+ if (now - day_clicked_ts < 400 && day_clicked == date.getTime()) { // emulate double-click on day
+ var enddate = new Date(); enddate.setTime(date.getTime() + 86400000 - 60000);
+ return event_edit_dialog('new', { start:date, end:enddate, allDay:allDay, calendar:me.selected_calendar });
+ }
if (!ignore_click) {
view.calendar.gotoDate(date);
@@ -1577,7 +1638,7 @@ function rcube_calendar_ui(settings)
$('#edit-enddate, input.edit-alarm-date').datepicker(datepicker_settings);
$('#edit-startdate').datepicker(datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); });
$('#edit-enddate').datepicker('option', 'onSelect', event_times_changed).change(event_times_changed);
- $('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); });
+ $('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); event_times_changed(); });
// configure drop-down menu on time input fields based on jquery UI autocomplete
$('#edit-starttime, #edit-endtime, input.edit-alarm-time')
@@ -1637,13 +1698,13 @@ function rcube_calendar_ui(settings)
event_freebusy_dialog();
});
- $('#shedule-freebusy-prev').button().click(function(){ render_freebusy_grid(-1); });
- $('#shedule-freebusy-next').button().click(function(){ render_freebusy_grid(1); }).parent().buttonset();
-
+ $('#shedule-freebusy-prev').html(bw.ie6 ? '<<' : '◄').button().click(function(){ render_freebusy_grid(-1); });
+ $('#shedule-freebusy-next').html(bw.ie6 ? '>>' : '►').button().click(function(){ render_freebusy_grid(1); }).parent().buttonset();
+
$('#schedule-freebusy-wokinghours').click(function(){
$('#workinghourscss').remove();
if (this.checked)
- $('').appendTo('head');
+ $('').appendTo('head');
});
// add proprietary css styles if not IE
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 7e44af93..74e1228c 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -594,7 +594,10 @@ class calendar_ui
html::div(array('id' => 'schedule-attendees-list'), '')
);
$table->add('times',
- html::div('scroll', html::tag('table', array('id' => 'schedule-freebusy-times', 'border' => 0, 'cellspacing' => 0), html::tag('thead') . html::tag('tbody')))
+ html::div('scroll',
+ html::tag('table', array('id' => 'schedule-freebusy-times', 'border' => 0, 'cellspacing' => 0), html::tag('thead') . html::tag('tbody')) .
+ html::div(array('id' => 'schedule-event-time', 'style' => 'display:none'), ' ')
+ )
);
return $table->show($attrib);
diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css
index 308b002f..aeb8a9ec 100644
--- a/plugins/calendar/skins/default/calendar.css
+++ b/plugins/calendar/skins/default/calendar.css
@@ -36,6 +36,7 @@ body.calendarmain {
#datepicker .ui-datepicker {
width: 97% !important;
+ box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
}
@@ -656,6 +657,7 @@ td.topalign {
}
#attendees-freebusy-table div.scroll {
+ position: relative;
overflow: auto;
}
@@ -665,10 +667,6 @@ td.topalign {
border-color: #ccc;
}
-#attendees-freebusy-table div.timesheader {
- padding: 0.3em;
-}
-
#schedule-attendees-list div.attendee {
padding: 3px 20px 3px 6px;
border-top: 1px solid #ccc;
@@ -693,6 +691,7 @@ td.topalign {
border-width: 0 1px 0 1px;
}
+#attendees-freebusy-table div.timesheader,
#schedule-freebusy-times tr.times td {
min-width: 30px;
font-size: 9px;
@@ -700,6 +699,15 @@ td.topalign {
text-align: center;
}
+#schedule-event-time {
+ position: absolute;
+ border: 2px solid #333;
+ background: #777;
+ background: rgba(60, 60, 60, 0.6);
+ opacity: 0.5;
+ border-radius: 4px;
+}
+
#eventfreebusy .schedule-options {
position: relative;
margin-bottom: 2em;
diff --git a/plugins/calendar/skins/default/iehacks.css b/plugins/calendar/skins/default/iehacks.css
index fa282176..31f82d78 100644
--- a/plugins/calendar/skins/default/iehacks.css
+++ b/plugins/calendar/skins/default/iehacks.css
@@ -43,3 +43,12 @@ html #calendartoolbar a.buttonPas {
.fc-header-title h2 {
font-size: 16px;
}
+
+#schedule-event-time {
+ filter: alpha(opacity=40);
+}
+
+#eventfreebusy .schedule-buttons,
+#edit-attendees-form #edit-attendee-schedule {
+ right: 0.6em;
+}
\ No newline at end of file