Elastic: Partial support for calendar plugin

This commit is contained in:
Aleksander Machniak 2018-03-16 09:22:42 +01:00
parent 6f73df9bbd
commit 21c4b6a5bb
16 changed files with 1221 additions and 428 deletions

View file

@ -320,7 +320,11 @@ class calendar extends rcube_plugin
$this->rc->output->set_env('timezone', $this->timezone->getName());
$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('identities-selector', $this->ui->identity_select(array('id' => 'edit-identities-list', 'aria-label' => $this->gettext('roleorganizer'))));
$this->rc->output->set_env('identities-selector', $this->ui->identity_select(array(
'id' => 'edit-identities-list',
'aria-label' => $this->gettext('roleorganizer'),
'class' => 'form-control',
)));
$view = rcube_utils::get_input_value('view', rcube_utils::INPUT_GPC);
if (in_array($view, array('agendaWeek', 'agendaDay', 'month', 'table')))
@ -2665,8 +2669,8 @@ class calendar extends rcube_plugin
// render small agenda view for the respective day
if ($data['method'] == 'REQUEST' && !empty($data['date']) && $response['action'] == 'rsvp') {
$event_start = rcube_utils::anytodatetime($data['date']);
$day_start = new Datetime(gmdate('Y-m-d 00:00', $data['date']), $this->lib->timezone);
$day_end = new Datetime(gmdate('Y-m-d 23:59', $data['date']), $this->lib->timezone);
$day_start = new Datetime(gmdate('Y-m-d 00:00', $data['date']), $this->lib->timezone);
$day_end = new Datetime(gmdate('Y-m-d 23:59', $data['date']), $this->lib->timezone);
// get events on that day from the user's personal calendars
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
@ -2675,6 +2679,7 @@ class calendar extends rcube_plugin
$before = $after = array();
foreach ($events as $event) {
// TODO: skip events with free_busy == 'free' ?
if ($event['uid'] == $data['uid'] || $event['end'] < $day_start || $event['start'] > $day_end)
continue;

View file

@ -66,7 +66,7 @@ function rcube_calendar_ui(settings)
var freebusy_data = {};
var current_view = null;
var count_sources = [];
var exec_deferred = bw.ie6 ? 5 : 1;
var exec_deferred = 1;
var sensitivitylabels = { 'public':rcmail.gettext('public','calendar'), 'private':rcmail.gettext('private','calendar'), 'confidential':rcmail.gettext('confidential','calendar') };
var ui_loading = rcmail.set_busy(true, 'loading');
@ -548,6 +548,7 @@ function rcube_calendar_ui(settings)
if (!temp && calendar.editable && event.editable !== false) {
buttons.push({
text: rcmail.gettext('edit', 'calendar'),
'class': 'edit mainaction',
click: function() {
event_edit_dialog('edit', event);
}
@ -567,7 +568,8 @@ function rcube_calendar_ui(settings)
if (!buttons.length) {
buttons.push({
text: rcmail.gettext('close', 'calendar'),
click: function(){
'class': 'cancel',
click: function() {
$dialog.dialog('close');
}
});
@ -575,9 +577,9 @@ function rcube_calendar_ui(settings)
// open jquery UI dialog
$dialog.dialog({
modal: false,
resizable: !bw.ie6,
closeOnEscape: (!bw.ie6 && !bw.ie7), // disable for performance reasons
modal: true,
resizable: true,
closeOnEscape: true,
title: me.event_date_text(event),
open: function() {
$dialog.attr('aria-hidden', 'false');
@ -585,17 +587,19 @@ function rcube_calendar_ui(settings)
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
}, 5);
},
close: function() {
beforeClose: function(e) {
rcmail.command('menu-close', 'eventoptionsmenu', null, e);
},
close: function(e) {
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
rcmail.command('menu-close','eventoptionsmenu');
$('.libcal-rsvp-replymode').hide();
},
dragStart: function() {
rcmail.command('menu-close','eventoptionsmenu');
dragStart: function(e) {
rcmail.command('menu-close', 'eventoptionsmenu', null, e);
$('.libcal-rsvp-replymode').hide();
},
resizeStart: function() {
rcmail.command('menu-close','eventoptionsmenu');
resizeStart: function(e) {
rcmail.command('menu-close', 'eventoptionsmenu', null, e);
$('.libcal-rsvp-replymode').hide();
},
buttons: buttons,
@ -616,9 +620,8 @@ function rcube_calendar_ui(settings)
// add link for "more options" drop-down
if (!temp && !event.temporary && event.calendar != '_resource') {
$('<a>')
.attr('href', '#')
.html(rcmail.gettext('eventoptions','calendar'))
.addClass('dropdown-link')
.attr({href: '#', 'class': 'dropdown-link btn btn-link options', 'data-popup-pos': 'top'})
.text(rcmail.gettext('eventoptions','calendar'))
.click(function(e) {
return rcmail.command('menu-open','eventoptionsmenu', this, e)
})
@ -818,7 +821,7 @@ function rcube_calendar_ui(settings)
// save action
buttons.push({
text: rcmail.gettext('save', 'calendar'),
'class': 'mainaction',
'class': 'save mainaction',
click: function() {
var start = parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val());
var end = parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val());
@ -919,6 +922,7 @@ function rcube_calendar_ui(settings)
buttons.push({
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
click: function() {
$dialog.dialog("close");
}
@ -941,7 +945,7 @@ function rcube_calendar_ui(settings)
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: (!bw.ie6 && !bw.ie7), // disable for performance reasons
resizable: true,
closeOnEscape: false,
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
open: function() {
@ -1129,10 +1133,11 @@ function rcube_calendar_ui(settings)
$('.event-date', $dialog).hide();
});
var buttons = {};
buttons[rcmail.gettext('close', 'calendar')] = function() {
$dialog.dialog('close');
};
var buttons = [{
text: rcmail.gettext('close', 'calendar'),
'class': 'cancel',
click: function() { $dialog.dialog('close'); }
}];
// open jquery UI dialog
$dialog.dialog({
@ -1265,47 +1270,50 @@ function rcube_calendar_ui(settings)
});
// enable/disable buttons
$('#shedule-find-prev').button('option', 'disabled', (fb_start.getTime() < now.getTime()));
$('#schedule-find-prev').button('option', 'disabled', (fb_start.getTime() < now.getTime()));
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('select', '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());
// write role changes back to main dialog
$('select.edit-attendee-role').each(function(i, elem){
if (event_attendees[i] && freebusy_ui.attendees[i]) {
event_attendees[i].role = freebusy_ui.attendees[i].role;
$(elem).val(event_attendees[i].role);
var buttons = [
{
text: rcmail.gettext('select', 'calendar'),
'class': 'save mainaction',
click: 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());
// write role changes back to main dialog
$('select.edit-attendee-role').each(function(i, elem){
if (event_attendees[i] && freebusy_ui.attendees[i]) {
event_attendees[i].role = freebusy_ui.attendees[i].role;
$(elem).val(event_attendees[i].role);
}
});
if (freebusy_ui.needsupdate)
update_freebusy_status(me.selected_event);
freebusy_ui.needsupdate = false;
$dialog.dialog("close");
}
});
if (freebusy_ui.needsupdate)
update_freebusy_status(me.selected_event);
freebusy_ui.needsupdate = false;
$dialog.dialog("close");
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
},
{
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
click: function() { $dialog.dialog("close"); }
}
];
$dialog.dialog({
modal: true,
resizable: true,
closeOnEscape: (!bw.ie6 && !bw.ie7),
closeOnEscape: true,
title: rcmail.gettext('scheduletime', 'calendar'),
open: function() {
rcmail.ksearch_blur();
$dialog.attr('aria-hidden', 'false').find('#shedule-find-next, #shedule-find-prev').not(':disabled').first().focus();
$dialog.attr('aria-hidden', 'false').find('#schedule-find-next, #schedule-find-prev').not(':disabled').first().focus();
},
close: function() {
if (bw.ie6)
$("#edit-attendees-table").css('visibility','visible');
$dialog.dialog("destroy").attr('aria-hidden', 'true').hide();
// TODO: focus opener button
},
@ -1317,10 +1325,6 @@ function rcube_calendar_ui(settings)
width: 850
}).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
var gridw = $('#schedule-freebusy-times').width();
var overflow = gridw - $('#attendees-freebusy-table td.times').width();
@ -1804,7 +1808,7 @@ function rcube_calendar_ui(settings)
render_freebusy_overlay();
var now = new Date();
$('#shedule-find-prev').button('option', 'disabled', (event.start.getTime() < now.getTime()));
$('#schedule-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');
@ -1895,15 +1899,14 @@ function rcube_calendar_ui(settings)
opts['CHAIR'] = rcmail.gettext('calendar.rolechair');
if (organizer && !readonly)
dispname = rcmail.env['identities-selector'];
var select = '<select class="edit-attendee-role"' + (organizer || readonly ? ' disabled="true"' : '') + ' aria-label="' + rcmail.gettext('role','calendar') + '">';
dispname = rcmail.env['identities-selector'];
var select = '<select class="edit-attendee-role form-control"'
+ (organizer || readonly ? ' disabled="true"' : '')
+ ' aria-label="' + rcmail.gettext('role','calendar') + '">';
for (var r in opts)
select += '<option value="'+ r +'" class="' + r.toLowerCase() + '"' + (data.role == r ? ' selected="selected"' : '') +'>' + Q(opts[r]) + '</option>';
select += '</select>';
// availability
var avail = data.email ? 'loading' : 'unknown';
// delete icon
var icon = rcmail.env.deleteicon ? '<img src="' + rcmail.env.deleteicon + '" alt="" />' : rcmail.gettext('delete');
@ -1919,6 +1922,8 @@ function rcube_calendar_ui(settings)
tooltip = rcmail.gettext('libcalendaring.delegatedto') + ' ' + data['delegated-to'];
else if (data['delegated-from'])
tooltip = rcmail.gettext('libcalendaring.delegatedfrom') + ' ' + data['delegated-from'];
else if (!status && organizer)
tooltip = rcmail.gettext('statusorganizer', 'libcalendaring');
else if (status)
tooltip = status_label;
@ -1928,15 +1933,18 @@ function rcube_calendar_ui(settings)
rcmail.gettext('expandattendeegroup','libcalendaring') + '</a>';
}
var avail = data.email ? 'loading' : 'unknown';
var table = rcmail.env.calendar_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list;
var img_src = rcmail.assets_path('program/resources/blank.gif');
var elastic = $(table).parents('.no-img').length > 0;
var avail_tag = elastic ? ('<span class="' + avail + '"') : ('<img alt="" src="' + img_src + '" class="availabilityicon ' + avail + '"');
var html = '<td class="role">' + select + '</td>' +
'<td class="name"><span class="attendee-name">' + dispname + '</span></td>' +
'<td class="availability"><img src="' + img_src + '" class="availabilityicon ' + avail + '" data-email="' + data.email + '" alt="" /></td>' +
'<td class="confirmstate"><span class="' + status + '" title="' + Q(tooltip) + '">' + Q(status ? status_label : '') + '</span></td>' +
'<td class="availability">' + avail_tag + ' data-email="' + data.email + '" /></td>' +
'<td class="confirmstate"><span class="attendee ' + (status || 'organizer') + '" title="' + Q(tooltip) + '">' + Q(status && !elastic ? status_label : '') + '</span></td>' +
(data.cutype != 'RESOURCE' ? '<td class="invite">' + (organizer || readonly || !invbox ? '' : invbox) + '</td>' : '') +
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
var table = rcmail.env.calendar_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list;
var tr = $('<tr>')
.addClass(String(data.role).toLowerCase())
.html(html);
@ -1960,7 +1968,7 @@ function rcube_calendar_ui(settings)
// check free-busy status
if (avail == 'loading') {
check_freebusy_status(tr.find('img.availabilityicon'), data.email, me.selected_event);
check_freebusy_status(tr.find('.availability > *:first'), data.email, me.selected_event);
}
event_attendees.push(data);
@ -1970,7 +1978,7 @@ function rcube_calendar_ui(settings)
// iterate over all attendees and update their free-busy status display
var update_freebusy_status = function(event)
{
attendees_list.find('img.availabilityicon').each(function(i,v) {
attendees_list.find('.availability > *').each(function(i,v) {
var email, icon = $(this);
if (email = icon.attr('data-email'))
check_freebusy_status(icon, email, event);
@ -1997,10 +2005,10 @@ function rcube_calendar_ui(settings)
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){
var avail = String(status).toLowerCase();
icon.removeClass('loading').addClass(avail).attr('alt', rcmail.gettext('avail' + avail, 'calendar'));
icon.removeClass('loading').addClass(avail).attr('title', rcmail.gettext('avail' + avail, 'calendar'));
},
error: function(){
icon.removeClass('loading').addClass('unknown').attr('alt', rcmail.gettext('availunknown', 'calendar'));
icon.removeClass('loading').addClass('unknown').attr('title', rcmail.gettext('availunknown', 'calendar'));
}
});
};
@ -2019,17 +2027,20 @@ function rcube_calendar_ui(settings)
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('addresource', 'calendar')] = function() {
rcmail.command('add-resource');
};
buttons[rcmail.gettext('close')] = function() {
$dialog.dialog("close");
};
var buttons = [
{
text: rcmail.gettext('addresource', 'calendar'),
'class': 'mainaction create',
click: function() { rcmail.command('add-resource'); }
},
{
text: rcmail.gettext('close'),
'class': 'cancel',
click: function() { $dialog.dialog("close"); }
}
];
// open jquery UI dialog
$dialog.dialog({
@ -2597,6 +2608,7 @@ function rcube_calendar_ui(settings)
if (!event.recurrence) {
buttons.push({
text: rcmail.gettext((action == 'remove' ? 'delete' : 'save'), 'calendar'),
'class': action == 'remove' ? 'delete mainaction' : 'save mainaction',
click: function() {
data._notify = notify && $dialog.find('input.confirm-attendees-donotify:checked').length ? 1 : 0;
data._decline = decline && $dialog.find('input.confirm-attendees-decline:checked').length ? 1 : 0;
@ -2608,6 +2620,7 @@ function rcube_calendar_ui(settings)
buttons.push({
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
click: function() {
$(this).dialog("close");
}
@ -2699,6 +2712,11 @@ function rcube_calendar_ui(settings)
width: 680,
height: h,
title: $.fullCalendar.formatDate(date, 'dddd ' + settings['date_long']),
buttons: [{
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
click: function() { $(this).dialog("close"); }
}],
close: function(){
dialog.dialog("destroy");
me.fisheye_date = null;
@ -2858,88 +2876,60 @@ function rcube_calendar_ui(settings)
// show confirm dialog for recurring events, use jquery UI dialog
return update_event_confirm('remove', event, { id:event.id, calendar:event.calendar, attendees:event.attendees });
};
// opens a jquery UI dialog with event properties (or empty for creating a new calendar)
this.calendar_edit_dialog = function(calendar)
{
// close show dialog first
var $dialog = $("#calendarform");
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (!calendar)
calendar = { name:'', color:'cc0000', editable:true, showalarms:true };
var form, name, color, alarms;
$dialog.html(rcmail.get_label('loading'));
$.ajax({
type: 'GET',
dataType: 'html',
url: rcmail.url('calendar'),
data: { action:(calendar.id ? 'form-edit' : 'form-new'), c:{ id:calendar.id } },
success: function(data) {
$dialog.html(data);
// resize and reposition dialog window
form = $('#calendarpropform');
me.dialog_resize('#calendarform', form.height(), form.width());
name = $('#calendar-name').prop('disabled', !calendar.editable).val(calendar.editname || calendar.name);
color = $('#calendar-color').val(calendar.color).minicolors($.extend(rcmail.env.minicolors_config || {}, {value: calendar.color}));
alarms = $('#calendar-showalarms').prop('checked', calendar.showalarms).get(0);
name.select();
}
var title = rcmail.gettext((calendar.id ? 'editcalendar' : 'createcalendar'), 'calendar'),
params = {action: calendar.id ? 'form-edit' : 'form-new', c: {id: calendar.id}, _framed: 1},
$dialog = $('<iframe>').attr('src', rcmail.url('calendar', params)).on('load', function() {
var contents = $(this).contents();
contents.find('#calendar-name')
.prop('disabled', !calendar.editable)
.val(calendar.editname || calendar.name)
.select();
contents.find('#calendar-color')
.val(calendar.color);
contents.find('#calendar-showalarms')
.prop('checked', calendar.showalarms);
}),
save_func = function() {
var data,
form = $dialog.contents().find('#calendarpropform'),
name = form.find('#calendar-name');
// form is not loaded
if (!form || !form.length)
return false;
// do some input validation
if (!name.val() || name.val().length < 2) {
rcmail.alert_dialog(rcmail.gettext('invalidcalendarproperties', 'calendar'), function() {
name.select();
});
return false;
}
// post data to server
data = form.serializeJSON();
if (data.color)
data.color = data.color.replace(/^#/, '');
if (calendar.id)
data.id = calendar.id;
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data });
$dialog.dialog("close");
};
rcmail.simple_dialog($dialog, title, save_func, {
width: 600,
height: 400
});
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('save', 'calendar')] = function() {
// form is not loaded
if (!form || !form.length)
return;
// TODO: do some input validation
if (!name.val() || name.val().length < 2) {
alert(rcmail.gettext('invalidcalendarproperties', 'calendar'));
name.select();
return;
}
// post data to server
var data = form.serializeJSON();
if (data.color)
data.color = data.color.replace(/^#/, '');
if (calendar.id)
data.id = calendar.id;
if (alarms)
data.showalarms = alarms.checked ? 1 : 0;
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data });
$dialog.dialog("close");
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: true,
closeOnEscape: false,
title: rcmail.gettext((calendar.id ? 'editcalendar' : 'createcalendar'), 'calendar'),
open: function() {
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
$dialog.html('').dialog("destroy").hide();
},
buttons: buttons,
minWidth: 400,
width: 420
}).show();
};
this.calendar_remove = function(calendar)
@ -2951,10 +2941,12 @@ function rcube_calendar_ui(settings)
this.calendar_delete = function(calendar)
{
if (confirm(rcmail.gettext(calendar.children ? 'deletecalendarconfirmrecursive' : 'deletecalendarconfirm', 'calendar'))) {
var label = calendar.children ? 'deletecalendarconfirmrecursive' : 'deletecalendarconfirm';
rcmail.confirm_dialog(rcmail.gettext(label, 'calendar'), 'delete', function() {
rcmail.http_post('calendar', { action:'delete', c:{ id:calendar.id } });
return true;
}
});
return false;
};
@ -3000,40 +2992,46 @@ function rcube_calendar_ui(settings)
// close show dialog first
var $dialog = $("#eventsimport"),
form = rcmail.gui_objects.importform;
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (calendar)
$('#event-import-calendar').val(calendar.id);
var buttons = {};
buttons[rcmail.gettext('import', 'calendar')] = function() {
if (form && form.elements._data.value) {
rcmail.async_upload_form(form, 'import_events', function(e) {
rcmail.set_busy(false, null, me.saving_lock);
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
// display error message if no sophisticated response from server arrived (e.g. iframe load error)
if (me.import_succeeded === null)
rcmail.display_message(rcmail.get_label('importerror', 'calendar'), 'error');
});
var buttons = [
{
text: rcmail.gettext('import', 'calendar'),
'class' : 'mainaction import',
click: function() {
if (form && form.elements._data.value) {
rcmail.async_upload_form(form, 'import_events', function(e) {
rcmail.set_busy(false, null, me.saving_lock);
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
// display upload indicator (with extended timeout)
var timeout = rcmail.env.request_timeout;
rcmail.env.request_timeout = 600;
me.import_succeeded = null;
me.saving_lock = rcmail.set_busy(true, 'uploading');
$('.ui-dialog-buttonpane button', $dialog.parent()).button('disable');
// display error message if no sophisticated response from server arrived (e.g. iframe load error)
if (me.import_succeeded === null)
rcmail.display_message(rcmail.get_label('importerror', 'calendar'), 'error');
});
// restore settings
rcmail.env.request_timeout = timeout;
// display upload indicator (with extended timeout)
var timeout = rcmail.env.request_timeout;
rcmail.env.request_timeout = 600;
me.import_succeeded = null;
me.saving_lock = rcmail.set_busy(true, 'uploading');
$('.ui-dialog-buttonpane button', $dialog.parent()).button('disable');
// restore settings
rcmail.env.request_timeout = timeout;
}
}
},
{
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
click: function() { $dialog.dialog("close"); }
}
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
];
// open jquery UI dialog
$dialog.dialog({
@ -3041,9 +3039,6 @@ function rcube_calendar_ui(settings)
resizable: false,
closeOnEscape: false,
title: rcmail.gettext('importevents', 'calendar'),
open: function() {
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
$dialog.dialog("destroy").hide();
@ -3094,26 +3089,32 @@ function rcube_calendar_ui(settings)
input.select();
})
var buttons = {};
buttons[rcmail.gettext('export', 'calendar')] = function() {
if (form) {
var start = 0, range = $('#event-export-range option:selected', this).val(),
source = $('#event-export-calendar option:selected').val(),
attachmt = $('#event-export-attachments').get(0).checked;
var buttons = [
{
text: rcmail.gettext('export', 'calendar'),
'class': 'mainaction export',
click: function() {
if (form) {
var start = 0, range = $('#event-export-range option:selected', this).val(),
source = $('#event-export-calendar option:selected').val(),
attachmt = $('#event-export-attachments').get(0).checked;
if (range == 'custom')
start = date2unixtime(parse_datetime('00:00', $('#event-export-startdate').val()));
else if (range > 0)
start = 'today -' + range + ' months';
if (range == 'custom')
start = date2unixtime(parse_datetime('00:00', $('#event-export-startdate').val()));
else if (range > 0)
start = 'today -' + range + ' months';
rcmail.goto_url('export_events', { source:source, start:start, attachments:attachmt?1:0 });
rcmail.goto_url('export_events', { source:source, start:start, attachments:attachmt?1:0 });
}
$dialog.dialog("close");
}
},
{
text: rcmail.gettext('cancel', 'calendar'),
'class': 'cancel',
click: function() { $dialog.dialog("close"); }
}
$dialog.dialog("close");
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
];
// open jquery UI dialog
$dialog.dialog({
@ -3121,9 +3122,6 @@ function rcube_calendar_ui(settings)
resizable: false,
closeOnEscape: false,
title: rcmail.gettext('exporttitle', 'calendar'),
open: function() {
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
$dialog.dialog("destroy").hide();
@ -3175,53 +3173,33 @@ function rcube_calendar_ui(settings)
// show URL of the given calendar in a dialog box
this.showurl = function(calendar)
{
var $dialog = $('#calendarurlbox');
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (calendar.feedurl) {
var dialog = $('#calendarurlbox').clone(true);
if (calendar.caldavurl) {
$('#caldavurl').val(calendar.caldavurl);
$('#calendarcaldavurl').show();
$('#caldavurl', dialog).val(calendar.caldavurl);
$('#calendarcaldavurl', dialog).show();
}
else {
$('#calendarcaldavurl').hide();
$('#calendarcaldavurl', dialog).hide();
}
$dialog.dialog({
resizable: true,
closeOnEscape: true,
title: rcmail.gettext('showurl', 'calendar'),
close: function() {
$dialog.dialog("destroy").hide();
},
width: 520
}).show();
$('#calfeedurl').val(calendar.feedurl).select();
rcmail.simple_dialog(dialog, rcmail.gettext('showurl', 'calendar'), null, {
open: function() { $('#calfeedurl', dialog).val(calendar.feedurl).select(); },
cancel_button: 'close'
});
}
};
// show free-busy URL in a dialog box
this.showfburl = function()
{
var $dialog = $('#fburlbox');
var dialog = $('#fburlbox').clone(true);
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
$dialog.dialog({
resizable: true,
closeOnEscape: true,
title: rcmail.gettext('showfburl', 'calendar'),
close: function() {
$dialog.dialog("destroy").hide();
},
width: 520
}).show();
$('#fburl').val(settings.freebusy_url).select();
rcmail.simple_dialog(dialog, rcmail.gettext('showfburl', 'calendar'), null, {
open: function() { $('#fburl', dialog).val(settings.freebusy_url).select(); },
cancel_button: 'close'
});
};
// refresh the calendar view after saving event data
@ -3736,6 +3714,16 @@ function rcube_calendar_ui(settings)
me.calendar_edit_dialog(me.calendars[id]);
});
// Make Elastic checkboxes pretty
if (window.UI && UI.pretty_checkbox) {
$(rcmail.gui_objects.calendarslist).find('input[type=checkbox]').each(function() {
UI.pretty_checkbox($(this).addClass('flex-checkbox'));
});
calendars_list.addEventListener('add-item', function(prop) {
UI.pretty_checkbox($(prop.li).find('input').addClass('flex-checkbox'));
});
}
// select default calendar
if (rcmail.env.source && this.calendars[rcmail.env.source])
this.selected_calendar = rcmail.env.source;
@ -4018,7 +4006,7 @@ function rcube_calendar_ui(settings)
// reload free-busy status when changing the organizer identity
$('#eventedit').on('change', '#edit-identities-list', function(e) {
var email = settings.identities[$(this).val()],
icon = $(this).closest('tr').find('img.availabilityicon');
icon = $(this).closest('tr').find('.availability > *');
if (email && icon.length) {
icon.attr('data-email', email);
@ -4091,11 +4079,11 @@ function rcube_calendar_ui(settings)
event_freebusy_dialog();
});
$('#shedule-freebusy-prev').html(bw.ie6 ? '&lt;&lt;' : '&#9668;').button().click(function(){ render_freebusy_grid(-1); });
$('#shedule-freebusy-next').html(bw.ie6 ? '&gt;&gt;' : '&#9658;').button().click(function(){ render_freebusy_grid(1); }).parent().buttonset();
$('#schedule-freebusy-prev').html('&#9668;').button().click(function(){ render_freebusy_grid(-1); });
$('#schedule-freebusy-next').html('&#9658;').button().click(function(){ render_freebusy_grid(1); }).parent();//FIXME .buttonset();
$('#shedule-find-prev').button().click(function(){ freebusy_find_slot(-1); });
$('#shedule-find-next').button().click(function(){ freebusy_find_slot(1); });
$('#schedule-find-prev').button().click(function(){ freebusy_find_slot(-1); });
$('#schedule-find-next').button().click(function(){ freebusy_find_slot(1); });
$('#schedule-freebusy-workinghours').click(function(){
freebusy_ui.workinhoursonly = this.checked;
@ -4166,17 +4154,6 @@ function rcube_calendar_ui(settings)
// add proprietary css styles if not IE
if (!bw.ie)
$('div.fc-content').addClass('rcube-fc-content');
// IE supresses 2nd click event when double-clicking
if (bw.ie && bw.vendver < 9) {
$('div.fc-content').bind('dblclick', function(e){
if (!$(this).hasClass('fc-widget-header') && fc.fullCalendar('getView').name != 'table') {
var date = fc.fullCalendar('getDate');
var enddate = new Date(); enddate.setTime(date.getTime() + DAY_MS - 60000);
event_edit_dialog('new', { start:date, end:enddate, allDay:true, calendar:me.selected_calendar });
}
});
}
} // end rcube_calendar class

View file

@ -12,7 +12,7 @@
"role": "Lead"
},
{
"name": "Alensader Machniak",
"name": "Aleksander Machniak",
"email": "machniak@kolabsys.com",
"role": "Developer"
}

View file

@ -2358,7 +2358,8 @@ class kolab_driver extends calendar_driver
// General tab
$form['props'] = array(
'name' => $this->rc->gettext('properties'),
'name' => $this->rc->gettext('properties'),
'content' => array(),
);
// Disable folder name input
@ -2369,12 +2370,7 @@ class kolab_driver extends calendar_driver
}
// calendar name (default field)
$form['props']['fieldsets']['location'] = array(
'name' => $this->rc->gettext('location'),
'content' => array(
'name' => $formfields['name']
),
);
$form['props']['content']['location'] = $formfields['name'];
if (!empty($options) && ($options['norename'] || $options['protected'])) {
// prevent user from moving folder
@ -2382,7 +2378,7 @@ class kolab_driver extends calendar_driver
}
else {
$select = kolab_storage::folder_selector('event', array('name' => 'parent', 'id' => 'calendar-parent'), $folder);
$form['props']['fieldsets']['location']['content']['path'] = array(
$form['props']['content']['path'] = array(
'id' => 'calendar-parent',
'label' => $this->cal->gettext('parentcalendar'),
'value' => $select->show(strlen($folder) ? $path_imap : ''),
@ -2390,25 +2386,13 @@ class kolab_driver extends calendar_driver
}
// calendar color (default field)
$form['props']['fieldsets']['settings'] = array(
'name' => $this->rc->gettext('settings'),
'content' => array(
'color' => $formfields['color'],
'showalarms' => $formfields['showalarms'],
),
);
$form['props']['content']['color'] = $formfields['color'];
$form['props']['content']['alarms'] = $formfields['showalarms'];
if ($action != 'form-new') {
$form['sharing'] = array(
'name' => rcube::Q($this->cal->gettext('tabsharing')),
'content' => html::tag('iframe', array(
'src' => $this->cal->rc->url(array('_action' => 'calendar-acl', 'id' => $calendar['id'], 'framed' => 1)),
'width' => '100%',
'height' => 350,
'border' => 0,
'style' => 'border:0'),
''),
'name' => rcube::Q($this->cal->gettext('tabsharing')),
'content' => $this->folder_acl_form($folder)
);
}
@ -2422,35 +2406,30 @@ class kolab_driver extends calendar_driver
// Create form output
foreach ($form as $tab) {
if (!empty($tab['fieldsets']) && is_array($tab['fieldsets'])) {
$content = '';
foreach ($tab['fieldsets'] as $fieldset) {
$subcontent = $this->get_form_part($fieldset);
if ($subcontent) {
$content .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($fieldset['name'])) . $subcontent) ."\n";
}
}
}
else {
$content = $this->get_form_part($tab);
}
if ($content) {
if ($content = $this->get_form_part($tab)) {
$this->form_html .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($tab['name'])) . $content) ."\n";
}
}
// Parse form template for skin-dependent stuff
$this->rc->output->add_handler('calendarform', array($this, 'calendar_form_html'));
return $this->rc->output->parse('calendar.kolabform', false, false);
return $this->form_html;
}
/**
* Handler for template object
* Returns ACL form
*/
public function calendar_form_html()
public function folder_acl_form($folder)
{
return $this->form_html;
if (strlen($folder)) {
$this->cal->require_plugin('acl');
$storage = $this->rc->get_storage();
$options = $storage->folder_info($folder);
// get sharing UI from acl plugin
$acl = $this->rc->plugins->exec_hook('folder_form',
array('form' => array(), 'options' => $options, 'name' => $folder));
}
return $acl['form']['sharing']['content'] ?: html::div('hint', $this->cal->gettext('aclnorights'));
}
/**
@ -2461,7 +2440,7 @@ class kolab_driver extends calendar_driver
$content = '';
if (is_array($form['content']) && !empty($form['content'])) {
$table = new html_table(array('cols' => 2));
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
foreach ($form['content'] as $col => $colprop) {
$label = !empty($colprop['label']) ? $colprop['label'] : $this->cal->gettext($col);

View file

@ -311,8 +311,8 @@ class calendar_ui
if (!$activeonly || $prop['active']) {
$label_id = 'cl:' . $id;
$content = html::div(join(' ', $classes),
html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? rcube::Q($prop['editname']) : $prop['listname']) .
($prop['virtual'] ? '' :
html::a(array('class' => 'calname', 'id' => $label_id, 'title' => $title, 'href' => '#'), rcube::Q($prop['editname'] ?: $prop['listname']))
. ($prop['virtual'] ? '' :
html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') .
html::span('actions',
($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->cal->gettext('removelist')), ' ') : '') .
@ -335,7 +335,7 @@ class calendar_ui
$attrib += array('id' => 'agendaoptions');
$attrib['style'] .= 'display:none';
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange'));
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange', 'class' => 'form-control'));
$select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $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);
@ -343,7 +343,7 @@ class calendar_ui
$html .= html::label('agenda-listrange', $this->cal->gettext('listrange'));
$html .= $select_range->show($this->rc->config->get('calendar_agenda_range', $this->cal->defaults['calendar_agenda_range']));
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections'));
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections', 'class' => 'form-control'));
$select_sections->add('---', '');
foreach (array('day' => 'libcalendaring.days', 'week' => 'libcalendaring.weeks', 'month' => 'libcalendaring.months', 'smart' => 'calendar.smartsections') as $val => $label)
$select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->rc->gettext($label))), $val);
@ -570,12 +570,11 @@ class calendar_ui
if (!$attrib['id'])
$attrib['id'] = 'rcmExportForm';
$html .= html::div('form-section',
html::label('event-export-calendar', $this->cal->gettext('calendar')) .
$this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar'))
);
$html = html::div('form-section form-group row',
html::label(array('for' => 'event-export-calendar', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('calendar'))
. html::div('col-sm-8', $this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar', 'class' => 'form-control'))));
$select = new html_select(array('name' => 'range', 'id' => 'event-export-range'));
$select = new html_select(array('name' => 'range', 'id' => 'event-export-range', 'class' => 'form-control'));
$select->add(array(
$this->cal->gettext('all'),
$this->cal->gettext('onemonthback'),
@ -589,22 +588,22 @@ class calendar_ui
$startdate = new html_inputfield(array('name' => 'start', 'size' => 11, 'id' => 'event-export-startdate'));
$html .= html::div('form-section',
html::label('event-export-range', $this->cal->gettext('exportrange')) .
$select->show(0) .
html::span(array('style'=>'display:none'), $startdate->show())
);
$html .= html::div('form-section form-group row',
html::label(array('for' => 'event-export-range', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportrange'))
. html::div('col-sm-8', $select->show(0) . html::span(array('style'=>'display:none'), $startdate->show())));
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1));
$html .= html::div('form-section',
html::label('event-export-attachments', $this->cal->gettext('exportattachments')) .
$checkbox->show(1)
);
$html .= html::div('form-section form-group row',
html::label(array('for' => 'event-export-attachments', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportattachments'))
. html::div('col-sm-8', $checkbox->show(1)));
$this->rc->output->add_gui_object('exportform', $attrib['id']);
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'export_events')),
'method' => "post", 'id' => $attrib['id']),
return html::tag('form', $attrib + array(
'action' => $this->rc->url(array('task' => 'calendar', 'action' => 'export_events')),
'method' => "post",
'id' => $attrib['id']
),
$html
);
}
@ -674,21 +673,37 @@ class calendar_ui
* The form content could be overriden by the driver
*/
function calendar_editform($action, $calendar = array())
{
$this->action = $action;
$this->calendar = $calendar;
// load miniColors js/css files
jqueryui::miniColors();
$this->rc->output->add_handler('calendarform', array($this, 'calendarform'));
$this->rc->output->send('calendar.folderform');
}
/**
* Handler for calendar form template.
* The form content could be overriden by the driver
*/
function calendarform($attrib)
{
// compose default calendar form fields
$input_name = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20));
$input_color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 6));
$input_name = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20));
$input_color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 7, 'class' => 'colors'));
$formfields = array(
'name' => array(
'label' => $this->cal->gettext('name'),
'value' => $input_name->show($calendar['name']),
'id' => 'calendar-name',
'id' => 'calendar-name',
),
'color' => array(
'label' => $this->cal->gettext('color'),
'value' => $input_color->show($calendar['color']),
'id' => 'calendar-color',
'id' => 'calendar-color',
),
);
@ -696,14 +711,14 @@ class calendar_ui
$checkbox = new html_checkbox(array('name' => 'showalarms', 'id' => 'calendar-showalarms', 'value' => 1));
$formfields['showalarms'] = array(
'label' => $this->cal->gettext('showalarms'),
'value' => $checkbox->show($calendar['showalarms']?1:0),
'id' => 'calendar-showalarms',
'value' => $checkbox->show($this->calendar['showalarms'] ? 1 :0),
'id' => 'calendar-showalarms',
);
}
// allow driver to extend or replace the form content
return html::tag('form', array('action' => "#", 'method' => "get", 'id' => 'calendarpropform'),
$this->cal->driver->calendar_form($action, $calendar, $formfields)
return html::tag('form', $attrib + array('action' => "#", 'method' => "get", 'id' => 'calendarpropform'),
$this->cal->driver->calendar_form($this->action, $this->calendar, $formfields)
);
}
@ -743,12 +758,12 @@ class calendar_ui
*/
function attendees_form($attrib = array())
{
$input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => 30));
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment',
$input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'class' => 'form-control'));
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment', 'class' => 'form-control',
'rows' => 4, 'cols' => 55, 'title' => $this->cal->gettext('itipcommenttitle')));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::div('form-searchbar', $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->cal->gettext('addattendee'))) . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-schedule', 'value' => $this->cal->gettext('scheduletime').'...'))) .
html::p('attendees-commentbox', html::label(null, $this->cal->gettext('itipcomment') . $textarea->show()))
@ -760,10 +775,10 @@ class calendar_ui
*/
function resources_form($attrib = array())
{
$input = new html_inputfield(array('name' => 'resource', 'id' => 'edit-resource-name', 'size' => 30));
$input = new html_inputfield(array('name' => 'resource', 'id' => 'edit-resource-name', 'class' => 'form-control'));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::div('form-searchbar', $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-add', 'value' => $this->cal->gettext('addresource'))) . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-find', 'value' => $this->cal->gettext('findresources').'...')))
);

View file

@ -38,6 +38,7 @@ $labels['calendar'] = 'Calendar';
$labels['calendars'] = 'Calendars';
$labels['category'] = 'Category';
$labels['categories'] = 'Categories';
$labels['addcalendar'] = 'Add calendar';
$labels['createcalendar'] = 'Create new calendar';
$labels['editcalendar'] = 'Edit calendar properties';
$labels['name'] = 'Name';

View file

@ -196,7 +196,7 @@ pre {
height: 22px;
}
#calendars .treelist li span.calname {
#calendars .treelist li a.calname {
display: block;
padding: 0px 18px 2px 2px;
position: absolute;
@ -221,18 +221,18 @@ pre {
background-image: none;
}
#calendars .treelist li div.virtual > span.calname {
#calendars .treelist li div.virtual > a.calname {
color: #aaa;
top: 4px;
left: 20px;
}
#calendars .treelist li.x-birthdays span.calname,
#calendars .treelist li.x-invitations span.calname {
#calendars .treelist li.x-birthdays a.calname,
#calendars .treelist li.x-invitations a.calname {
font-style: italic;
}
#calendars .treelist.flat li span.calname {
#calendars .treelist.flat li a.calname {
left: 24px;
right: 42px;
}
@ -376,27 +376,27 @@ pre {
background-color: #c7e3ef;
}
#calendars .treelist li.selected > span.calname {
#calendars .treelist li.selected > a.calname {
font-weight: bold;
}
#calendars .treelist div.readonly span.calname {
#calendars .treelist div.readonly a.calname {
background-position: right -20px;
}
#calendars .treelist li.user > div > span.calname {
#calendars .treelist li.user > div > a.calname {
background-position: right -38px;
}
/*
#calendars .treelist div.user.readonly span.calname {
#calendars .treelist div.user.readonly a.calname {
background-position: right -56px;
}
#calendars .treelist div.shared span.calname {
#calendars .treelist div.shared a.calname {
background-position: right -74px;
}
#calendars .treelist div.shared.readonly span.calname {
#calendars .treelist div.shared.readonly a.calname {
background-position: right -92px;
}
*/

