Accessibility enhancements for the calendar module (#3084)
This commit is contained in:
parent
6d9d854e65
commit
efecba6675
13 changed files with 315 additions and 152 deletions
|
@ -299,7 +299,7 @@ class calendar extends rcube_plugin
|
||||||
$this->rc->output->set_env('calendar_driver', $this->rc->config->get('calendar_driver'), false);
|
$this->rc->output->set_env('calendar_driver', $this->rc->config->get('calendar_driver'), false);
|
||||||
$this->rc->output->set_env('calendar_resources', (bool)$this->rc->config->get('calendar_resources_driver'));
|
$this->rc->output->set_env('calendar_resources', (bool)$this->rc->config->get('calendar_resources_driver'));
|
||||||
$this->rc->output->set_env('mscolors', jqueryui::get_color_values());
|
$this->rc->output->set_env('mscolors', jqueryui::get_color_values());
|
||||||
$this->rc->output->set_env('identities-selector', $this->ui->identity_select(array('id' => 'edit-identities-list')));
|
$this->rc->output->set_env('identities-selector', $this->ui->identity_select(array('id' => 'edit-identities-list', 'aria-label' => $this->gettext('roleorganizer'))));
|
||||||
|
|
||||||
$view = get_input_value('view', RCUBE_INPUT_GPC);
|
$view = get_input_value('view', RCUBE_INPUT_GPC);
|
||||||
if (in_array($view, array('agendaWeek', 'agendaDay', 'month', 'table')))
|
if (in_array($view, array('agendaWeek', 'agendaDay', 'month', 'table')))
|
||||||
|
|
|
@ -237,32 +237,33 @@ function rcube_calendar_ui(settings)
|
||||||
if (edit) {
|
if (edit) {
|
||||||
rcmail.env.attachments[elem.id] = elem;
|
rcmail.env.attachments[elem.id] = elem;
|
||||||
// delete icon
|
// delete icon
|
||||||
content = document.createElement('A');
|
content = $('<a href="#delete" />')
|
||||||
content.href = '#delete';
|
.attr('title', rcmail.gettext('delete'))
|
||||||
content.title = rcmail.gettext('delete');
|
.attr('aria-label', rcmail.gettext('delete') + ' ' + Q(elem.name))
|
||||||
content.className = 'delete';
|
.addClass('delete')
|
||||||
$(content).click({id: elem.id}, function(e) { remove_attachment(this, e.data.id); return false; });
|
.click({id: elem.id}, function(e) { remove_attachment(this, e.data.id); return false; });
|
||||||
|
|
||||||
if (!rcmail.env.deleteicon)
|
if (!rcmail.env.deleteicon)
|
||||||
content.innerHTML = rcmail.gettext('delete');
|
content.html(rcmail.gettext('delete'));
|
||||||
else {
|
else {
|
||||||
img = document.createElement('IMG');
|
img = document.createElement('IMG');
|
||||||
img.src = rcmail.env.deleteicon;
|
img.src = rcmail.env.deleteicon;
|
||||||
img.alt = rcmail.gettext('delete');
|
img.alt = rcmail.gettext('delete');
|
||||||
content.appendChild(img);
|
content.append(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
li.appendChild(content);
|
content.appendTo(li);
|
||||||
}
|
}
|
||||||
|
|
||||||
// name/link
|
// name/link
|
||||||
content = document.createElement('A');
|
content = $('<a href="#load" />')
|
||||||
content.innerHTML = elem.name;
|
.html(Q(elem.name))
|
||||||
content.className = 'file';
|
.addClass('file')
|
||||||
content.href = '#load';
|
.click({event: event, att: elem}, function(e) {
|
||||||
$(content).click({event: event, att: elem}, function(e) {
|
load_attachment(e.data.event, e.data.att);
|
||||||
load_attachment(e.data.event, e.data.att); return false; });
|
return false;
|
||||||
li.appendChild(content);
|
})
|
||||||
|
.appendTo(li);
|
||||||
|
|
||||||
ul.appendChild(li);
|
ul.appendChild(li);
|
||||||
}
|
}
|
||||||
|
@ -283,7 +284,7 @@ function rcube_calendar_ui(settings)
|
||||||
};
|
};
|
||||||
|
|
||||||
// event details dialog (show only)
|
// event details dialog (show only)
|
||||||
var event_show_dialog = function(event)
|
var event_show_dialog = function(event, ev)
|
||||||
{
|
{
|
||||||
var $dialog = $("#eventshow").attr('class', 'uidialog');
|
var $dialog = $("#eventshow").attr('class', 'uidialog');
|
||||||
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:false };
|
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:false };
|
||||||
|
@ -430,18 +431,28 @@ function rcube_calendar_ui(settings)
|
||||||
modal: false,
|
modal: false,
|
||||||
resizable: !bw.ie6,
|
resizable: !bw.ie6,
|
||||||
closeOnEscape: (!bw.ie6 && !bw.ie7), // disable for performance reasons
|
closeOnEscape: (!bw.ie6 && !bw.ie7), // disable for performance reasons
|
||||||
title: Q(me.event_date_text(event)),
|
title: me.event_date_text(event),
|
||||||
open: function() {
|
open: function() {
|
||||||
$dialog.parent().find('.ui-button').first().focus();
|
$dialog.attr('aria-hidden', 'false');
|
||||||
|
setTimeout(function(){
|
||||||
|
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
|
||||||
|
}, 5);
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
$dialog.dialog('destroy').hide();
|
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
|
||||||
},
|
},
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
minWidth: 320,
|
minWidth: 320,
|
||||||
width: 420
|
width: 420
|
||||||
}).show();
|
}).show();
|
||||||
|
|
||||||
|
// remember opener element (to be focused on close)
|
||||||
|
$dialog.data('opener', ev && rcube_event.is_keyboard(ev) ? ev.target : null);
|
||||||
|
|
||||||
|
// set voice title on dialog widget
|
||||||
|
$dialog.dialog('widget').removeAttr('aria-labelledby')
|
||||||
|
.attr('aria-label', me.event_date_text(event, true) + ', ', event.title);
|
||||||
|
|
||||||
// set dialog size according to content
|
// set dialog size according to content
|
||||||
me.dialog_resize($dialog.get(0), $dialog.height(), 420);
|
me.dialog_resize($dialog.get(0), $dialog.height(), 420);
|
||||||
/*
|
/*
|
||||||
|
@ -472,8 +483,11 @@ function rcube_calendar_ui(settings)
|
||||||
// bring up the event dialog (jquery-ui popup)
|
// bring up the event dialog (jquery-ui popup)
|
||||||
var event_edit_dialog = function(action, event)
|
var event_edit_dialog = function(action, event)
|
||||||
{
|
{
|
||||||
|
// copy opener element from show dialog
|
||||||
|
var op_elem = $("#eventshow:ui-dialog").data('opener');
|
||||||
|
|
||||||
// close show dialog first
|
// close show dialog first
|
||||||
$("#eventshow:ui-dialog").dialog('close');
|
$("#eventshow:ui-dialog").data('opener', null).dialog('close');
|
||||||
|
|
||||||
var $dialog = $('<div>');
|
var $dialog = $('<div>');
|
||||||
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' };
|
||||||
|
@ -675,7 +689,7 @@ function rcube_calendar_ui(settings)
|
||||||
$('#edit-tab-attachments')[(calendar.attachments?'show':'hide')]();
|
$('#edit-tab-attachments')[(calendar.attachments?'show':'hide')]();
|
||||||
|
|
||||||
// activate the first tab
|
// activate the first tab
|
||||||
$('#eventtabs').tabs('select', 0);
|
$('#eventtabs').tabs('option', 'active', 0);
|
||||||
|
|
||||||
// hack: set task to 'calendar' to make all dialog actions work correctly
|
// hack: set task to 'calendar' to make all dialog actions work correctly
|
||||||
var comm_path_before = rcmail.env.comm_path;
|
var comm_path_before = rcmail.env.comm_path;
|
||||||
|
@ -690,15 +704,18 @@ function rcube_calendar_ui(settings)
|
||||||
closeOnEscape: false,
|
closeOnEscape: false,
|
||||||
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
|
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
|
||||||
open: function() {
|
open: function() {
|
||||||
|
editform.attr('aria-hidden', 'false');
|
||||||
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
|
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
editform.hide().appendTo(document.body);
|
editform.hide().attr('aria-hidden', 'true').appendTo(document.body);
|
||||||
$dialog.dialog("destroy").remove();
|
$dialog.dialog("destroy").remove();
|
||||||
rcmail.ksearch_blur();
|
rcmail.ksearch_blur();
|
||||||
rcmail.ksearch_destroy();
|
rcmail.ksearch_destroy();
|
||||||
freebusy_data = {};
|
freebusy_data = {};
|
||||||
rcmail.env.comm_path = comm_path_before; // restore comm_path
|
rcmail.env.comm_path = comm_path_before; // restore comm_path
|
||||||
|
if (op_elem)
|
||||||
|
$(op_elem).focus();
|
||||||
},
|
},
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
minWidth: 500,
|
minWidth: 500,
|
||||||
|
@ -843,12 +860,13 @@ function rcube_calendar_ui(settings)
|
||||||
closeOnEscape: (!bw.ie6 && !bw.ie7),
|
closeOnEscape: (!bw.ie6 && !bw.ie7),
|
||||||
title: rcmail.gettext('scheduletime', 'calendar'),
|
title: rcmail.gettext('scheduletime', 'calendar'),
|
||||||
open: function() {
|
open: function() {
|
||||||
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().focus();
|
$dialog.attr('aria-hidden', 'false').find('#shedule-find-next, #shedule-find-prev').not(':disabled').first().focus();
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
if (bw.ie6)
|
if (bw.ie6)
|
||||||
$("#edit-attendees-table").css('visibility','visible');
|
$("#edit-attendees-table").css('visibility','visible');
|
||||||
$dialog.dialog("destroy").hide();
|
$dialog.dialog("destroy").attr('aria-hidden', 'true').hide();
|
||||||
|
// TODO: focus opener button
|
||||||
},
|
},
|
||||||
resizeStop: function() {
|
resizeStop: function() {
|
||||||
render_freebusy_overlay();
|
render_freebusy_overlay();
|
||||||
|
@ -1316,6 +1334,9 @@ function rcube_calendar_ui(settings)
|
||||||
|
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
$('#shedule-find-prev').button('option', 'disabled', (event.start.getTime() < now.getTime()));
|
$('#shedule-find-prev').button('option', 'disabled', (event.start.getTime() < now.getTime()));
|
||||||
|
|
||||||
|
// speak new selection
|
||||||
|
rcmail.display_message(rcmail.gettext('suggestedslot', 'calendar') + ': ' + me.event_date_text(event, true), 'voice');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert(rcmail.gettext('noslotfound','calendar'));
|
alert(rcmail.gettext('noslotfound','calendar'));
|
||||||
|
@ -1407,7 +1428,7 @@ function rcube_calendar_ui(settings)
|
||||||
if (organizer && !readonly)
|
if (organizer && !readonly)
|
||||||
dispname = rcmail.env['identities-selector'];
|
dispname = rcmail.env['identities-selector'];
|
||||||
|
|
||||||
var select = '<select class="edit-attendee-role"' + (organizer || readonly ? ' disabled="true"' : '') + '>';
|
var select = '<select class="edit-attendee-role"' + (organizer || readonly ? ' disabled="true"' : '') + ' aria-label="' + rcmail.gettext('role','calendar') + '">';
|
||||||
for (var r in opts)
|
for (var r in opts)
|
||||||
select += '<option value="'+ r +'" class="' + r.toLowerCase() + '"' + (data.role == r ? ' selected="selected"' : '') +'>' + Q(opts[r]) + '</option>';
|
select += '<option value="'+ r +'" class="' + r.toLowerCase() + '"' + (data.role == r ? ' selected="selected"' : '') +'>' + Q(opts[r]) + '</option>';
|
||||||
select += '</select>';
|
select += '</select>';
|
||||||
|
@ -1427,7 +1448,7 @@ function rcube_calendar_ui(settings)
|
||||||
|
|
||||||
var html = '<td class="role">' + select + '</td>' +
|
var html = '<td class="role">' + select + '</td>' +
|
||||||
'<td class="name">' + dispname + '</td>' +
|
'<td class="name">' + dispname + '</td>' +
|
||||||
'<td class="availability"><img src="./program/resources/blank.gif" class="availabilityicon ' + avail + '" data-email="' + data.email + '" /></td>' +
|
'<td class="availability"><img src="./program/resources/blank.gif" class="availabilityicon ' + avail + '" data-email="' + data.email + '" alt="" /></td>' +
|
||||||
'<td class="confirmstate"><span class="' + String(data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + Q(data.status || '') + '</span></td>' +
|
'<td class="confirmstate"><span class="' + String(data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + Q(data.status || '') + '</span></td>' +
|
||||||
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
|
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
|
||||||
|
|
||||||
|
@ -1482,10 +1503,11 @@ function rcube_calendar_ui(settings)
|
||||||
url: rcmail.url('freebusy-status'),
|
url: rcmail.url('freebusy-status'),
|
||||||
data: { email:email, start:date2servertime(clone_date(event.start, event.allDay?1:0)), end:date2servertime(clone_date(event.end, event.allDay?2:0)), _remote: 1 },
|
data: { email:email, start:date2servertime(clone_date(event.start, event.allDay?1:0)), end:date2servertime(clone_date(event.end, event.allDay?2:0)), _remote: 1 },
|
||||||
success: function(status){
|
success: function(status){
|
||||||
icon.removeClass('loading').addClass(String(status).toLowerCase());
|
var avail = String(status).toLowerCase();
|
||||||
|
icon.removeClass('loading').addClass(avail).attr('alt', rcmail.gettext('avail' + avail, 'calendar'));
|
||||||
},
|
},
|
||||||
error: function(){
|
error: function(){
|
||||||
icon.removeClass('loading').addClass('unknown');
|
icon.removeClass('loading').addClass('unknown').attr('alt', rcmail.gettext('availunknown', 'calendar'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1522,11 +1544,14 @@ function rcube_calendar_ui(settings)
|
||||||
resizable: true,
|
resizable: true,
|
||||||
closeOnEscape: true,
|
closeOnEscape: true,
|
||||||
title: rcmail.gettext('findresources', 'calendar'),
|
title: rcmail.gettext('findresources', 'calendar'),
|
||||||
|
open: function() {
|
||||||
|
$dialog.attr('aria-hidden', 'false');
|
||||||
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
$dialog.dialog('destroy').hide();
|
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
|
||||||
},
|
},
|
||||||
resize: function(e) {
|
resize: function(e) {
|
||||||
var container = $(rcmail.gui_objects.resourceinfocalendar)
|
var container = $(rcmail.gui_objects.resourceinfocalendar);
|
||||||
container.fullCalendar('option', 'height', container.height() + 4);
|
container.fullCalendar('option', 'height', container.height() + 4);
|
||||||
},
|
},
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
|
@ -1593,9 +1618,11 @@ function rcube_calendar_ui(settings)
|
||||||
titleFormat: { day: 'dddd ' + settings['date_long'] },
|
titleFormat: { day: 'dddd ' + settings['date_long'] },
|
||||||
currentTimeIndicator: settings.time_indicator,
|
currentTimeIndicator: settings.time_indicator,
|
||||||
eventRender: function(event, element, view) {
|
eventRender: function(event, element, view) {
|
||||||
|
var title = rcmail.get_label(event.status, 'calendar');
|
||||||
element.addClass('status-' + event.status);
|
element.addClass('status-' + event.status);
|
||||||
element.find('.fc-event-head').hide();
|
element.find('.fc-event-head').hide();
|
||||||
element.find('.fc-event-title').text(rcmail.get_label(event.status, 'calendar'));
|
element.find('.fc-event-title').text(title);
|
||||||
|
element.attr('aria-label', me.event_date_text(event, true) + ': ' + title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1971,10 +1998,12 @@ function rcube_calendar_ui(settings)
|
||||||
title: rcmail.gettext((action == 'remove' ? 'removeeventconfirm' : 'changeeventconfirm'), 'calendar'),
|
title: rcmail.gettext((action == 'remove' ? 'removeeventconfirm' : 'changeeventconfirm'), 'calendar'),
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
open: function() {
|
open: function() {
|
||||||
$dialog.parent().find('.ui-button').first().focus();
|
setTimeout(function(){
|
||||||
|
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
|
||||||
|
}, 5);
|
||||||
},
|
},
|
||||||
close: function(){
|
close: function(){
|
||||||
$dialog.dialog("destroy").hide();
|
$dialog.dialog("destroy").remove();
|
||||||
if (!rcmail.busy)
|
if (!rcmail.busy)
|
||||||
fc.fullCalendar('refetchEvents');
|
fc.fullCalendar('refetchEvents');
|
||||||
}
|
}
|
||||||
|
@ -2021,6 +2050,8 @@ function rcube_calendar_ui(settings)
|
||||||
if (event.status) {
|
if (event.status) {
|
||||||
element.addClass('cal-event-status-' + String(event.status).toLowerCase());
|
element.addClass('cal-event-status-' + String(event.status).toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
element.attr('aria-label', event.title + ', ' + me.event_date_text(event, true));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2099,8 +2130,8 @@ function rcube_calendar_ui(settings)
|
||||||
allDayText: rcmail.gettext('all-day', 'calendar'),
|
allDayText: rcmail.gettext('all-day', 'calendar'),
|
||||||
currentTimeIndicator: settings.time_indicator,
|
currentTimeIndicator: settings.time_indicator,
|
||||||
eventRender: fc_event_render,
|
eventRender: fc_event_render,
|
||||||
eventClick: function(event) {
|
eventClick: function(event, ev, view) {
|
||||||
event_show_dialog(event);
|
event_show_dialog(event, ev);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2743,6 +2774,7 @@ function rcube_calendar_ui(settings)
|
||||||
id_prefix: 'rcmlical',
|
id_prefix: 'rcmlical',
|
||||||
selectable: true,
|
selectable: true,
|
||||||
save_state: true,
|
save_state: true,
|
||||||
|
keyboard: false,
|
||||||
searchbox: '#calendarlistsearch',
|
searchbox: '#calendarlistsearch',
|
||||||
search_action: 'calendar/calendar',
|
search_action: 'calendar/calendar',
|
||||||
search_sources: [ 'folders', 'users' ],
|
search_sources: [ 'folders', 'users' ],
|
||||||
|
@ -2773,6 +2805,12 @@ function rcube_calendar_ui(settings)
|
||||||
rcmail.http_post('calendar', { action:'subscribe', c:{ id:p.id, active:cal.active?1:0, permanent:cal.subscribed?1:0 } });
|
rcmail.http_post('calendar', { action:'subscribe', c:{ id:p.id, active:cal.active?1:0, permanent:cal.subscribed?1:0 } });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
calendars_list.addEventListener('search-complete', function(data) {
|
||||||
|
if (data.length)
|
||||||
|
rcmail.display_message(rcmail.gettext('nrcalendarsfound','calendar').replace('$nr', data.length), 'voice');
|
||||||
|
else
|
||||||
|
rcmail.display_message(rcmail.gettext('nocalendarsfound','calendar'), 'info');
|
||||||
|
});
|
||||||
|
|
||||||
// init (delegate) event handler on calendar list checkboxes
|
// init (delegate) event handler on calendar list checkboxes
|
||||||
$(rcmail.gui_objects.calendarslist).on('click', 'input[type=checkbox]', function(e){
|
$(rcmail.gui_objects.calendarslist).on('click', 'input[type=checkbox]', function(e){
|
||||||
|
@ -2922,9 +2960,9 @@ function rcube_calendar_ui(settings)
|
||||||
day_clicked_ts = now;
|
day_clicked_ts = now;
|
||||||
},
|
},
|
||||||
// callback when a specific event is clicked
|
// callback when a specific event is clicked
|
||||||
eventClick: function(event) {
|
eventClick: function(event, ev, view) {
|
||||||
if (!event.temp)
|
if (!event.temp)
|
||||||
event_show_dialog(event);
|
event_show_dialog(event, ev);
|
||||||
},
|
},
|
||||||
// callback when an event was dragged and finally dropped
|
// callback when an event was dragged and finally dropped
|
||||||
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
|
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
|
||||||
|
@ -3054,7 +3092,7 @@ function rcube_calendar_ui(settings)
|
||||||
// scroll to current time
|
// scroll to current time
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var widget = $this.autocomplete('widget');
|
var widget = $this.autocomplete('widget');
|
||||||
var menu = $this.data('autocomplete').menu;
|
var menu = $this.data('ui-autocomplete').menu;
|
||||||
var amregex = /^(.+)(a[.m]*)/i;
|
var amregex = /^(.+)(a[.m]*)/i;
|
||||||
var pmregex = /^(.+)(a[.m]*)/i;
|
var pmregex = /^(.+)(a[.m]*)/i;
|
||||||
var val = $(this).val().replace(amregex, '0:$1').replace(pmregex, '1:$1');
|
var val = $(this).val().replace(amregex, '0:$1').replace(pmregex, '1:$1');
|
||||||
|
@ -3107,9 +3145,9 @@ function rcube_calendar_ui(settings)
|
||||||
return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), ''];
|
return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), ''];
|
||||||
}
|
}
|
||||||
})) // set event handler for clicks on calendar week cell of the datepicker widget
|
})) // set event handler for clicks on calendar week cell of the datepicker widget
|
||||||
.click(function(e) {
|
.on('click', 'td.ui-datepicker-week-col', function(e) {
|
||||||
var cell = $(e.target);
|
var cell = $(e.target);
|
||||||
if (e.target.tagName == 'TD' && cell.hasClass('ui-datepicker-week-col')) {
|
if (e.target.tagName == 'TD' && cell.hasClass('')) {
|
||||||
var base_date = minical.datepicker('getDate');
|
var base_date = minical.datepicker('getDate');
|
||||||
if (minical.data('month'))
|
if (minical.data('month'))
|
||||||
base_date.setMonth(minical.data('month')-1);
|
base_date.setMonth(minical.data('month')-1);
|
||||||
|
@ -3126,7 +3164,9 @@ function rcube_calendar_ui(settings)
|
||||||
fc.fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek');
|
fc.fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek');
|
||||||
minical.datepicker('setDate', date);
|
minical.datepicker('setDate', date);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
minical.find('.ui-datepicker-inline').attr('aria-labelledby', 'aria-label-minical');
|
||||||
|
|
||||||
if (rcmail.env.date) {
|
if (rcmail.env.date) {
|
||||||
var viewdate = new Date();
|
var viewdate = new Date();
|
||||||
|
@ -3136,10 +3176,11 @@ function rcube_calendar_ui(settings)
|
||||||
|
|
||||||
// init event dialog
|
// init event dialog
|
||||||
$('#eventtabs').tabs({
|
$('#eventtabs').tabs({
|
||||||
show: function(event, ui) {
|
activate: function(event, ui) {
|
||||||
if (ui.panel.id == 'event-panel-attendees' || ui.panel.id == 'event-panel-resources') {
|
if (ui.newPanel.selector == '#event-panel-attendees' || ui.newPanel.selector == '#event-panel-resources') {
|
||||||
var tab = ui.panel.id == 'event-panel-resources' ? 'resource' : 'attendee';
|
var tab = ui.newPanel.selector == '#event-panel-resources' ? 'resource' : 'attendee';
|
||||||
$('#edit-'+tab+'-name').select();
|
if (!rcube_event.is_keyboard(event))
|
||||||
|
$('#edit-'+tab+'-name').select();
|
||||||
// update free-busy status if needed
|
// update free-busy status if needed
|
||||||
if (freebusy_ui.needsupdate && me.selected_event)
|
if (freebusy_ui.needsupdate && me.selected_event)
|
||||||
update_freebusy_status(me.selected_event);
|
update_freebusy_status(me.selected_event);
|
||||||
|
@ -3162,6 +3203,7 @@ function rcube_calendar_ui(settings)
|
||||||
.autocomplete({
|
.autocomplete({
|
||||||
delay: 100,
|
delay: 100,
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
|
appendTo: '#eventedit',
|
||||||
source: autocomplete_times,
|
source: autocomplete_times,
|
||||||
open: autocomplete_open,
|
open: autocomplete_open,
|
||||||
change: event_times_changed,
|
change: event_times_changed,
|
||||||
|
@ -3173,9 +3215,9 @@ function rcube_calendar_ui(settings)
|
||||||
.click(function() { // show drop-down upon clicks
|
.click(function() { // show drop-down upon clicks
|
||||||
$(this).autocomplete('search', $(this).val() ? $(this).val().replace(/\D.*/, "") : " ");
|
$(this).autocomplete('search', $(this).val() ? $(this).val().replace(/\D.*/, "") : " ");
|
||||||
}).each(function(){
|
}).each(function(){
|
||||||
$(this).data('autocomplete')._renderItem = function(ul, item) {
|
$(this).data('ui-autocomplete')._renderItem = function(ul, item) {
|
||||||
return $('<li>')
|
return $('<li>')
|
||||||
.data('item.autocomplete', item)
|
.data('ui-autocomplete-item', item)
|
||||||
.append('<a>' + item[0] + item[1] + '</a>')
|
.append('<a>' + item[0] + item[1] + '</a>')
|
||||||
.appendTo(ul);
|
.appendTo(ul);
|
||||||
};
|
};
|
||||||
|
|
|
@ -303,10 +303,11 @@ class calendar_ui
|
||||||
|
|
||||||
$content = '';
|
$content = '';
|
||||||
if (!$activeonly || $prop['active']) {
|
if (!$activeonly || $prop['active']) {
|
||||||
|
$label_id = 'cl:' . $id;
|
||||||
$content = html::div(join(' ', $classes),
|
$content = html::div(join(' ', $classes),
|
||||||
html::span(array('class' => 'calname', 'title' => $title), $prop['editname'] ? Q($prop['editname']) : $prop['listname']) .
|
html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? Q($prop['editname']) : $prop['listname']) .
|
||||||
($prop['virtual'] ? '' :
|
($prop['virtual'] ? '' :
|
||||||
html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active']), '') .
|
html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') .
|
||||||
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe')), ' ') : '') .
|
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe')), ' ') : '') .
|
||||||
html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' ')
|
html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' ')
|
||||||
)
|
)
|
||||||
|
@ -326,7 +327,7 @@ class calendar_ui
|
||||||
|
|
||||||
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange'));
|
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange'));
|
||||||
$select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $days);
|
$select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $days);
|
||||||
foreach (array(2,5,7,14,30,60,90) as $days)
|
foreach (array(2,5,7,14,30,60,90,180,365) as $days)
|
||||||
$select_range->add($days . ' ' . preg_replace('/\(|\)/', '', $this->cal->lib->gettext('days')), $days);
|
$select_range->add($days . ' ' . preg_replace('/\(|\)/', '', $this->cal->lib->gettext('days')), $days);
|
||||||
|
|
||||||
$html .= html::label('agenda-listrange', $this->cal->gettext('listrange'));
|
$html .= html::label('agenda-listrange', $this->cal->gettext('listrange'));
|
||||||
|
@ -334,8 +335,8 @@ class calendar_ui
|
||||||
|
|
||||||
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections'));
|
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections'));
|
||||||
$select_sections->add('---', '');
|
$select_sections->add('---', '');
|
||||||
foreach (array('day' => 'days', 'week' => 'weeks', 'month' => 'months', 'smart' => 'smartsections') as $val => $label)
|
foreach (array('day' => 'libcalendaring.days', 'week' => 'libcalendaring.weeks', 'month' => 'libcalendaring.months', 'smart' => 'calendar.smartsections') as $val => $label)
|
||||||
$select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->cal->gettext($label))), $val);
|
$select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->rc->gettext($label))), $val);
|
||||||
|
|
||||||
$html .= html::span('spacer', ' ');
|
$html .= html::span('spacer', ' ');
|
||||||
$html .= html::label('agenda-listsections', $this->cal->gettext('listsections'));
|
$html .= html::label('agenda-listsections', $this->cal->gettext('listsections'));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* FullCalendar v1.6.4-rcube-1.0
|
* FullCalendar v1.6.4-rcube-1.1
|
||||||
* Docs & License: http://arshaw.com/fullcalendar/
|
* Docs & License: http://arshaw.com/fullcalendar/
|
||||||
* (c) 2013 Adam Shaw, 2014 Kolab Systems AG
|
* (c) 2013 Adam Shaw, 2014 Kolab Systems AG
|
||||||
*/
|
*/
|
||||||
|
@ -813,7 +813,7 @@ function Header(calendar, options) {
|
||||||
var prevButton;
|
var prevButton;
|
||||||
$.each(this.split(','), function(j, buttonName) {
|
$.each(this.split(','), function(j, buttonName) {
|
||||||
if (buttonName == 'title') {
|
if (buttonName == 'title') {
|
||||||
e.append("<span class='fc-header-title'><h2> </h2></span>");
|
e.append("<span class='fc-header-title'><h2 aria-live='polite' aria-relevant='text' aria-atomic='true'> </h2></span>");
|
||||||
if (prevButton) {
|
if (prevButton) {
|
||||||
prevButton.addClass(tm + '-corner-right');
|
prevButton.addClass(tm + '-corner-right');
|
||||||
}
|
}
|
||||||
|
@ -833,7 +833,7 @@ function Header(calendar, options) {
|
||||||
var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?
|
var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?
|
||||||
var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?
|
var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?
|
||||||
var button = $(
|
var button = $(
|
||||||
"<span class='fc-button fc-button-" + buttonName + " " + tm + "-state-default'>" +
|
"<span class='fc-button fc-button-" + buttonName + " " + tm + "-state-default' role='button' tabindex='0'>" +
|
||||||
(icon ?
|
(icon ?
|
||||||
"<span class='fc-icon-wrap'>" +
|
"<span class='fc-icon-wrap'>" +
|
||||||
"<span class='ui-icon ui-icon-" + icon + "'/>" +
|
"<span class='ui-icon ui-icon-" + icon + "'/>" +
|
||||||
|
@ -869,6 +869,10 @@ function Header(calendar, options) {
|
||||||
.removeClass(tm + '-state-down');
|
.removeClass(tm + '-state-down');
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.keypress(function(ev) {
|
||||||
|
if (ev.keyCode == 13)
|
||||||
|
$(ev.target).trigger('click');
|
||||||
|
})
|
||||||
.appendTo(e);
|
.appendTo(e);
|
||||||
disableTextSelection(button);
|
disableTextSelection(button);
|
||||||
if (!prevButton) {
|
if (!prevButton) {
|
||||||
|
@ -895,25 +899,25 @@ function Header(calendar, options) {
|
||||||
|
|
||||||
function activateButton(buttonName) {
|
function activateButton(buttonName) {
|
||||||
element.find('span.fc-button-' + buttonName)
|
element.find('span.fc-button-' + buttonName)
|
||||||
.addClass(tm + '-state-active');
|
.addClass(tm + '-state-active').attr('tabindex', '-1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deactivateButton(buttonName) {
|
function deactivateButton(buttonName) {
|
||||||
element.find('span.fc-button-' + buttonName)
|
element.find('span.fc-button-' + buttonName)
|
||||||
.removeClass(tm + '-state-active');
|
.removeClass(tm + '-state-active').attr('tabindex', '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function disableButton(buttonName) {
|
function disableButton(buttonName) {
|
||||||
element.find('span.fc-button-' + buttonName)
|
element.find('span.fc-button-' + buttonName)
|
||||||
.addClass(tm + '-state-disabled');
|
.addClass(tm + '-state-disabled').attr('tabindex', '-1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function enableButton(buttonName) {
|
function enableButton(buttonName) {
|
||||||
element.find('span.fc-button-' + buttonName)
|
element.find('span.fc-button-' + buttonName)
|
||||||
.removeClass(tm + '-state-disabled');
|
.removeClass(tm + '-state-disabled').attr('tabindex', '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1760,7 +1764,7 @@ function _exclEndDay(end, allDay) {
|
||||||
|
|
||||||
|
|
||||||
function lazySegBind(container, segs, bindHandlers) {
|
function lazySegBind(container, segs, bindHandlers) {
|
||||||
container.unbind('mouseover').mouseover(function(ev) {
|
container.unbind('mouseover focusin').bind('mouseover focusin', function(ev) {
|
||||||
var parent=ev.target, e,
|
var parent=ev.target, e,
|
||||||
i, seg;
|
i, seg;
|
||||||
while (parent != this) {
|
while (parent != this) {
|
||||||
|
@ -4051,7 +4055,7 @@ function AgendaEventRenderer() {
|
||||||
"left:" + seg.left + "px;" +
|
"left:" + seg.left + "px;" +
|
||||||
skinCss +
|
skinCss +
|
||||||
"'" +
|
"'" +
|
||||||
">" +
|
" tabindex='0'>" +
|
||||||
"<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
|
"<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
|
||||||
"<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
|
"<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
|
||||||
"<div class='fc-event-time'>" +
|
"<div class='fc-event-time'>" +
|
||||||
|
@ -4067,7 +4071,7 @@ function AgendaEventRenderer() {
|
||||||
"</div>"; // close inner
|
"</div>"; // close inner
|
||||||
if (seg.isEnd && isEventResizable(event)) {
|
if (seg.isEnd && isEventResizable(event)) {
|
||||||
html +=
|
html +=
|
||||||
"<div class='ui-resizable-handle ui-resizable-s'>=</div>";
|
"<div class='ui-resizable-handle ui-resizable-s' role='presentation'>=</div>";
|
||||||
}
|
}
|
||||||
html +=
|
html +=
|
||||||
"</" + (url ? "a" : "div") + ">";
|
"</" + (url ? "a" : "div") + ">";
|
||||||
|
@ -4941,7 +4945,7 @@ function ListEventRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazySegBind(container, seg, bindHandlers) {
|
function lazySegBind(container, seg, bindHandlers) {
|
||||||
container.unbind('mouseover').mouseover(function(ev) {
|
container.unbind('mouseover focusin').bind('mouseover focusin', function(ev) {
|
||||||
var parent = ev.target, e = parent, i, event;
|
var parent = ev.target, e = parent, i, event;
|
||||||
while (parent != this) {
|
while (parent != this) {
|
||||||
e = parent;
|
e = parent;
|
||||||
|
@ -5132,7 +5136,7 @@ function TableEventRenderer() {
|
||||||
rowClasses.push('fc-today');
|
rowClasses.push('fc-today');
|
||||||
}
|
}
|
||||||
|
|
||||||
s += "<tr class='" + rowClasses.join(' ') + "'>";
|
s += "<tr class='" + rowClasses.join(' ') + "' tabindex='0'>";
|
||||||
for (var col, c=0; c < tableCols.length; c++) {
|
for (var col, c=0; c < tableCols.length; c++) {
|
||||||
col = tableCols[c];
|
col = tableCols[c];
|
||||||
if (col == 'handle') {
|
if (col == 'handle') {
|
||||||
|
@ -5358,7 +5362,11 @@ function View(element, calendar, viewName) {
|
||||||
function(ev) {
|
function(ev) {
|
||||||
trigger('eventMouseout', this, event, ev);
|
trigger('eventMouseout', this, event, ev);
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
.keypress(function(ev) {
|
||||||
|
if (ev.keyCode == 13)
|
||||||
|
$(this).trigger('click', { pointerType:'keyboard' });
|
||||||
|
});
|
||||||
// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)
|
// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)
|
||||||
// TODO: same for resizing
|
// TODO: same for resizing
|
||||||
}
|
}
|
||||||
|
@ -6008,7 +6016,7 @@ function DayEventRenderer() {
|
||||||
"left:" + segment.left + "px;" +
|
"left:" + segment.left + "px;" +
|
||||||
skinCss +
|
skinCss +
|
||||||
"'" +
|
"'" +
|
||||||
">" +
|
" tabindex='0'>" +
|
||||||
"<div class='fc-event-inner'>";
|
"<div class='fc-event-inner'>";
|
||||||
if (!event.allDay && segment.isStart) {
|
if (!event.allDay && segment.isStart) {
|
||||||
html +=
|
html +=
|
||||||
|
|
|
@ -53,7 +53,9 @@ $labels['location'] = 'Location';
|
||||||
$labels['url'] = 'URL';
|
$labels['url'] = 'URL';
|
||||||
$labels['date'] = 'Date';
|
$labels['date'] = 'Date';
|
||||||
$labels['start'] = 'Start';
|
$labels['start'] = 'Start';
|
||||||
|
$labels['starttime'] = 'Start time';
|
||||||
$labels['end'] = 'End';
|
$labels['end'] = 'End';
|
||||||
|
$labels['endtime'] = 'End time';
|
||||||
$labels['repeat'] = 'Repeat';
|
$labels['repeat'] = 'Repeat';
|
||||||
$labels['selectdate'] = 'Choose date';
|
$labels['selectdate'] = 'Choose date';
|
||||||
$labels['freebusy'] = 'Show me as';
|
$labels['freebusy'] = 'Show me as';
|
||||||
|
@ -87,8 +89,11 @@ $labels['showurl'] = 'Show calendar URL';
|
||||||
$labels['showurldescription'] = 'Use the following address to access (read only) your calendar from other applications. You can copy and paste this into any calendar software that supports the iCal format.';
|
$labels['showurldescription'] = 'Use the following address to access (read only) your calendar from other applications. You can copy and paste this into any calendar software that supports the iCal format.';
|
||||||
$labels['caldavurldescription'] = 'Copy this address to a <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> client application (e.g. Evolution or Mozilla Thunderbird) to fully synchronize this specific calendar with your computer or mobile device.';
|
$labels['caldavurldescription'] = 'Copy this address to a <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> client application (e.g. Evolution or Mozilla Thunderbird) to fully synchronize this specific calendar with your computer or mobile device.';
|
||||||
$labels['findcalendars'] = 'Find calendars...';
|
$labels['findcalendars'] = 'Find calendars...';
|
||||||
|
$labels['searchterms'] = 'Search terms';
|
||||||
$labels['calsearchresults'] = 'Available Calendars';
|
$labels['calsearchresults'] = 'Available Calendars';
|
||||||
$labels['calendarsubscribe'] = 'List permanently';
|
$labels['calendarsubscribe'] = 'List permanently';
|
||||||
|
$labels['nocalendarsfound'] = 'No calendars found';
|
||||||
|
$labels['nrcalendarsfound'] = '$nr calendars found';
|
||||||
|
|
||||||
// agenda view
|
// agenda view
|
||||||
$labels['listrange'] = 'Range to display:';
|
$labels['listrange'] = 'Range to display:';
|
||||||
|
@ -99,6 +104,7 @@ $labels['today'] = 'Today';
|
||||||
$labels['tomorrow'] = 'Tomorrow';
|
$labels['tomorrow'] = 'Tomorrow';
|
||||||
$labels['thisweek'] = 'This week';
|
$labels['thisweek'] = 'This week';
|
||||||
$labels['nextweek'] = 'Next week';
|
$labels['nextweek'] = 'Next week';
|
||||||
|
$labels['prevweek'] = 'Previous week';
|
||||||
$labels['thismonth'] = 'This month';
|
$labels['thismonth'] = 'This month';
|
||||||
$labels['nextmonth'] = 'Next month';
|
$labels['nextmonth'] = 'Next month';
|
||||||
$labels['weekofyear'] = 'Week';
|
$labels['weekofyear'] = 'Week';
|
||||||
|
@ -140,6 +146,7 @@ $labels['onlyworkinghours'] = 'Find availability within my working hours';
|
||||||
$labels['reqallattendees'] = 'Required/all participants';
|
$labels['reqallattendees'] = 'Required/all participants';
|
||||||
$labels['prevslot'] = 'Previous Slot';
|
$labels['prevslot'] = 'Previous Slot';
|
||||||
$labels['nextslot'] = 'Next Slot';
|
$labels['nextslot'] = 'Next Slot';
|
||||||
|
$labels['suggestedslot'] = 'Suggested Slot';
|
||||||
$labels['noslotfound'] = 'Unable to find a free time slot';
|
$labels['noslotfound'] = 'Unable to find a free time slot';
|
||||||
$labels['invitationsubject'] = 'You\'ve been invited to "$title"';
|
$labels['invitationsubject'] = 'You\'ve been invited to "$title"';
|
||||||
$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with all the event details which you can import to your calendar application.";
|
$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with all the event details which you can import to your calendar application.";
|
||||||
|
@ -232,4 +239,16 @@ $labels['birthdayscalendarsources'] = 'From these address books';
|
||||||
$labels['birthdayeventtitle'] = '$name\'s Birthday';
|
$labels['birthdayeventtitle'] = '$name\'s Birthday';
|
||||||
$labels['birthdayage'] = 'Age $age';
|
$labels['birthdayage'] = 'Age $age';
|
||||||
|
|
||||||
|
// (hidden) titles and labels for accessibility annotations
|
||||||
|
$labels['arialabelminical'] = 'Calendar date selection';
|
||||||
|
$labels['arialabelcalendarview'] = 'Calendar view';
|
||||||
|
$labels['arialabelsearchform'] = 'Event search form';
|
||||||
|
$labels['arialabelquicksearchbox'] = 'Event search input';
|
||||||
|
$labels['arialabelcalsearchform'] = 'Calendars search form';
|
||||||
|
$labels['calendaractions'] = 'Calendar actions';
|
||||||
|
$labels['arialabeleventattendees'] = 'Event participants list';
|
||||||
|
$labels['arialabeleventresources'] = 'Event resources list';
|
||||||
|
$labels['arialabelresourcesearchform'] = 'Resources search form';
|
||||||
|
$labels['arialabelresourceselection'] = 'Available resources';
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -85,6 +85,14 @@ body.attachmentwin #topnav .topright {
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d9f1fb', endColorstr='#c5e3ee', GradientType=0);
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d9f1fb', endColorstr='#c5e3ee', GradientType=0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#datepicker .ui-datepicker-days-cell-over a.ui-state-default {
|
||||||
|
color: #fff;
|
||||||
|
border-color: #2fa0c0;
|
||||||
|
background: rgba(73,180,210,0.6);
|
||||||
|
text-shadow: 0px 1px 1px #666;
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
#datepicker .ui-datepicker-activerange a.ui-state-active {
|
#datepicker .ui-datepicker-activerange a.ui-state-active {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #00acd4;
|
background: #00acd4;
|
||||||
|
@ -265,12 +273,19 @@ pre {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendars .treelist div:hover > a.subscribed {
|
#calendars .treelist div > a.subscribed:focus {
|
||||||
background-position: 1px -110px;
|
border-radius: 3px;
|
||||||
|
outline: 2px solid rgba(30,150,192, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendars .treelist div.subscribed a.subscribed {
|
#calendars .treelist div:hover > a.subscribed,
|
||||||
background-position: -15px -110px;
|
#calendars .treelist div > a.subscribed:focus {
|
||||||
|
background-position: 0 -110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#calendars .treelist div.subscribed a.subscribed,
|
||||||
|
#calendars .treelist div.subscribed a.subscribed:focus {
|
||||||
|
background-position: -16px -110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendars .treelist li input {
|
#calendars .treelist li input {
|
||||||
|
@ -420,7 +435,7 @@ pre {
|
||||||
}
|
}
|
||||||
|
|
||||||
body.calendarmain #quicksearchbar {
|
body.calendarmain #quicksearchbar {
|
||||||
z-index: 200;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.calendarmain #searchmenulink {
|
body.calendarmain #searchmenulink {
|
||||||
|
@ -600,7 +615,7 @@ a.miniColors-trigger {
|
||||||
.calendarmain .fc-view-table td.fc-list-header,
|
.calendarmain .fc-view-table td.fc-list-header,
|
||||||
#attendees-freebusy-table h3.boxtitle,
|
#attendees-freebusy-table h3.boxtitle,
|
||||||
#schedule-freebusy-times thead th,
|
#schedule-freebusy-times thead th,
|
||||||
.edit-attendees-table thead td
|
.edit-attendees-table thead th
|
||||||
{
|
{
|
||||||
color: #69939e;
|
color: #69939e;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
@ -614,6 +629,7 @@ a.miniColors-trigger {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
padding: 8px 7px 3px 7px;
|
padding: 8px 7px 3px 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,21 +791,26 @@ td.topalign {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-attendees-table th.role,
|
||||||
.edit-attendees-table td.role {
|
.edit-attendees-table td.role {
|
||||||
width: 9em;
|
width: 9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-attendees-table th.availability,
|
||||||
.edit-attendees-table td.availability,
|
.edit-attendees-table td.availability,
|
||||||
|
.edit-attendees-table th.confirmstate,
|
||||||
.edit-attendees-table td.confirmstate {
|
.edit-attendees-table td.confirmstate {
|
||||||
width: 4em;
|
width: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-attendees-table th.options,
|
||||||
.edit-attendees-table td.options {
|
.edit-attendees-table td.options {
|
||||||
width: 3em;
|
width: 3em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-attendees-table th.name,
|
||||||
.edit-attendees-table td.name {
|
.edit-attendees-table td.name {
|
||||||
width: auto;
|
width: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -1120,7 +1141,7 @@ a.dropdown-link:after {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
z-index: 200;
|
z-index: 10;
|
||||||
padding: 4px 5px;
|
padding: 4px 5px;
|
||||||
border: 1px solid #c3c3c3;
|
border: 1px solid #c3c3c3;
|
||||||
border-top-color: #ddd;
|
border-top-color: #ddd;
|
||||||
|
@ -1376,11 +1397,21 @@ a.dropdown-link:after {
|
||||||
-o-box-shadow: none;
|
-o-box-shadow: none;
|
||||||
-webkit-box-shadow: none;
|
-webkit-box-shadow: none;
|
||||||
-moz-box-shadow: none;
|
-moz-box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendarmain .fc-header-left .fc-button:focus {
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0px 1px 1px #666;
|
||||||
|
background-color: rgba(30,150,192, 0.5);
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button.fc-state-active {
|
.calendarmain .fc-header-left .fc-button.fc-state-active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #222;
|
color: #222;
|
||||||
|
text-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-agendaDay {
|
.calendarmain .fc-header-left .fc-button-agendaDay {
|
||||||
|
@ -1428,6 +1459,13 @@ a.dropdown-link:after {
|
||||||
font-size: 1em !important;
|
font-size: 1em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendarmain .fc-event:focus {
|
||||||
|
outline: 1px solid rgba(71,135,177, 0.4);
|
||||||
|
-webkit-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
|
||||||
|
-moz-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
|
||||||
|
-o-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
|
||||||
|
box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
|
||||||
|
}
|
||||||
.fc-event-title {
|
.fc-event-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,6 +269,10 @@ html .fc,
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-event:focus {
|
||||||
|
outline: 2px solid ActiveBorder;
|
||||||
|
}
|
||||||
|
|
||||||
a.fc-event {
|
a.fc-event {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,12 @@
|
||||||
|
|
||||||
<roundcube:include file="/includes/header.html" />
|
<roundcube:include file="/includes/header.html" />
|
||||||
|
|
||||||
|
<h1 class="voice"><roundcube:label name="calendar.calendar" /></h1>
|
||||||
|
|
||||||
<div id="mainscreen">
|
<div id="mainscreen">
|
||||||
<div id="calendarsidebar">
|
<div id="calendarsidebar">
|
||||||
<div id="calendartoolbar" class="toolbar">
|
<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
|
||||||
|
<div id="calendartoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
|
||||||
<roundcube:button command="addevent" type="link" class="button addevent disabled" classAct="button addevent" classSel="button addevent pressed" label="calendar.new_event" title="calendar.new_event" />
|
<roundcube:button command="addevent" type="link" class="button addevent disabled" classAct="button addevent" classSel="button addevent pressed" label="calendar.new_event" title="calendar.new_event" />
|
||||||
<roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="calendar.print" title="calendar.printtitle" />
|
<roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="calendar.print" title="calendar.printtitle" />
|
||||||
<roundcube:button command="events-import" type="link" class="button import disabled" classAct="button import" classSel="button import pressed" label="import" title="calendar.importevents" />
|
<roundcube:button command="events-import" type="link" class="button import disabled" classAct="button import" classSel="button import pressed" label="import" title="calendar.importevents" />
|
||||||
|
@ -19,35 +22,41 @@
|
||||||
<roundcube:container name="toolbar" id="calendartoolbar" />
|
<roundcube:container name="toolbar" id="calendartoolbar" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="datepicker" class="uibox"></div>
|
<h2 id="aria-label-minical" class="voice"><roundcube:label name="calendar.arialabelminical" /></h2>
|
||||||
|
<div id="datepicker" class="uibox" role="presentation"></div>
|
||||||
|
|
||||||
<div id="calendars" class="uibox listbox" style="visibility:hidden">
|
<div id="calendars" class="uibox listbox" style="visibility:hidden" role="navigation" aria-labelledby="aria-label-calendarlist">
|
||||||
<h2 class="boxtitle"><roundcube:label name="calendar.calendars" />
|
<h2 class="boxtitle" id="aria-label-calendarlist"><roundcube:label name="calendar.calendars" />
|
||||||
<a class="iconbutton search" title="<roundcube:label name='calendar.findcalendars' />"></a>
|
<a href="#calendars" class="iconbutton search" title="<roundcube:label name='calendar.findcalendars' />" tabindex="0"><roundcube:label name='calendar.findcalendars' /></a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="listsearchbox">
|
<div class="listsearchbox">
|
||||||
<div class="searchbox">
|
<div class="searchbox" role="search" aria-labelledby="aria-label-calsearchform" aria-controls="calendarslist">
|
||||||
|
<h3 id="aria-label-calsearchform" class="voice"><roundcube:label name="calendar.arialabelcalsearchform" /></h3>
|
||||||
|
<label for="calendarlistsearch" class="voice"><roundcube:label name="calendar.searchterms" /></label>
|
||||||
<input type="text" name="q" id="calendarlistsearch" placeholder="<roundcube:label name='calendar.findcalendars' />" />
|
<input type="text" name="q" id="calendarlistsearch" placeholder="<roundcube:label name='calendar.findcalendars' />" />
|
||||||
<a class="iconbutton searchicon"></a>
|
<a class="iconbutton searchicon"></a>
|
||||||
<roundcube:button command="reset-listsearch" id="calendarlistsearch-reset" class="iconbutton reset" title="resetsearch" content="x" />
|
<roundcube:button command="reset-listsearch" id="calendarlistsearch-reset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroller withfooter">
|
<div class="scroller withfooter">
|
||||||
<roundcube:object name="plugin.calendar_list" id="calendarslist" class="treelist listing" />
|
<roundcube:object name="plugin.calendar_list" id="calendarslist" class="treelist listing" />
|
||||||
</div>
|
</div>
|
||||||
<div class="boxfooter">
|
<div class="boxfooter">
|
||||||
<roundcube:button command="calendar-create" type="link" title="calendar.createcalendar" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="calendaroptionslink" id="calendaroptionsmenulink" type="link" title="moreactions" class="listbutton groupactions" onclick="UI.show_popup('calendaroptionsmenu', undefined, { above:true });return false" innerClass="inner" content="⚙" />
|
<roundcube:button command="calendar-create" type="link" title="calendar.createcalendar" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="calendaroptionslink" id="calendaroptionsmenulink" type="link" title="moreactions" class="listbutton groupactions" onclick="return UI.toggle_popup('calendaroptionsmenu', event, { above:true })" innerClass="inner" label="calendar.calendaractions" aria-haspopup="true" aria-expanded="false" aria-owns="calendaroptionsmenu-menu" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="quicksearchbar">
|
<div id="quicksearchbar" class="searchbox" role="search" aria-labelledby="aria-label-searchform">
|
||||||
|
<h2 id="aria-label-searchform" class="voice"><roundcube:label name="calendar.arialabelsearchform" /></h2>
|
||||||
|
<label for="quicksearchbox" class="voice"><roundcube:label name="calendar.arialabelquicksearchbox" /></label>
|
||||||
<roundcube:object name="plugin.searchform" id="quicksearchbox" />
|
<roundcube:object name="plugin.searchform" id="quicksearchbox" />
|
||||||
<a id="searchmenulink" class="iconbutton searchoptions" > </a>
|
<a id="searchmenulink" class="iconbutton searchoptions" tabindex="-1"> </a>
|
||||||
<roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
|
<roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="calendar">
|
<h2 id="aria-label-calendarview" class="voice"><roundcube:label name="calendar.arialabelcalendarview" /></h2>
|
||||||
|
<div id="calendar" role="main" aria-labelledby="aria-label-calendarview">
|
||||||
<roundcube:object name="plugin.angenda_options" class="boxfooter" id="agendaoptions" />
|
<roundcube:object name="plugin.angenda_options" class="boxfooter" id="agendaoptions" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,18 +65,19 @@
|
||||||
|
|
||||||
<roundcube:object name="message" id="messagestack" />
|
<roundcube:object name="message" id="messagestack" />
|
||||||
|
|
||||||
<div id="calendaroptionsmenu" class="popupmenu">
|
<div id="calendaroptionsmenu" class="popupmenu" aria-hidden="true">
|
||||||
<ul class="toolbarmenu">
|
<h3 id="aria-label-calendaroptions" class="voice"><roundcube:label name="calendar.calendaractions" /></h3>
|
||||||
<li><roundcube:button command="calendar-edit" label="calendar.edit" classAct="active" /></li>
|
<ul id="calendaroptionsmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-calendaroptions">
|
||||||
<li><roundcube:button command="calendar-remove" label="calendar.remove" classAct="active" /></li>
|
<li role="menuitem"><roundcube:button command="calendar-edit" label="calendar.edit" classAct="active" /></li>
|
||||||
<li><roundcube:button command="calendar-showurl" label="calendar.showurl" classAct="active" /></li>
|
<li role="menuitem"><roundcube:button command="calendar-remove" label="calendar.remove" classAct="active" /></li>
|
||||||
|
<li role="menuitem"><roundcube:button command="calendar-showurl" label="calendar.showurl" classAct="active" /></li>
|
||||||
<roundcube:if condition="env:calendar_driver == 'kolab'" />
|
<roundcube:if condition="env:calendar_driver == 'kolab'" />
|
||||||
<li class="separator_above"><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li>
|
<li role="menuitem"><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li>
|
||||||
<roundcube:endif />
|
<roundcube:endif />
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="eventshow" class="uidialog">
|
<div id="eventshow" class="uidialog" aria-hidden="true">
|
||||||
<h1 id="event-title">Event Title</h1>
|
<h1 id="event-title">Event Title</h1>
|
||||||
<div class="event-section" id="event-location">Location</div>
|
<div class="event-section" id="event-location">Location</div>
|
||||||
<div class="event-section" id="event-date">From-To</div>
|
<div class="event-section" id="event-date">From-To</div>
|
||||||
|
@ -125,14 +135,17 @@
|
||||||
|
|
||||||
<roundcube:include file="/templates/eventedit.html" />
|
<roundcube:include file="/templates/eventedit.html" />
|
||||||
|
|
||||||
<div id="eventresourcesdialog" class="uidialog">
|
<div id="eventresourcesdialog" class="uidialog" aria-hidden="true">
|
||||||
<div id="resource-dialog-left">
|
<div id="resource-dialog-left">
|
||||||
<div id="resource-selection" class="uibox listbox">
|
<div id="resource-selection" class="uibox listbox" role="navigation" aria-labelledby="aria-label-resourceselection">
|
||||||
|
<h2 class="voice" id="aria-label-resourceselection"><roundcube:label name="calendar.arialabelresourceselection" /></h2>
|
||||||
<div id="resourcequicksearch">
|
<div id="resourcequicksearch">
|
||||||
<div class="searchbox">
|
<div class="searchbox" role="search" aria-labelledby="aria-label-resourcesearchform" aria-controls="resources-list">
|
||||||
|
<h3 id="aria-label-resourcesearchform" class="voice"><roundcube:label name="calendar.arialabelresourcesearchform" /></h3>
|
||||||
|
<label for="resourcesearchbox" class="voice"><roundcube:label name="calendar.searchterms" /></label>
|
||||||
<roundcube:object name="plugin.resources_searchform" id="resourcesearchbox" />
|
<roundcube:object name="plugin.resources_searchform" id="resourcesearchbox" />
|
||||||
<a id="resourcesearchmenulink" class="iconbutton searchoptions"> </a>
|
<a id="resourcesearchmenulink" class="iconbutton searchoptions"> </a>
|
||||||
<roundcube:button command="reset-resource-search" id="resourcesearchreset" class="iconbutton reset" title="resetsearch" content=" " />
|
<roundcube:button command="reset-resource-search" id="resourcesearchreset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroller">
|
<div class="scroller">
|
||||||
|
@ -142,25 +155,25 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="resource-dialog-right">
|
<div id="resource-dialog-right">
|
||||||
<div id="resource-info" class="uibox contentbox">
|
<div id="resource-info" class="uibox contentbox" role="region" aria-labelledby="aria-label-resourcedetails">
|
||||||
<h2 class="boxtitle"><roundcube:label name="calendar.resourcedetails" /></h2>
|
<h2 class="boxtitle" id="aria-label-resourcedetails"><roundcube:label name="calendar.resourcedetails" /></h2>
|
||||||
<div class="scroller">
|
<div class="scroller">
|
||||||
<roundcube:object name="plugin.resource_info" id="resource-details" class="propform" />
|
<roundcube:object name="plugin.resource_info" id="resource-details" class="propform" aria-live="polite" aria-relevant="text" aria-atomic="true" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="resource-availability" class="uibox contentbox">
|
<div id="resource-availability" class="uibox contentbox" role="region" aria-labelledby="aria-label-resourceavailability">
|
||||||
<h2 class="boxtitle"><roundcube:label name="calendar.resourceavailability" /></h2>
|
<h2 class="boxtitle" id="aria-label-resourceavailability"><roundcube:label name="calendar.resourceavailability" /></h2>
|
||||||
<roundcube:object name="plugin.resource_calendar" id="resource-freebusy-calendar" />
|
<roundcube:object name="plugin.resource_calendar" id="resource-freebusy-calendar" />
|
||||||
<div class="boxpagenav">
|
<div class="boxpagenav">
|
||||||
<roundcube:button name="resource-cal-prev" id="resource-calendar-prev" type="link" class="icon prevpage" title="calendar.prevslot" content="&lt;" />
|
<roundcube:button name="resource-cal-prev" id="resource-calendar-prev" type="link" class="icon prevpage" title="calendar.prevslot" label="calendar.prevweek" />
|
||||||
<roundcube:button name="resource-cal-next" id="resource-calendar-next" type="link" class="icon nextpage" title="calendar.nextslot" content="&gt;" />
|
<roundcube:button name="resource-cal-next" id="resource-calendar-next" type="link" class="icon nextpage" title="calendar.nextslot" label="calendar.nextweek" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="eventfreebusy" class="uidialog">
|
<div id="eventfreebusy" class="uidialog" aria-hidden="true">
|
||||||
<roundcube:object name="plugin.attendees_freebusy_table" id="attendees-freebusy-table" cellpadding="0" />
|
<roundcube:object name="plugin.attendees_freebusy_table" id="attendees-freebusy-table" cellpadding="0" />
|
||||||
|
|
||||||
<div class="schedule-options">
|
<div class="schedule-options">
|
||||||
|
@ -203,7 +216,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="calendarform" class="uidialog">
|
<div id="calendarform" class="uidialog" aria-hidden="true">
|
||||||
<roundcube:label name="loading" />
|
<roundcube:label name="loading" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -262,6 +275,8 @@ $(document).ready(function(e){
|
||||||
// TODO: save state in localStorage
|
// TODO: save state in localStorage
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -275,8 +290,8 @@ function calendarview_splitter(p)
|
||||||
this.collapsed = false;
|
this.collapsed = false;
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
this.threshold = 80;
|
this.threshold = 80;
|
||||||
this.lastpos = 0;
|
this.lastpos = -1;
|
||||||
this._lastpos = 0;
|
this._lastpos = -1;
|
||||||
this._min = p.min;
|
this._min = p.min;
|
||||||
|
|
||||||
var me = this;
|
var me = this;
|
||||||
|
@ -316,6 +331,9 @@ function calendarview_splitter(p)
|
||||||
this.p1.resize();
|
this.p1.resize();
|
||||||
this.lastpos = this.pos;
|
this.lastpos = this.pos;
|
||||||
|
|
||||||
|
if (this._lastpos == -1)
|
||||||
|
this._lastpos = this.pos;
|
||||||
|
|
||||||
// also resize iframe covers
|
// also resize iframe covers
|
||||||
if (this.drag_active) {
|
if (this.drag_active) {
|
||||||
$('iframe').each(function(i, elem) {
|
$('iframe').each(function(i, elem) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div id="eventedit" class="uidialog uidialog-tabbed">
|
<div id="eventedit" class="uidialog uidialog-tabbed" aria-hidden="true">
|
||||||
<form id="eventtabs" action="#" method="post" enctype="multipart/form-data">
|
<form id="eventtabs" action="#" method="post" enctype="multipart/form-data">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#event-panel-summary"><roundcube:label name="calendar.tabsummary" /></a></li><li id="edit-tab-recurrence"><a href="#event-panel-recurrence"><roundcube:label name="calendar.tabrecurrence" /></a></li><li id="edit-tab-attendees"><a href="#event-panel-attendees"><roundcube:label name="calendar.tabattendees" /></a></li><li id="edit-tab-resources"><a href="#event-panel-resources"><roundcube:label name="calendar.tabresources" /></a></li><li id="edit-tab-attachments"><a href="#event-panel-attachments"><roundcube:label name="calendar.tabattachments" /></a></li>
|
<li><a href="#event-panel-summary"><roundcube:label name="calendar.tabsummary" /></a></li><li id="edit-tab-recurrence"><a href="#event-panel-recurrence"><roundcube:label name="calendar.tabrecurrence" /></a></li><li id="edit-tab-attendees"><a href="#event-panel-attendees"><roundcube:label name="calendar.tabattendees" /></a></li><li id="edit-tab-resources"><a href="#event-panel-resources"><roundcube:label name="calendar.tabresources" /></a></li><li id="edit-tab-attachments"><a href="#event-panel-attachments"><roundcube:label name="calendar.tabattachments" /></a></li>
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
<div class="event-section">
|
<div class="event-section">
|
||||||
<label for="edit-title"><roundcube:label name="calendar.title" /></label>
|
<label for="edit-title"><roundcube:label name="calendar.title" /></label>
|
||||||
<br />
|
<br />
|
||||||
<input type="text" class="text" name="title" id="edit-title" size="40" />
|
<input type="text" class="text" name="title" id="edit-title" size="40" required="true" />
|
||||||
</div>
|
</div>
|
||||||
<div class="event-section">
|
<div class="event-section">
|
||||||
<label for="edit-location"><roundcube:label name="calendar.location" /></label>
|
<label for="edit-location"><roundcube:label name="calendar.location" /></label>
|
||||||
|
@ -28,21 +28,21 @@
|
||||||
<div class="event-section">
|
<div class="event-section">
|
||||||
<label style="float:right;padding-right:0.5em"><input type="checkbox" name="allday" id="edit-allday" value="1" /><roundcube:label name="calendar.all-day" /></label>
|
<label style="float:right;padding-right:0.5em"><input type="checkbox" name="allday" id="edit-allday" value="1" /><roundcube:label name="calendar.all-day" /></label>
|
||||||
<label for="edit-startdate"><roundcube:label name="calendar.start" /></label>
|
<label for="edit-startdate"><roundcube:label name="calendar.start" /></label>
|
||||||
<input type="text" name="startdate" size="11" id="edit-startdate" />
|
<input type="text" name="startdate" size="11" id="edit-startdate" required="true" />
|
||||||
<input type="text" name="starttime" size="6" id="edit-starttime" />
|
<input type="text" name="starttime" size="6" id="edit-starttime" aria-label="<roundcube:label name='calendar.starttime' />" />
|
||||||
</div>
|
</div>
|
||||||
<div class="event-section">
|
<div class="event-section">
|
||||||
<label for="edit-enddate"><roundcube:label name="calendar.end" /></label>
|
<label for="edit-enddate"><roundcube:label name="calendar.end" /></label>
|
||||||
<input type="text" name="enddate" size="11" id="edit-enddate" />
|
<input type="text" name="enddate" size="11" id="edit-enddate" required="true" />
|
||||||
<input type="text" name="endtime" size="6" id="edit-endtime" />
|
<input type="text" name="endtime" size="6" id="edit-endtime" aria-label="<roundcube:label name='calendar.endtime' />" />
|
||||||
</div>
|
</div>
|
||||||
<div class="event-section" id="edit-alarms">
|
<div class="event-section" id="edit-alarms">
|
||||||
<div class="edit-alarm-item first">
|
<div class="edit-alarm-item first">
|
||||||
<label><roundcube:label name="calendar.alarms" /></label>
|
<label for="edit-alarm-item"><roundcube:label name="calendar.alarms" /></label>
|
||||||
<roundcube:object name="plugin.alarm_select" />
|
<roundcube:object name="plugin.alarm_select" id="edit-alarm-item" />
|
||||||
<span class="edit-alarm-buttons">
|
<span class="edit-alarm-buttons">
|
||||||
<a href="#add" class="iconbutton add add-alarm">+</a>
|
<a href="#add" class="iconbutton add add-alarm"><roundcube:label name="libcalendaring.addalarm" /></a>
|
||||||
<a href="#delete" class="iconbutton remove delete-alarm">-</a>
|
<a href="#delete" class="iconbutton remove delete-alarm"><roundcube:label name="libcalendaring.removealarm" /></a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,13 +97,15 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- attendees list -->
|
<!-- attendees list -->
|
||||||
<div id="event-panel-attendees">
|
<div id="event-panel-attendees">
|
||||||
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="records-table edit-attendees-table" coltitle="attendee" />
|
<h3 id="aria-label-attendeestable" class="voice"><roundcube:label name="calendar.arialabeleventattendees" /></h3>
|
||||||
|
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="records-table edit-attendees-table" coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
|
||||||
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
|
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
|
||||||
<roundcube:include file="/templates/freebusylegend.html" />
|
<roundcube:include file="/templates/freebusylegend.html" />
|
||||||
</div>
|
</div>
|
||||||
<!-- resources list -->
|
<!-- resources list -->
|
||||||
<div id="event-panel-resources">
|
<div id="event-panel-resources">
|
||||||
<roundcube:object name="plugin.attendees_list" id="edit-resources-table" class="records-table edit-attendees-table" coltitle="resource" />
|
<h3 id="aria-label-resourcestable" class="voice"><roundcube:label name="calendar.arialabeleventresources" /></h3>
|
||||||
|
<roundcube:object name="plugin.attendees_list" id="edit-resources-table" class="records-table edit-attendees-table" coltitle="resource" aria-labelledby="aria-label-resourcestable" />
|
||||||
<roundcube:object name="plugin.resources_form" id="edit-resources-form" />
|
<roundcube:object name="plugin.resources_form" id="edit-resources-form" />
|
||||||
<roundcube:include file="/templates/freebusylegend.html" />
|
<roundcube:include file="/templates/freebusylegend.html" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -112,7 +114,8 @@
|
||||||
<div id="edit-attachments">
|
<div id="edit-attachments">
|
||||||
<roundcube:object name="plugin.attachments_list" id="attachment-list" class="attachmentslist" />
|
<roundcube:object name="plugin.attachments_list" id="attachment-list" class="attachmentslist" />
|
||||||
</div>
|
</div>
|
||||||
<div id="edit-attachments-form">
|
<div id="edit-attachments-form" role="region" aria-labelledby="aria-label-attachmentuploadform">
|
||||||
|
<h3 id="aria-label-attachmentuploadform" class="voice"><roundcube:label name="arialabelattachmentuploadform" /></h2>
|
||||||
<roundcube:object name="plugin.attachments_form" id="calendar-attachment-form" attachmentFieldSize="30" />
|
<roundcube:object name="plugin.attachments_form" id="calendar-attachment-form" attachmentFieldSize="30" />
|
||||||
</div>
|
</div>
|
||||||
<roundcube:object name="plugin.filedroparea" id="event-panel-attachments" />
|
<roundcube:object name="plugin.filedroparea" id="event-panel-attachments" />
|
||||||
|
|
|
@ -68,25 +68,26 @@ function rcube_libcalendaring(settings)
|
||||||
/**
|
/**
|
||||||
* Create a nice human-readable string for the date/time range
|
* Create a nice human-readable string for the date/time range
|
||||||
*/
|
*/
|
||||||
this.event_date_text = function(event)
|
this.event_date_text = function(event, voice)
|
||||||
{
|
{
|
||||||
if (!event.start)
|
if (!event.start)
|
||||||
return '';
|
return '';
|
||||||
if (!event.end)
|
if (!event.end)
|
||||||
event.end = event.start;
|
event.end = event.start;
|
||||||
|
|
||||||
var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000;
|
var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000,
|
||||||
|
until = voice ? ' ' + rcmail.gettext('until','libcalendaring') + ' ' : ' — ';
|
||||||
if (event.allDay) {
|
if (event.allDay) {
|
||||||
fromto = this.format_datetime(event.start, 1)
|
fromto = this.format_datetime(event.start, 1, voice)
|
||||||
+ (duration > 86400 || event.start.getDay() != event.end.getDay() ? ' — ' + this.format_datetime(event.end, 1) : '');
|
+ (duration > 86400 || event.start.getDay() != event.end.getDay() ? until + this.format_datetime(event.end, 1, voice) : '');
|
||||||
}
|
}
|
||||||
else if (duration < 86400 && event.start.getDay() == event.end.getDay()) {
|
else if (duration < 86400 && event.start.getDay() == event.end.getDay()) {
|
||||||
fromto = this.format_datetime(event.start, 0)
|
fromto = this.format_datetime(event.start, 0, voice)
|
||||||
+ (duration > 0 ? ' — ' + this.format_datetime(event.end, 2) : '');
|
+ (duration > 0 ? until + this.format_datetime(event.end, 2, voice) : '');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fromto = this.format_datetime(event.start, 0)
|
fromto = this.format_datetime(event.start, 0, voice)
|
||||||
+ (duration > 0 ? ' — ' + this.format_datetime(event.end, 0) : '');
|
+ (duration > 0 ? until + this.format_datetime(event.end, 0, voice) : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
return fromto;
|
return fromto;
|
||||||
|
@ -178,15 +179,18 @@ function rcube_libcalendaring(settings)
|
||||||
/**
|
/**
|
||||||
* Format the given date object according to user's prefs
|
* Format the given date object according to user's prefs
|
||||||
*/
|
*/
|
||||||
this.format_datetime = function(date, mode)
|
this.format_datetime = function(date, mode, voice)
|
||||||
{
|
{
|
||||||
var res = '';
|
var res = '';
|
||||||
if (!mode || mode == 1)
|
if (!mode || mode == 1) {
|
||||||
res += $.datepicker.formatDate(datepicker_settings.dateFormat, date, datepicker_settings);
|
res += $.datepicker.formatDate(voice ? 'MM d yy' : datepicker_settings.dateFormat, date, datepicker_settings);
|
||||||
if (!mode)
|
}
|
||||||
res += ' ';
|
if (!mode) {
|
||||||
if (!mode || mode == 2)
|
res += voice ? ' ' + rcmail.gettext('at','libcalendaring') + ' ' : ' ';
|
||||||
res += this.format_time(date);
|
}
|
||||||
|
if (!mode || mode == 2) {
|
||||||
|
res += this.format_time(date, voice);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +198,7 @@ function rcube_libcalendaring(settings)
|
||||||
/**
|
/**
|
||||||
* Clone from fullcalendar.js
|
* Clone from fullcalendar.js
|
||||||
*/
|
*/
|
||||||
this.format_time = function(date)
|
this.format_time = function(date, voice)
|
||||||
{
|
{
|
||||||
var zeroPad = function(n) { return (n < 10 ? '0' : '') + n; }
|
var zeroPad = function(n) { return (n < 10 ? '0' : '') + n; }
|
||||||
var formatters = {
|
var formatters = {
|
||||||
|
@ -212,7 +216,8 @@ function rcube_libcalendaring(settings)
|
||||||
TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }
|
TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }
|
||||||
};
|
};
|
||||||
|
|
||||||
var i, i2, c, formatter, res = '', format = settings['time_format'];
|
var i, i2, c, formatter, res = '',
|
||||||
|
format = voice ? settings['time_format'].replace(':',' ').replace('HH','H').replace('hh','h').replace('mm','m').replace('ss','s') : settings['time_format'];
|
||||||
for (i=0; i < format.length; i++) {
|
for (i=0; i < format.length; i++) {
|
||||||
c = format.charAt(i);
|
c = format.charAt(i);
|
||||||
for (i2=Math.min(i+2, format.length); i2 > i; i2--) {
|
for (i2=Math.min(i+2, format.length); i2 > i; i2--) {
|
||||||
|
@ -316,10 +321,13 @@ function rcube_libcalendaring(settings)
|
||||||
.replace(/\n/g, "<br/>");
|
.replace(/\n/g, "<br/>");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.init_alarms_edit = function(prefix)
|
this.init_alarms_edit = function(prefix, index)
|
||||||
{
|
{
|
||||||
|
var edit_type = $(prefix+' select.edit-alarm-type'),
|
||||||
|
dom_id = edit_type.attr('id');
|
||||||
|
|
||||||
// register events on alarm fields
|
// register events on alarm fields
|
||||||
$(prefix+' select.edit-alarm-type').change(function(){
|
edit_type.change(function(){
|
||||||
$(this).parent().find('span.edit-alarm-values')[(this.selectedIndex>0?'show':'hide')]();
|
$(this).parent().find('span.edit-alarm-values')[(this.selectedIndex>0?'show':'hide')]();
|
||||||
});
|
});
|
||||||
$(prefix+' select.edit-alarm-offset').change(function(){
|
$(prefix+' select.edit-alarm-offset').change(function(){
|
||||||
|
@ -337,13 +345,20 @@ function rcube_libcalendaring(settings)
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// set a unique id attribute and set label reference accordingly
|
||||||
|
if ((index || 0) > 0 && dom_id) {
|
||||||
|
dom_id += ':' + (new Date().getTime());
|
||||||
|
edit_type.attr('id', dom_id);
|
||||||
|
$(prefix+' label:first').attr('for', dom_id);
|
||||||
|
}
|
||||||
|
|
||||||
$(prefix).on('click', 'a.add-alarm', function(e){
|
$(prefix).on('click', 'a.add-alarm', function(e){
|
||||||
var i = $(this).closest('.edit-alarm-item').siblings().length + 1;
|
var i = $(this).closest('.edit-alarm-item').siblings().length + 1;
|
||||||
var item = $(this).closest('.edit-alarm-item').clone(false)
|
var item = $(this).closest('.edit-alarm-item').clone(false)
|
||||||
.removeClass('first')
|
.removeClass('first')
|
||||||
.appendTo(prefix);
|
.appendTo(prefix);
|
||||||
|
|
||||||
me.init_alarms_edit(prefix + ' .edit-alarm-item:eq(' + i + ')');
|
me.init_alarms_edit(prefix + ' .edit-alarm-item:eq(' + i + ')', i);
|
||||||
$('select.edit-alarm-type, select.edit-alarm-offset', item).change();
|
$('select.edit-alarm-type, select.edit-alarm-offset', item).change();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -364,7 +379,7 @@ function rcube_libcalendaring(settings)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
domnode = $(prefix + ' .edit-alarm-item').eq(0).clone(false).removeClass('first').appendTo(prefix);
|
domnode = $(prefix + ' .edit-alarm-item').eq(0).clone(false).removeClass('first').appendTo(prefix);
|
||||||
this.init_alarms_edit(prefix + ' .edit-alarm-item:eq(' + i + ')');
|
this.init_alarms_edit(prefix + ' .edit-alarm-item:eq(' + i + ')', i);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('select.edit-alarm-type', domnode).val(alarm.action);
|
$('select.edit-alarm-type', domnode).val(alarm.action);
|
||||||
|
|
|
@ -288,7 +288,7 @@ class libcalendaring extends rcube_plugin
|
||||||
public function alarm_select($attrib, $alarm_types, $absolute_time = true)
|
public function alarm_select($attrib, $alarm_types, $absolute_time = true)
|
||||||
{
|
{
|
||||||
unset($attrib['name']);
|
unset($attrib['name']);
|
||||||
$select_type = new html_select(array('name' => 'alarmtype[]', 'class' => 'edit-alarm-type'));
|
$select_type = new html_select(array('name' => 'alarmtype[]', 'class' => 'edit-alarm-type', 'id' => $attrib['id']));
|
||||||
$select_type->add($this->gettext('none'), '');
|
$select_type->add($this->gettext('none'), '');
|
||||||
foreach ($alarm_types as $type)
|
foreach ($alarm_types as $type)
|
||||||
$select_type->add($this->gettext(strtolower("alarm{$type}option")), $type);
|
$select_type->add($this->gettext(strtolower("alarm{$type}option")), $type);
|
||||||
|
@ -991,6 +991,7 @@ class libcalendaring extends rcube_plugin
|
||||||
'class' => 'delete',
|
'class' => 'delete',
|
||||||
'onclick' => sprintf("return %s.remove_from_attachment_list('rcmfile%s')", JS_OBJECT_NAME, $id),
|
'onclick' => sprintf("return %s.remove_from_attachment_list('rcmfile%s')", JS_OBJECT_NAME, $id),
|
||||||
'title' => $this->rc->gettext('delete'),
|
'title' => $this->rc->gettext('delete'),
|
||||||
|
'aria-label' => $this->rc->gettext('delete') . ' ' . $attachment['name'],
|
||||||
), $button);
|
), $button);
|
||||||
|
|
||||||
$content .= Q($attachment['name']);
|
$content .= Q($attachment['name']);
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
$labels = array();
|
$labels = array();
|
||||||
|
|
||||||
|
// words for spoken dates
|
||||||
|
$labels['until'] = 'until';
|
||||||
|
$labels['at'] = 'at';
|
||||||
|
|
||||||
// alarms related labels
|
// alarms related labels
|
||||||
$labels['alarmemail'] = 'Send Email';
|
$labels['alarmemail'] = 'Send Email';
|
||||||
$labels['alarmdisplay'] = 'Show message';
|
$labels['alarmdisplay'] = 'Show message';
|
||||||
|
@ -18,7 +22,8 @@ $labels['trigger+M'] = 'minutes after';
|
||||||
$labels['trigger+H'] = 'hours after';
|
$labels['trigger+H'] = 'hours after';
|
||||||
$labels['trigger+D'] = 'days after';
|
$labels['trigger+D'] = 'days after';
|
||||||
$labels['triggerattime'] = 'at time';
|
$labels['triggerattime'] = 'at time';
|
||||||
$labels['addalarm'] = 'add alarm';
|
$labels['addalarm'] = 'Add alarm';
|
||||||
|
$labels['removealarm'] = 'Remove alarm';
|
||||||
|
|
||||||
$labels['alarmtitle'] = 'Upcoming events';
|
$labels['alarmtitle'] = 'Upcoming events';
|
||||||
$labels['dismissall'] = 'Dismiss all';
|
$labels['dismissall'] = 'Dismiss all';
|
||||||
|
|
|
@ -46,8 +46,9 @@ function kolab_folderlist(node, p)
|
||||||
if (results.length) {
|
if (results.length) {
|
||||||
// create treelist widget to present the search results
|
// create treelist widget to present the search results
|
||||||
if (!search_results_widget) {
|
if (!search_results_widget) {
|
||||||
|
var list_id = (me.container.attr('id') || p.id_prefix || '0')
|
||||||
search_results_container = $('<div class="searchresults"></div>')
|
search_results_container = $('<div class="searchresults"></div>')
|
||||||
.html(p.search_title ? '<h2 class="boxtitle">' + p.search_title + '</h2>' : '')
|
.html(p.search_title ? '<h2 class="boxtitle" id="st:' + list_id + '">' + p.search_title + '</h2>' : '')
|
||||||
.insertAfter(me.container);
|
.insertAfter(me.container);
|
||||||
|
|
||||||
search_results_widget = new rcube_treelist_widget('<ul>', {
|
search_results_widget = new rcube_treelist_widget('<ul>', {
|
||||||
|
@ -55,7 +56,7 @@ function kolab_folderlist(node, p)
|
||||||
selectable: false
|
selectable: false
|
||||||
});
|
});
|
||||||
// copy classes from main list
|
// copy classes from main list
|
||||||
search_results_widget.container.addClass(me.container.attr('class'));
|
search_results_widget.container.addClass(me.container.attr('class')).attr('aria-labelledby', 'st:' + list_id);
|
||||||
|
|
||||||
// register click handler on search result's checkboxes to select the given item for listing
|
// register click handler on search result's checkboxes to select the given item for listing
|
||||||
search_results_widget.container
|
search_results_widget.container
|
||||||
|
@ -87,6 +88,11 @@ function kolab_folderlist(node, p)
|
||||||
else {
|
else {
|
||||||
li.remove();
|
li.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set focus to cloned checkbox
|
||||||
|
if (rcube_event.is_keyboard(e)) {
|
||||||
|
$(me.get_item(id, true)).find('input[type=checkbox]').first().focus();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +184,7 @@ function kolab_folderlist(node, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listsearch_request) {
|
if (listsearch_request) {
|
||||||
// ignore, let the currently runnung sequest finish
|
// ignore, let the currently running request finish
|
||||||
if (listsearch_request.query == search.query) {
|
if (listsearch_request.query == search.query) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -196,7 +202,10 @@ function kolab_folderlist(node, p)
|
||||||
postdata: { action:'search', q:search.query, source:'%s' },
|
postdata: { action:'search', q:search.query, source:'%s' },
|
||||||
lock: rcmail.display_message(rcmail.get_label('searching'), 'loading'),
|
lock: rcmail.display_message(rcmail.get_label('searching'), 'loading'),
|
||||||
onresponse: render_search_results,
|
onresponse: render_search_results,
|
||||||
whendone: function(e){ listsearch_request = null; }
|
whendone: function(data){
|
||||||
|
listsearch_request = null;
|
||||||
|
me.triggerEvent('search-complete', data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
listsearch_request = { id:reqid, query:search.query };
|
listsearch_request = { id:reqid, query:search.query };
|
||||||
|
|
Loading…
Add table
Reference in a new issue