Merge branch 'master' of ssh://git.kolabsys.com/git/roundcube
This commit is contained in:
commit
b2a873008a
8 changed files with 259 additions and 36 deletions
|
@ -52,6 +52,8 @@ class calendar extends rcube_plugin
|
||||||
'calendar_timeslots' => 2,
|
'calendar_timeslots' => 2,
|
||||||
'calendar_first_day' => 1,
|
'calendar_first_day' => 1,
|
||||||
'calendar_first_hour' => 6,
|
'calendar_first_hour' => 6,
|
||||||
|
'calendar_work_start' => 6,
|
||||||
|
'calendar_work_end' => 18,
|
||||||
);
|
);
|
||||||
|
|
||||||
private $default_categories = array(
|
private $default_categories = array(
|
||||||
|
@ -627,6 +629,8 @@ class calendar extends rcube_plugin
|
||||||
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']);
|
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']);
|
||||||
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
|
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
|
||||||
$settings['first_hour'] = (int)$this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']);
|
$settings['first_hour'] = (int)$this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']);
|
||||||
|
$settings['work_start'] = (int)$this->rc->config->get('calendar_work_start', $this->defaults['calendar_work_start']);
|
||||||
|
$settings['work_end'] = (int)$this->rc->config->get('calendar_work_end', $this->defaults['calendar_work_end']);
|
||||||
$settings['timezone'] = $this->timezone;
|
$settings['timezone'] = $this->timezone;
|
||||||
|
|
||||||
// localization
|
// localization
|
||||||
|
|
|
@ -42,9 +42,10 @@ function rcube_calendar_ui(settings)
|
||||||
var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0);
|
var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0);
|
||||||
var day_clicked = day_clicked_ts = 0;
|
var day_clicked = day_clicked_ts = 0;
|
||||||
var ignore_click = false;
|
var ignore_click = false;
|
||||||
|
var event_defaults = { free_busy:'busy' };
|
||||||
var event_attendees = null;
|
var event_attendees = null;
|
||||||
var attendees_list;
|
var attendees_list;
|
||||||
var freebusy_ui = {};
|
var freebusy_ui = { workinhoursonly:false };
|
||||||
var freebusy_data = {};
|
var freebusy_data = {};
|
||||||
var freebusy_needsupdate;
|
var freebusy_needsupdate;
|
||||||
|
|
||||||
|
@ -330,7 +331,8 @@ 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 = $.extend({}, event); // clone event object
|
me.selected_event = $.extend(event_defaults, event); // clone event object (with defaults)
|
||||||
|
event = me.selected_event; // change reference to clone
|
||||||
freebusy_needsupdate = false;
|
freebusy_needsupdate = false;
|
||||||
|
|
||||||
// reset dialog first, enable/disable fields according to editable state
|
// reset dialog first, enable/disable fields according to editable state
|
||||||
|
@ -616,27 +618,34 @@ function rcube_calendar_ui(settings)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// set form elements
|
// set form elements
|
||||||
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000);
|
|
||||||
var startdate = $('#schedule-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration);
|
|
||||||
var starttime = $('#schedule-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show();
|
|
||||||
var enddate = $('#schedule-enddate').val($.fullCalendar.formatDate(event.end, settings['date_format']));
|
|
||||||
var endtime = $('#schedule-endtime').val($.fullCalendar.formatDate(event.end, settings['time_format'])).show();
|
|
||||||
var allday = $('#edit-allday').get(0);
|
var allday = $('#edit-allday').get(0);
|
||||||
|
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000);
|
||||||
|
freebusy_ui.startdate = $('#schedule-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration);
|
||||||
|
freebusy_ui.starttime = $('#schedule-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show();
|
||||||
|
freebusy_ui.enddate = $('#schedule-enddate').val($.fullCalendar.formatDate(event.end, settings['date_format']));
|
||||||
|
freebusy_ui.endtime = $('#schedule-endtime').val($.fullCalendar.formatDate(event.end, settings['time_format'])).show();
|
||||||
|
|
||||||
if (allday.checked) {
|
if (allday.checked) {
|
||||||
starttime.val("00:00").hide();
|
starttime.val("00:00").hide();
|
||||||
endtime.val("23:59").hide();
|
endtime.val("23:59").hide();
|
||||||
|
event.allDay = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read attendee roles from drop-downs
|
||||||
|
$('select.edit-attendee-role').each(function(i, elem){
|
||||||
|
if (event_attendees[i])
|
||||||
|
event_attendees[i].role = $(elem).val();
|
||||||
|
});
|
||||||
|
|
||||||
// render time slots
|
// render time slots
|
||||||
var now = new Date(), fb_start = new Date(), fb_end = new Date();
|
var now = new Date(), fb_start = new Date(), fb_end = new Date();
|
||||||
fb_start.setTime(Math.max(now, event.start));
|
fb_start.setTime(event.start);
|
||||||
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() + 86400000);
|
fb_end.setTime(fb_start.getTime() + 86400000);
|
||||||
|
|
||||||
freebusy_data = {};
|
freebusy_data = {};
|
||||||
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 : 1;
|
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;
|
||||||
freebusy_ui.start = fb_start;
|
freebusy_ui.start = fb_start;
|
||||||
freebusy_ui.end = new Date(freebusy_ui.start.getTime() + 86400000 * freebusy_ui.numdays);
|
freebusy_ui.end = new Date(freebusy_ui.start.getTime() + 86400000 * freebusy_ui.numdays);
|
||||||
|
@ -653,9 +662,23 @@ function rcube_calendar_ui(settings)
|
||||||
|
|
||||||
$('#schedule-attendees-list').html(list_html);
|
$('#schedule-attendees-list').html(list_html);
|
||||||
|
|
||||||
|
// enable/disable buttons
|
||||||
|
$('#shedule-find-prev').button('option', 'disabled', (fb_start.getTime() < now.getTime()));
|
||||||
|
|
||||||
// dialog buttons
|
// dialog buttons
|
||||||
var buttons = {};
|
var buttons = {};
|
||||||
|
|
||||||
|
buttons[rcmail.gettext('adobt', 'calendar')] = function() {
|
||||||
|
$('#edit-startdate').val(freebusy_ui.startdate.val());
|
||||||
|
$('#edit-starttime').val(freebusy_ui.starttime.val());
|
||||||
|
$('#edit-enddate').val(freebusy_ui.enddate.val());
|
||||||
|
$('#edit-endtime').val(freebusy_ui.endtime.val());
|
||||||
|
if (freebusy_needsupdate)
|
||||||
|
update_freebusy_status(me.selected_event);
|
||||||
|
freebusy_needsupdate = false;
|
||||||
|
$dialog.dialog("close");
|
||||||
|
};
|
||||||
|
|
||||||
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
|
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
|
||||||
$dialog.dialog("close");
|
$dialog.dialog("close");
|
||||||
};
|
};
|
||||||
|
@ -666,6 +689,8 @@ function rcube_calendar_ui(settings)
|
||||||
closeOnEscape: true,
|
closeOnEscape: true,
|
||||||
title: rcmail.gettext('scheduletime', 'calendar'),
|
title: rcmail.gettext('scheduletime', 'calendar'),
|
||||||
close: function() {
|
close: function() {
|
||||||
|
if (bw.ie6)
|
||||||
|
$("#edit-attendees-table").css('visibility','visible');
|
||||||
$dialog.dialog("destroy").hide();
|
$dialog.dialog("destroy").hide();
|
||||||
},
|
},
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
|
@ -673,6 +698,10 @@ function rcube_calendar_ui(settings)
|
||||||
width: 850
|
width: 850
|
||||||
}).show();
|
}).show();
|
||||||
|
|
||||||
|
// hide edit dialog on IE6 because of drop-down elements
|
||||||
|
if (bw.ie6)
|
||||||
|
$("#edit-attendees-table").css('visibility','hidden');
|
||||||
|
|
||||||
// adjust dialog size to fit grid without scrolling
|
// adjust dialog size to fit grid without scrolling
|
||||||
var gridw = $('#schedule-freebusy-times').width();
|
var gridw = $('#schedule-freebusy-times').width();
|
||||||
var overflow = gridw - $('#attendees-freebusy-table td.times').width() + 1;
|
var overflow = gridw - $('#attendees-freebusy-table td.times').width() + 1;
|
||||||
|
@ -704,8 +733,8 @@ function rcube_calendar_ui(settings)
|
||||||
lastdate = datestr;
|
lastdate = datestr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: define working hours by config
|
// set css class according to working hours
|
||||||
css = (freebusy_ui.numdays == 1 && (curdate.getHours() < 6 || curdate.getHours() > 18)) ? 'offhours' : 'workinghours';
|
css = (freebusy_ui.numdays == 1 && (curdate.getHours() < settings['work_start'] || curdate.getHours() > settings['work_end'])) ? 'offhours' : 'workinghours';
|
||||||
times_row += '<td class="' + css + '">' + Q($.fullCalendar.formatDate(curdate, settings['time_format'])) + '</td>';
|
times_row += '<td class="' + css + '">' + Q($.fullCalendar.formatDate(curdate, settings['time_format'])) + '</td>';
|
||||||
slots_row += '<td class="' + css + ' unknown"> </td>';
|
slots_row += '<td class="' + css + ' unknown"> </td>';
|
||||||
|
|
||||||
|
@ -749,15 +778,15 @@ function rcube_calendar_ui(settings)
|
||||||
{
|
{
|
||||||
var overlay = $('#schedule-event-time');
|
var overlay = $('#schedule-event-time');
|
||||||
if (me.selected_event.end.getTime() < freebusy_ui.start.getTime() || me.selected_event.start.getTime() > freebusy_ui.end.getTime()) {
|
if (me.selected_event.end.getTime() < freebusy_ui.start.getTime() || me.selected_event.start.getTime() > freebusy_ui.end.getTime()) {
|
||||||
overlay.hide();
|
overlay.draggable('disable').hide();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var table = $('#schedule-freebusy-times'),
|
var table = $('#schedule-freebusy-times'),
|
||||||
width = 0,
|
width = 0,
|
||||||
pos = { top:table.children('thead').height(), left:0 },
|
pos = { top:table.children('thead').height(), left:0 },
|
||||||
eventstart = Math.floor(me.selected_event.start.getTime() / 1000),
|
eventstart = date2unixtime(me.selected_event.start),
|
||||||
eventend = Math.floor(me.selected_event.end.getTime() / 1000),
|
eventend = date2unixtime(me.selected_event.end),
|
||||||
slotstart = Math.floor(freebusy_ui.start.getTime() / 1000),
|
slotstart = date2unixtime(freebusy_ui.start),
|
||||||
slotsize = freebusy_ui.interval * 60,
|
slotsize = freebusy_ui.interval * 60,
|
||||||
slotend, fraction, $cell;
|
slotend, fraction, $cell;
|
||||||
|
|
||||||
|
@ -782,14 +811,38 @@ function rcube_calendar_ui(settings)
|
||||||
width = table.width() - pos.left;
|
width = table.width() - pos.left;
|
||||||
|
|
||||||
// overlay is visible
|
// overlay is visible
|
||||||
if (width > 0)
|
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();
|
overlay.css({ width: (width-5)+'px', height:(table.children('tbody').height() - 4)+'px', left:pos.left+'px', top:pos.top+'px' }).draggable('enable').show();
|
||||||
|
|
||||||
|
// configure draggable
|
||||||
|
if (!overlay.data('isdraggable')) {
|
||||||
|
overlay.draggable({
|
||||||
|
axis: 'x',
|
||||||
|
scroll: true,
|
||||||
|
stop: function(e, ui){
|
||||||
|
// convert pixels to time
|
||||||
|
var px = ui.position.left;
|
||||||
|
var range_p = $('#schedule-freebusy-times').width();
|
||||||
|
var range_t = freebusy_ui.end.getTime() - freebusy_ui.start.getTime();
|
||||||
|
var newstart = new Date(freebusy_ui.start.getTime() + px * (range_t / range_p));
|
||||||
|
newstart.setSeconds(0); newstart.setMilliseconds(0);
|
||||||
|
// round to 5 minutes
|
||||||
|
var round = newstart.getMinutes() % 5;
|
||||||
|
if (round > 2.5) newstart.setTime(newstart.getTime() + (5 - round) * 60000);
|
||||||
|
else if (round > 0) newstart.setTime(newstart.getTime() - round * 60000);
|
||||||
|
// update event times
|
||||||
|
update_freebusy_dates(newstart, new Date(newstart.getTime() + freebusy_ui.startdate.data('duration') * 1000));
|
||||||
|
}
|
||||||
|
}).data('isdraggable', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
overlay.hide();
|
overlay.draggable('disable').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// fetch free-busy information for each attendee from server
|
// fetch free-busy information for each attendee from server
|
||||||
var load_freebusy_data = function(from, interval)
|
var load_freebusy_data = function(from, interval)
|
||||||
{
|
{
|
||||||
|
@ -852,12 +905,116 @@ function rcube_calendar_ui(settings)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// write changed event date/times back to form fields
|
||||||
|
var update_freebusy_dates = function(start, end)
|
||||||
|
{
|
||||||
|
me.selected_event.start = start;
|
||||||
|
me.selected_event.end = end;
|
||||||
|
freebusy_ui.startdate.val($.fullCalendar.formatDate(start, settings['date_format']));
|
||||||
|
freebusy_ui.starttime.val($.fullCalendar.formatDate(start, settings['time_format']));
|
||||||
|
freebusy_ui.enddate.val($.fullCalendar.formatDate(end, settings['date_format']));
|
||||||
|
freebusy_ui.endtime.val($.fullCalendar.formatDate(end, settings['time_format']));
|
||||||
|
freebusy_needsupdate = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// attempt to find a time slot where all attemdees are available
|
||||||
|
var freebusy_find_slot = function(dir)
|
||||||
|
{
|
||||||
|
var event = me.selected_event,
|
||||||
|
eventstart = date2unixtime(event.start), // calculate with unitimes
|
||||||
|
eventend = date2unixtime(event.end),
|
||||||
|
duration = eventend - eventstart,
|
||||||
|
sinterval = freebusy_data.interval * 60,
|
||||||
|
intvlslots = event.allDay ? 4 : 1,
|
||||||
|
numslots = Math.ceil(duration / sinterval),
|
||||||
|
checkdate, slotend, email, curdate;
|
||||||
|
|
||||||
|
// 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 (var slot = dir > 0 ? freebusy_data.start : freebusy_data.end - sinterval; (dir > 0 && slot < freebusy_data.end) || (dir < 0 && slot >= freebusy_data.start); slot += sinterval * dir) {
|
||||||
|
slotend = slot + sinterval;
|
||||||
|
if ((dir > 0 && slotend <= eventstart) || (dir < 0 && slot >= eventend)) // skip
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// respect workingours setting
|
||||||
|
if (freebusy_ui.workinhoursonly && freebusy_data.interval <= 60) {
|
||||||
|
curdate = fromunixtime(dir > 0 || !candidateend ? slot : (candidateend - duration));
|
||||||
|
if (curdate.getHours() < settings['work_start'] || curdate.getHours() > settings['work_end']) { // skip off-hours
|
||||||
|
candidatestart = candidateend = false;
|
||||||
|
candidatecount = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!candidatestart)
|
||||||
|
candidatestart = slot;
|
||||||
|
|
||||||
|
// check freebusy data for all attendees
|
||||||
|
for (var i=0; i < event_attendees.length; i++) {
|
||||||
|
if ((email = event_attendees[i].email) && freebusy_data[email][slot] > 1) {
|
||||||
|
candidatestart = candidateend = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// occupied slot
|
||||||
|
if (!candidatestart) {
|
||||||
|
slot += Math.max(0, intvlslots - candidatecount - 1) * sinterval * dir;
|
||||||
|
candidatecount = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = fromunixtime(candidatestart);
|
||||||
|
event.end = fromunixtime(candidatestart + duration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
event.end = fromunixtime(candidateend);
|
||||||
|
event.start = fromunixtime(candidateend - duration);
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update event date/time display
|
||||||
|
if (success) {
|
||||||
|
update_freebusy_dates(event.start, event.end);
|
||||||
|
|
||||||
|
// move freebusy grid if necessary
|
||||||
|
if (event.start.getTime() >= freebusy_ui.end.getTime())
|
||||||
|
render_freebusy_grid(1);
|
||||||
|
else if (event.end.getTime() <= freebusy_ui.start.getTime())
|
||||||
|
render_freebusy_grid(-1);
|
||||||
|
else
|
||||||
|
render_freebusy_overlay();
|
||||||
|
|
||||||
|
var now = new Date();
|
||||||
|
$('#shedule-find-prev').button('option', 'disabled', (event.start.getTime() < now.getTime()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(rcmail.gettext('noslotfound','calendar'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// update event properties and attendees availability if event times have changed
|
// update event properties and attendees availability if event times have changed
|
||||||
var event_times_changed = function()
|
var event_times_changed = function()
|
||||||
{
|
{
|
||||||
if (me.selected_event) {
|
if (me.selected_event) {
|
||||||
var allday = $('#edit-allday').get(0);
|
var allday = $('#edit-allday').get(0);
|
||||||
|
me.selected_event.allDay = allday.checked;
|
||||||
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 (event_attendees)
|
if (event_attendees)
|
||||||
|
@ -1701,7 +1858,11 @@ function rcube_calendar_ui(settings)
|
||||||
$('#shedule-freebusy-prev').html(bw.ie6 ? '<<' : '◄').button().click(function(){ render_freebusy_grid(-1); });
|
$('#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();
|
$('#shedule-freebusy-next').html(bw.ie6 ? '>>' : '►').button().click(function(){ render_freebusy_grid(1); }).parent().buttonset();
|
||||||
|
|
||||||
|
$('#shedule-find-prev').button().click(function(){ freebusy_find_slot(-1); });
|
||||||
|
$('#shedule-find-next').button().click(function(){ freebusy_find_slot(1); });
|
||||||
|
|
||||||
$('#schedule-freebusy-wokinghours').click(function(){
|
$('#schedule-freebusy-wokinghours').click(function(){
|
||||||
|
freebusy_ui.workinhoursonly = this.checked;
|
||||||
$('#workinghourscss').remove();
|
$('#workinghourscss').remove();
|
||||||
if (this.checked)
|
if (this.checked)
|
||||||
$('<style type="text/css" id="workinghourscss"> td.offhours { opacity:0.3; filter:alpha(opacity=30) } </style>').appendTo('head');
|
$('<style type="text/css" id="workinghourscss"> td.offhours { opacity:0.3; filter:alpha(opacity=30) } </style>').appendTo('head');
|
||||||
|
|
|
@ -52,6 +52,12 @@ $rcmail_config['calendar_first_day'] = 1;
|
||||||
// first hour of the calendar (0-23)
|
// first hour of the calendar (0-23)
|
||||||
$rcmail_config['calendar_first_hour'] = 6;
|
$rcmail_config['calendar_first_hour'] = 6;
|
||||||
|
|
||||||
|
// working hours begin
|
||||||
|
$rcmail_config['calendar_work_start'] = 6;
|
||||||
|
|
||||||
|
// working hours end
|
||||||
|
$rcmail_config['calendar_work_end'] = 18;
|
||||||
|
|
||||||
// event categories
|
// event categories
|
||||||
$rcmail_config['calendar_categories'] = array(
|
$rcmail_config['calendar_categories'] = array(
|
||||||
'Personal' => 'c0c0c0',
|
'Personal' => 'c0c0c0',
|
||||||
|
|
|
@ -591,7 +591,7 @@ class calendar_ui
|
||||||
$table->add('attendees',
|
$table->add('attendees',
|
||||||
html::tag('h3', 'boxtitle', $this->calendar->gettext('tabattendees')) .
|
html::tag('h3', 'boxtitle', $this->calendar->gettext('tabattendees')) .
|
||||||
html::div('timesheader', ' ') .
|
html::div('timesheader', ' ') .
|
||||||
html::div(array('id' => 'schedule-attendees-list'), '')
|
html::div(array('id' => 'schedule-attendees-list', 'class' => 'attendees-list'), '')
|
||||||
);
|
);
|
||||||
$table->add('times',
|
$table->add('times',
|
||||||
html::div('scroll',
|
html::div('scroll',
|
||||||
|
|
|
@ -31,6 +31,7 @@ $labels['edit'] = 'Edit';
|
||||||
$labels['save'] = 'Save';
|
$labels['save'] = 'Save';
|
||||||
$labels['remove'] = 'Remove';
|
$labels['remove'] = 'Remove';
|
||||||
$labels['cancel'] = 'Cancel';
|
$labels['cancel'] = 'Cancel';
|
||||||
|
$labels['adobt'] = 'Adopt changes';
|
||||||
$labels['print'] = 'Print calendars';
|
$labels['print'] = 'Print calendars';
|
||||||
$labels['title'] = 'Summary';
|
$labels['title'] = 'Summary';
|
||||||
$labels['description'] = 'Description';
|
$labels['description'] = 'Description';
|
||||||
|
@ -99,7 +100,10 @@ $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';
|
||||||
$labels['onlyworkinghours'] = 'Show only working hours';
|
$labels['onlyworkinghours'] = 'Only working hours';
|
||||||
|
$labels['prevslot'] = 'Previous Slot';
|
||||||
|
$labels['nextslot'] = 'Next Slot';
|
||||||
|
$labels['noslotfound'] = 'Unable to find a free time slot';
|
||||||
|
|
||||||
// event dialog tabs
|
// event dialog tabs
|
||||||
$labels['tabsummary'] = 'Summary';
|
$labels['tabsummary'] = 'Summary';
|
||||||
|
|
|
@ -597,6 +597,7 @@ td.topalign {
|
||||||
|
|
||||||
#edit-attendees-legend {
|
#edit-attendees-legend {
|
||||||
margin-top: 3em;
|
margin-top: 3em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#edit-attendees-legend .legend {
|
#edit-attendees-legend .legend {
|
||||||
|
@ -667,13 +668,33 @@ td.topalign {
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#schedule-attendees-list div.attendee {
|
.attendees-list .attendee {
|
||||||
padding: 3px 20px 3px 6px;
|
padding: 3px 4px 3px 20px;
|
||||||
|
background: url('images/attendee-status.gif') 2px -97px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attendees-list div.attendee {
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#schedule-attendees-list div.loading {
|
.attendees-list span.attendee {
|
||||||
background: url('images/loading-small.gif') top right no-repeat;
|
margin-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attendees-list .organizer {
|
||||||
|
background-position: 3px -77px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attendees-list .opt-participant {
|
||||||
|
background-position: 2px -117px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attendees-list .chair {
|
||||||
|
background-position: 2px -137px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attendees-list .loading {
|
||||||
|
background: url('images/loading-small.gif') 1px 50% no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
#schedule-freebusy-times {
|
#schedule-freebusy-times {
|
||||||
|
@ -706,11 +727,12 @@ td.topalign {
|
||||||
background: rgba(60, 60, 60, 0.6);
|
background: rgba(60, 60, 60, 0.6);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|
||||||
#eventfreebusy .schedule-options {
|
#eventfreebusy .schedule-options {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 2em;
|
margin-bottom: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#eventfreebusy .schedule-buttons {
|
#eventfreebusy .schedule-buttons {
|
||||||
|
@ -719,6 +741,15 @@ td.topalign {
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#eventfreebusy .schedule-find-buttons {
|
||||||
|
padding-bottom:0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#eventfreebusy .schedule-find-buttons button {
|
||||||
|
min-width: 9em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
span.edit-alarm-set {
|
span.edit-alarm-set {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2 KiB |
|
@ -188,13 +188,13 @@
|
||||||
<roundcube:object name="plugin.attendees_freebusy_table" id="attendees-freebusy-table" cellspacing="0" cellpadding="0" border="0" />
|
<roundcube:object name="plugin.attendees_freebusy_table" id="attendees-freebusy-table" cellspacing="0" cellpadding="0" border="0" />
|
||||||
|
|
||||||
<div class="schedule-options">
|
<div class="schedule-options">
|
||||||
<label><input type="checkbox" id="schedule-freebusy-wokinghours" value="1" /><roundcube:label name="calendar.onlyworkinghours" /></label>
|
|
||||||
<div class="schedule-buttons">
|
<div class="schedule-buttons">
|
||||||
<button id="shedule-freebusy-prev" title="<roundcube:label name='previouspage' />">◄</button>
|
<button id="shedule-freebusy-prev" title="<roundcube:label name='previouspage' />">◄</button><button id="shedule-freebusy-next" title="<roundcube:label name='nextpage' />">►</button>
|
||||||
<button id="shedule-freebusy-next" title="<roundcube:label name='nextpage' />">►</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="float:left; width:28em">
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<label for="schedule-startdate"><roundcube:label name="calendar.start" /></label>
|
<label for="schedule-startdate"><roundcube:label name="calendar.start" /></label>
|
||||||
<input type="text" name="startdate" size="10" id="schedule-startdate" disabled="true" />
|
<input type="text" name="startdate" size="10" id="schedule-startdate" disabled="true" />
|
||||||
|
@ -205,8 +205,25 @@
|
||||||
<input type="text" name="enddate" size="10" id="schedule-enddate" disabled="true" />
|
<input type="text" name="enddate" size="10" id="schedule-enddate" disabled="true" />
|
||||||
<input type="text" name="endtime" size="6" id="schedule-endtime" disabled="true" />
|
<input type="text" name="endtime" size="6" id="schedule-endtime" disabled="true" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="float:left">
|
||||||
|
<div class="schedule-find-buttons">
|
||||||
|
<button id="shedule-find-prev">◄ <roundcube:label name="calendar.prevslot" /></button>
|
||||||
|
<button id="shedule-find-next"><roundcube:label name="calendar.nextslot" /> ►</button>
|
||||||
|
</div>
|
||||||
|
<div class="schedule-options">
|
||||||
|
<label><input type="checkbox" id="schedule-freebusy-wokinghours" value="1" /><roundcube:label name="calendar.onlyworkinghours" /></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br style="clear:both;" />
|
||||||
|
|
||||||
<roundcube:include file="/templates/freebusylegend.html" />
|
<roundcube:include file="/templates/freebusylegend.html" />
|
||||||
|
<div class="attendees-list">
|
||||||
|
<span class="attendee organizer"><roundcube:label name="calendar.roleorganizer" /></span>
|
||||||
|
<span class="attendee req-participant"><roundcube:label name="calendar.rolerequired" /></span>
|
||||||
|
<span class="attendee opt-participant"><roundcube:label name="calendar.roleoptional" /></span>
|
||||||
|
<span class="attendee chair"><roundcube:label name="calendar.roleresource" /></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="calendarform" class="uidialog">
|
<div id="calendarform" class="uidialog">
|
||||||
|
|
Loading…
Add table
Reference in a new issue