View file

@ -1,25 +0,0 @@
/* CSS hacks for IE 7 */
#calendar {
top: 5em;
}
.calwidth {
width: 172mm;
}
.fc-header-title h2 {
font-size: 16px;
}
#calendarlist li {
float: none;
padding: 0;
margin-left: 1em;
}
@media print {
#calendar {
top: 0;
}
}

View file

@ -301,7 +301,7 @@
<div class="schedule-options">
&nbsp;
<div class="schedule-buttons">
<button id="shedule-freebusy-prev" title="<roundcube:label name='previouspage' />">&#9668;</button><button id="shedule-freebusy-next" title="<roundcube:label name='nextpage' />">&#9658;</button>
<button id="schedule-freebusy-prev" title="<roundcube:label name='previouspage' />">&#9668;</button><button id="schedule-freebusy-next" title="<roundcube:label name='nextpage' />">&#9658;</button>
</div>
</div>
@ -319,8 +319,8 @@
</div>
<div style="float:left">
<div class="schedule-find-buttons">
<button id="shedule-find-prev">&#9668; <roundcube:label name="calendar.prevslot" /></button>
<button id="shedule-find-next"><roundcube:label name="calendar.nextslot" /> &#9658;</button>
<button id="schedule-find-prev">&#9668; <roundcube:label name="calendar.prevslot" /></button>
<button id="schedule-find-next"><roundcube:label name="calendar.nextslot" /> &#9658;</button>
</div>
<div class="schedule-options">
<label><input type="checkbox" id="schedule-freebusy-workinghours" value="1" /><roundcube:label name="calendar.onlyworkinghours" /></label>

