From dd5f8e56bde546a392086e142bea0756da34f0fe Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sat, 23 Jul 2011 17:08:31 +0200 Subject: [PATCH] Display current event time over free/busy grid --- plugins/calendar/calendar_ui.js | 95 +++++++++++++++++---- plugins/calendar/lib/calendar_ui.php | 5 +- plugins/calendar/skins/default/calendar.css | 16 +++- plugins/calendar/skins/default/iehacks.css | 9 ++ 4 files changed, 103 insertions(+), 22 deletions(-) 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