View file

@ -1,26 +0,0 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
<style type="text/css" media="screen">
body.aclform {
background: #efefef;
margin: 0;
}
body.aclform .hint {
margin: 1em;
}
</style>
</head>
<body class="iframe aclform">
<roundcube:object name="folderacl" />
<roundcube:include file="/includes/footer.html" />
</body>
</html>

View file

@ -24,6 +24,5 @@
<roundcube:object name="plugin.calendar_css" printmode="true" />
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="plugins/calendar/skins/classic/print.iehacks.css" /><![endif]-->
</body>
</html>

View file

@ -50,7 +50,7 @@ libkolab_audittrail.object_history_dialog = function(p)
// open jquery UI dialog
$dialog.dialog({
modal: false,
modal: true,
resizable: true,
closeOnEscape: true,
title: p.title,

View file

@ -25,6 +25,56 @@
a.calendarlink:before {
.font-icon-regular(@fa-var-calendar);
}
a.send:before {
content: @fa-var-paper-plane;
}
}
// Icon for resources in autocompletion list
.listing.iconized li.resource > i:before {
content: @fa-var-cube;
}
.listing {
li {
& > div {
&.calendar .calname:before {
&:extend(.font-icon-class);
content: @fa-var-calendar-alt;
}
&.calendar.cal---invitation--pending .calname:before,
&.calendar.cal---invitation--declined .calname:before {
.font-icon-regular(@fa-var-calendar-alt);
}
&.calendar.cal-__bdays__ .calname:before {
content: @fa-var-birthday-cake;
}
&.calendar.cal---invitation--pending,
&.calendar.cal---invitation--declined,
&.calendar.cal-__bdays__ {
a.quickview {
padding-right: .25rem;
}
a.calname {
padding-right: 4em;
}
.count {
right: 5.5em;
}
}
}
// Calednars list element (color indicator) used in Larry
span.handle {
display: none;
}
}
}
#calendarcategories {
@ -88,3 +138,750 @@ fieldset.categories .input-group {
.event-date {
}
}
.calendar-datepicker {
// overwrite jQuery-UI datepicker styles
.ui-datepicker {
top: initial !important;
left: initial !important;
position: relative !important;
transform: unset;
box-shadow: none;
border: 0;
border-radius: 0;
width: auto;
min-width: auto !important;
font-size: .9rem;
background-color: @color-black-shade-bg;
td a {
font-size: .9rem !important;
}
}
.ui-datepicker-header {
background-color: @color-black-shade-bg;
border-top: 1px solid @color-layout-border;
}
}
// Fullcalendar styles
.fc {
flex: auto !important;
.fc-header {
}
.fc-header-left {
}
.fc-header-right {
}
.fc-header-title {
h2 {
font-size: 1.5rem;
font-weight: bold;
}
}
.fc-content {
}
.fc-view {
width: 100%;
overflow: hidden;
}
// Cell Styles
.fc-widget-header, // <th>, usually
.fc-widget-content { // <td>, usually
border: 1px solid #ddd;
}
.fc-cell-overlay { // semi-transparent rectangle while dragging
background: #bce8f1;
opacity: .3;
filter: alpha(opacity=30); /* for IE */
}
// Buttons
.fc-button {
position: relative;
display: inline-block;
padding: 0 .6em;
overflow: hidden;
height: 1.9em;
line-height: 1.9em;
white-space: nowrap;
cursor: pointer;
}
// Our default prev/next buttons use HTML entities like &lsaquo; &rsaquo; &laquo; &raquo;
// and we'll try to make them look good cross-browser.
.fc-text-arrow {
margin: 0 .1em;
font-size: 2em;
}
.fc-button-prev .fc-text-arrow,
.fc-button-next .fc-text-arrow { // for &lsaquo; &rsaquo;
font-weight: bold;
}
// icon (for jquery ui)
.fc-button {
.fc-icon-wrap {
position: relative;
float: left;
top: 50%;
}
.ui-icon {
position: relative;
float: left;
margin-top: -50%;
}
}
// Button states
// borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/)
.fc-state-highlight { // <td> today cell, TODO: add .fc-today to <th>
background: #fcf8e3;
}
.fc-state-default {
border: 1px solid;
background-color: #f5f5f5;
&.fc-corner-left { // non-theme
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
&.fc-corner-right { // non-theme
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
.fc-state-hover,
.fc-state-down,
.fc-state-active,
.fc-state-disabled {
color: #333333;
background-color: #e6e6e6;
}
.fc-state-hover {
color: #333333;
text-decoration: none;
}
.fc-state-down,
.fc-state-active {
background-color: #cccccc;
outline: 0;
}
.fc-state-disabled {
cursor: default;
background-image: none;
opacity: 0.65;
}
// Global Event Styles
.fc-event-container {
& > * {
z-index: 8;
}
& > .ui-draggable-dragging,
& > .ui-resizable-resizing {
z-index: 9;
}
}
.fc-event {
border: 1px solid #3a87ad; // default BORDER color
background-color: #3a87ad; // default BACKGROUND color
color: #fff; // default TEXT color
font-size: .85em;
cursor: default;
&:focus {
outline: 2px solid ActiveBorder;
}
.fc-rtl & {
text-align: right;
}
}
a.fc-event {
text-decoration: none;
}
a.fc-event,
.fc-event-draggable {
cursor: pointer;
}
.fc-event-inner {
width: 100%;
height: 100%;
overflow: hidden;
}
.fc-event-time,
.fc-event-title {
padding: 0 1px;
}
.ui-resizable-handle {
display: block;
position: absolute;
z-index: 99999;
font-size: 300%;
line-height: 50%;
}
// Horizontal Events
.fc-event-hori {
border-width: 1px 0;
margin-bottom: 1px;
}
.fc-ltr .fc-event-hori.fc-event-start,
.fc-rtl .fc-event-hori.fc-event-end {
border-left-width: 1px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.fc-ltr .fc-event-hori.fc-event-end,
.fc-rtl .fc-event-hori.fc-event-start {
border-right-width: 1px;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
// resizable
.fc-event-hori .ui-resizable-e {
top: 0 !important; // importants override pre jquery ui 1.7 styles
right: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: e-resize;
}
.fc-event-hori .ui-resizable-w {
top: 0 !important;
left: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: w-resize;
}
// Reusable Separate-border Table
.fc-border-separate {
border-collapse: separate;
th,
td {
border-width: 1px 0 0 1px;
&.fc-last {
border-right-width: 1px;
}
}
tr.fc-last th,
tr.fc-last td {
border-bottom-width: 1px;
}
tbody tr.fc-first td,
tbody tr.fc-first th {
border-top-width: 0;
}
}
// Month View, Basic Week View, Basic Day View
.fc-week-number {
width: 22px;
text-align: center;
div {
padding: 0 2px;
}
}
.fc-grid {
th {
text-align: center;
}
.fc-day-number {
float: right;
padding: 0 2px;
}
.fc-other-month .fc-day-number {
opacity: 0.3;
}
.fc-day-content {
clear: both;
padding: 2px 2px 1px; // distance between events and day edges
}
// event styles
.fc-event-time {
font-weight: bold;
}
// right-to-left
.fc-rtl & .fc-day-number {
float: left;
}
.fc-rtl & .fc-event-time {
float: right;
}
}
.fc-more-link {
font-size: 0.85em;
white-space: nowrap;
text-decoration: none;
cursor: pointer;
padding: 1px;
}
// Agenda Week View, Agenda Day View
.fc-agenda-days th {
text-align: center;
}
.fc-agenda {
table {
border-collapse: separate;
}
.fc-agenda-axis {
width: 50px;
padding: 0 4px;
vertical-align: middle;
text-align: right;
white-space: nowrap;
font-weight: normal;
}
.fc-week-number {
font-weight: bold;
}
.fc-agenda .fc-day-content {
padding: 2px 2px 1px;
}
}
// make axis border take precedence
.fc-agenda-days .fc-agenda-axis {
border-right-width: 1px;
}
.fc-agenda-days .fc-col0 {
border-left-width: 0;
}
// all-day area
.fc-agenda-allday {
th {
border-width: 0 1px;
}
.fc-day-content {
min-height: 34px;
}
}
// divider (between all-day and slots)
.fc-agenda-divider-inner {
height: 2px;
overflow: hidden;
.fc-widget-header & {
background: #eee;
}
}
// slot rows
.fc-agenda-slots {
th {
border-width: 1px 1px 0;
}
td {
border-width: 1px 0 0;
background: none;
}
td div {
height: 20px;
}
tr.fc-slot0 th,
tr.fc-slot0 td {
border-top-width: 0;
}
tr.fc-minor th,
tr.fc-minor td {
border-top-style: dotted;
}
}
// Vertical Events
.fc-event-vert {
border-width: 0 1px;
.fc-event-head,
.fc-event-content {
position: relative;
z-index: 2;
width: 100%;
overflow: hidden;
}
&.fc-event-start {
border-top-width: 1px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
&.fc-event-end {
border-bottom-width: 1px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.fc-event-time {
white-space: nowrap;
font-size: 10px;
}
.fc-event-inner {
position: relative;
z-index: 2;
}
.fc-event-bg { // makes the event lighter w/ a semi-transparent overlay
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
opacity: .25;
}
}
// resizable
.fc-event-vert .ui-resizable-s {
bottom: 0 !important; // importants override pre jquery ui 1.7 styles
width: 100% !important;
height: 8px !important;
overflow: hidden !important;
line-height: 8px !important;
font-size: 11px !important;
font-family: monospace;
text-align: center;
cursor: s-resize;
}
.fc-timeline {
position: absolute;
width: 100%;
left: 0;
margin: 0;
padding: 0;
border: none;
border-top: 2px solid #3ec400;
z-index: 999;
}
// List view (by bruederli@kolabsys.com)
.fc-view-list,
.fc-view-table {
border: 1px solid #ccc;
width: auto;
.fc-list-header,
td.fc-list-header {
border-width: 0;
border-bottom-width: 1px;
padding: 3px 5px;
}
}
.fc-list-section {
padding: 4px 2px;
border-width: 0;
border-bottom-width: 1px;
}
.fc-view-list .fc-last {
border-bottom-width: 0;
}
.fc-list-section .fc-event {
position: relative;
margin: 1px 2px 3px 2px;
}
.fc-view-table {
tr.fc-event {
background: inherit;
color: inherit;
td {
padding: 2px;
border-bottom: 1px solid #ccc;
}
td.fc-event-handle {
padding: 3px 8px 3px 3px;
}
}
.fc-first td.fc-list-header {
border-top-width: 0;
}
.fc-event-handle {
.fc-event-skin {
border-radius: 2px;
}
.fc-event-inner {
display: block;
width: 8px;
height: 10px;
border-radius: 2px;
}
}
table {
table-layout: fixed;
width: 100%;
}
.fc-event-inner {
border-color: inherit;
background-color: inherit;
}
col.fc-event-handle {
width: 18px;
}
col.fc-event-date {
width: 7em;
white-space: nowrap;
padding-right: 1em;
.fc-list-day & {
width: 1px;
}
}
col.fc-event-time {
width: 9em;
white-space: nowrap;
padding-right: 1em;
}
}
.fc-icon-alarms,
.fc-icon-sensitive,
.fc-icon-recurring {
display: inline-block;
width: 1em;
height: 1em;
margin-left: .25rem;
&:before {
&:extend(.font-icon-class);
font-size: 1em;
line-height: 1;
}
}
.fc-icon-recurring:before {
.font-icon-regular(@fa-var-clone);
}
.fc-icon-alarms:before {
content: @fa-var-bell;
}
.fc-icon-sensitive:before {
content: @fa-var-lock;
}
}
#timezone-display {
}
#event-status-badge {
width: 7rem;
height: 7rem;
position: absolute;
top: 0;
right: 0;
overflow: hidden;
span {
display: none;
text-transform: uppercase;
line-height: 20px;
position: absolute;
left: -2.4rem;
top: 2.4rem;
width: 13.2rem;
text-align: center;
font-weight: bold;
font-size: .85rem;
color: #fff;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
&:before {
&:extend(.font-icon-class);
display: inline;
float: none;
}
.status-cancelled & {
background-color: darken(@color-error, 10%);
display: block;
&:before {
content: @fa-var-times-circle;
}
}
.sensitivity-private & {
background-color: darken(@color-warning, 10%);
display: block;
&:before {
content: @fa-var-lock;
}
}
.sensitivity-confidential & {
background-color: darken(@color-error, 10%);
display: block;
&:before {
content: @fa-var-user-secret;
}
}
}
}
@color-availability-unknown: #ddd;
@color-availability-free: #abd640;
@color-availability-busy: #e26569;
@color-availability-tentative: #8383fc;
@color-availability-out-of-office: #fbaa68;
.availability {
span {
margin-right: .5rem;
color: @color-black-shade-text;
&:before {
&:extend(.font-icon-class);
content: @fa-var-square;
display: inline;
float: none;
}
&.legend:before {
font-size: 1em;
}
&.loading:before {
.animated-icon-class;
content: @fa-var-circle-notch;
display: block;
line-height: 1;
}
&.unknown:before {
color: @color-availability-unknown;
}
&.free:before {
color: @color-availability-free;
}
&.busy:before {
color: @color-availability-busy;
}
&.tentative:before {
color: @color-availability-tentative;
}
&.out-of-office:before {
color: @color-availability-out-of-office;
}
}
}
.calendar-scheduler {
.schedule-nav {
}
.schedule-range {
}
.slot-nav {
position: absolute;
top: 1rem;
right: 1rem;
}
.schedule-legend {
margin-top: 1rem;
}
}

View file

@ -144,3 +144,73 @@
}
}
.attendee {
&:after {
&:extend(.font-icon-class);
content: @fa-var-question-circle;
display: inline;
float: none;
font-size: 1em;
margin-left: .2rem;
}
&.req-participant:after {
content: @fa-var-user;
}
&.opt-participant:after {
.font-icon-regular(@fa-var-user);
}
&.non-participant:after {
content: @fa-var-user;
color: #999;
}
&.chair:after {
content: @fa-var-user; // todo
color: @color-warning;
}
&.accepted:after {
content: @fa-var-check-circle;
color: @color-success;
}
&.declined:after {
content: @fa-var-ban;
color: @color-error;
}
&.tentative:after {
content: @fa-var-check-circle;
color: @color-warning;
}
&.delegated:after {
content: @fa-var-share;
}
&.organizer:after {
content: @fa-var-briefcase; // TODO: better icon
}
}
.form-searchbar {
display: flex;
margin-bottom: .5rem;
input[type=button] {
margin-left: .5em;
}
}
.attendees-comentbox {
label {
display: inline;
}
}
#edit-attendees-legend {
margin-top: 1rem;
}

View file

@ -34,6 +34,17 @@
}
}
.listing {
li {
& > div {
&.tasklist .listname:before {
&:extend(.font-icon-class);
content: @fa-var-tasks;
}
}
}
}
@tasklist-record-height: 3.8rem;
#tasklist {

View file

@ -62,25 +62,12 @@
}
}
&.tasklist .listname:before {
&:extend(.font-icon-class);
content: @fa-var-tasks;
}
&.calendar .calname:before {
.font-icon-regular(@fa-var-calendar);
}
&.folder .listname:before {
&:extend(.font-icon-class);
content: @fa-var-sticky-note;
margin-right: .5rem;
}
span.handle {
// TODO calendar/tasklist color indicator
}
span.actions {
display: flex;
@ -110,6 +97,10 @@
color: @color-link;
}
a.quickview:after {
display: none !important;
}
&.focusview {
a.quickview:before {
content: @fa-var-eye;
@ -149,7 +140,7 @@
color: @color-list-selected;
background-color: @color-list-selected-background;
}
/*
&.shared > div a:first-child {
padding-right: 1.6em;
@ -167,7 +158,7 @@
content: @fa-var-user;
}
}
*/
& > div.readonly a:first-child,
&.readonly:not(.virtual) > div a:first-child {
padding-right: 1.6em;
@ -185,19 +176,18 @@
}
&:after {
content: "";
display: none;
}
}
&.other.user > div {
span.calname {
// TODO @fa-var-user;
& > div.virtual.shared > .listname,
&.virtual.shared > div a:first-child {
&:before {
.font-icon-solid(@fa-var-share-alt);
}
}
&.shared > div {
span.calname {
// TODO @fa-var-share-alt;
&:after {
display: none;
}
}