Implement quickview for calendars, showing free-busy data for other user's calendars (#3043)
This commit is contained in:
parent
30c6840269
commit
ab43057b1f
7 changed files with 289 additions and 157 deletions
|
@ -3,12 +3,11 @@
|
||||||
/**
|
/**
|
||||||
* Calendar plugin for Roundcube webmail
|
* Calendar plugin for Roundcube webmail
|
||||||
*
|
*
|
||||||
* @version @package_version@
|
|
||||||
* @author Lazlo Westerhof <hello@lazlo.me>
|
* @author Lazlo Westerhof <hello@lazlo.me>
|
||||||
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
|
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
|
||||||
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
|
* Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -1397,7 +1396,9 @@ class calendar extends rcube_plugin
|
||||||
'title' => strval($event['title']),
|
'title' => strval($event['title']),
|
||||||
'description' => strval($event['description']),
|
'description' => strval($event['description']),
|
||||||
'location' => strval($event['location']),
|
'location' => strval($event['location']),
|
||||||
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true),
|
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') .
|
||||||
|
'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true) .
|
||||||
|
rtrim(' ' . $event['className']),
|
||||||
'allDay' => ($event['allday'] == 1),
|
'allDay' => ($event['allday'] == 1),
|
||||||
) + $event;
|
) + $event;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* JavaScript code in this file.
|
* JavaScript code in this file.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
|
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
|
||||||
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
|
* Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -83,6 +83,78 @@ function rcube_calendar_ui(settings)
|
||||||
selectOtherMonths: true
|
selectOtherMonths: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// global fullcalendar settings
|
||||||
|
var fullcalendar_defaults = {
|
||||||
|
aspectRatio: 1,
|
||||||
|
ignoreTimezone: true, // will treat the given date strings as in local (browser's) timezone
|
||||||
|
monthNames : settings.months,
|
||||||
|
monthNamesShort : settings.months_short,
|
||||||
|
dayNames : settings.days,
|
||||||
|
dayNamesShort : settings.days_short,
|
||||||
|
firstDay : settings.first_day,
|
||||||
|
firstHour : settings.first_hour,
|
||||||
|
slotMinutes : 60/settings.timeslots,
|
||||||
|
timeFormat: {
|
||||||
|
'': settings.time_format,
|
||||||
|
agenda: settings.time_format + '{ - ' + settings.time_format + '}',
|
||||||
|
list: settings.time_format + '{ - ' + settings.time_format + '}',
|
||||||
|
table: settings.time_format + '{ - ' + settings.time_format + '}'
|
||||||
|
},
|
||||||
|
axisFormat : settings.time_format,
|
||||||
|
columnFormat: {
|
||||||
|
month: 'ddd', // Mon
|
||||||
|
week: 'ddd ' + settings.date_short, // Mon 9/7
|
||||||
|
day: 'dddd ' + settings.date_short, // Monday 9/7
|
||||||
|
table: settings.date_agenda
|
||||||
|
},
|
||||||
|
titleFormat: {
|
||||||
|
month: 'MMMM yyyy',
|
||||||
|
week: settings.dates_long,
|
||||||
|
day: 'dddd ' + settings['date_long'],
|
||||||
|
table: settings.dates_long
|
||||||
|
},
|
||||||
|
listPage: 1, // advance one day in agenda view
|
||||||
|
listRange: settings.agenda_range,
|
||||||
|
listSections: settings.agenda_sections,
|
||||||
|
tableCols: ['handle', 'date', 'time', 'title', 'location'],
|
||||||
|
defaultView: rcmail.env.view || settings.default_view,
|
||||||
|
allDayText: rcmail.gettext('all-day', 'calendar'),
|
||||||
|
buttonText: {
|
||||||
|
prev: ' ◄ ',
|
||||||
|
next: ' ► ',
|
||||||
|
today: settings['today'],
|
||||||
|
day: rcmail.gettext('day', 'calendar'),
|
||||||
|
week: rcmail.gettext('week', 'calendar'),
|
||||||
|
month: rcmail.gettext('month', 'calendar'),
|
||||||
|
table: rcmail.gettext('agenda', 'calendar')
|
||||||
|
},
|
||||||
|
listTexts: {
|
||||||
|
until: rcmail.gettext('until', 'calendar'),
|
||||||
|
past: rcmail.gettext('pastevents', 'calendar'),
|
||||||
|
today: rcmail.gettext('today', 'calendar'),
|
||||||
|
tomorrow: rcmail.gettext('tomorrow', 'calendar'),
|
||||||
|
thisWeek: rcmail.gettext('thisweek', 'calendar'),
|
||||||
|
nextWeek: rcmail.gettext('nextweek', 'calendar'),
|
||||||
|
thisMonth: rcmail.gettext('thismonth', 'calendar'),
|
||||||
|
nextMonth: rcmail.gettext('nextmonth', 'calendar'),
|
||||||
|
future: rcmail.gettext('futureevents', 'calendar'),
|
||||||
|
week: rcmail.gettext('weekofyear', 'calendar')
|
||||||
|
},
|
||||||
|
currentTimeIndicator: settings.time_indicator,
|
||||||
|
// event rendering
|
||||||
|
eventRender: fc_event_render,
|
||||||
|
// render element indicating more (invisible) events
|
||||||
|
overflowRender: function(data, element) {
|
||||||
|
element.html(rcmail.gettext('andnmore', 'calendar').replace('$nr', data.count))
|
||||||
|
.click(function(e){ me.fisheye_view(data.date); });
|
||||||
|
},
|
||||||
|
// callback when a specific event is clicked
|
||||||
|
eventClick: function(event, ev, view) {
|
||||||
|
if (!event.temp && String(event.className).indexOf('fc-type-freebusy') < 0)
|
||||||
|
event_show_dialog(event, ev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*** imports ***/
|
/*** imports ***/
|
||||||
var Q = this.quote_html;
|
var Q = this.quote_html;
|
||||||
var text2html = this.text2html;
|
var text2html = this.text2html;
|
||||||
|
@ -1598,25 +1670,13 @@ function rcube_calendar_ui(settings)
|
||||||
|
|
||||||
// initialize resource calendar display
|
// initialize resource calendar display
|
||||||
var resource_cal = $(rcmail.gui_objects.resourceinfocalendar);
|
var resource_cal = $(rcmail.gui_objects.resourceinfocalendar);
|
||||||
resource_cal.fullCalendar({
|
resource_cal.fullCalendar($.extend({}, fullcalendar_defaults, {
|
||||||
header: { left: '', center: '', right: '' },
|
header: { left: '', center: '', right: '' },
|
||||||
height: resource_cal.height() + 4,
|
height: resource_cal.height() + 4,
|
||||||
defaultView: 'agendaWeek',
|
defaultView: 'agendaWeek',
|
||||||
ignoreTimezone: true,
|
|
||||||
eventSources: [],
|
eventSources: [],
|
||||||
monthNames: settings['months'],
|
|
||||||
monthNamesShort: settings['months_short'],
|
|
||||||
dayNames: settings['days'],
|
|
||||||
dayNamesShort : settings['days_short'],
|
|
||||||
firstDay: settings['first_day'],
|
|
||||||
firstHour: settings['first_hour'],
|
|
||||||
slotMinutes: 60,
|
slotMinutes: 60,
|
||||||
allDaySlot: false,
|
allDaySlot: false,
|
||||||
timeFormat: { '': settings['time_format'] },
|
|
||||||
axisFormat: settings['time_format'],
|
|
||||||
columnFormat: { day: 'dddd ' + settings['date_short'] },
|
|
||||||
titleFormat: { day: 'dddd ' + settings['date_long'] },
|
|
||||||
currentTimeIndicator: settings.time_indicator,
|
|
||||||
eventRender: function(event, element, view) {
|
eventRender: function(event, element, view) {
|
||||||
var title = rcmail.get_label(event.status, 'calendar');
|
var title = rcmail.get_label(event.status, 'calendar');
|
||||||
element.addClass('status-' + event.status);
|
element.addClass('status-' + event.status);
|
||||||
|
@ -1624,7 +1684,7 @@ function rcube_calendar_ui(settings)
|
||||||
element.find('.fc-event-title').text(title);
|
element.find('.fc-event-title').text(title);
|
||||||
element.attr('aria-label', me.event_date_text(event, true) + ': ' + title);
|
element.attr('aria-label', me.event_date_text(event, true) + ': ' + title);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
$('#resource-calendar-prev').click(function(){
|
$('#resource-calendar-prev').click(function(){
|
||||||
resource_cal.fullCalendar('prev');
|
resource_cal.fullCalendar('prev');
|
||||||
|
@ -2107,37 +2167,69 @@ function rcube_calendar_ui(settings)
|
||||||
me.fisheye_date = null;
|
me.fisheye_date = null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fullCalendar({
|
.fullCalendar($.extend({}, fullcalendar_defaults, {
|
||||||
header: { left: '', center: '', right: '' },
|
header: { left: '', center: '', right: '' },
|
||||||
height: h - 50,
|
height: h - 50,
|
||||||
defaultView: 'agendaDay',
|
|
||||||
date: date.getDate(),
|
date: date.getDate(),
|
||||||
month: date.getMonth(),
|
month: date.getMonth(),
|
||||||
year: date.getFullYear(),
|
year: date.getFullYear(),
|
||||||
ignoreTimezone: true, /* will treat the given date strings as in local (browser's) timezone */
|
eventSources: sources
|
||||||
eventSources: sources,
|
}));
|
||||||
monthNames : settings['months'],
|
|
||||||
monthNamesShort : settings['months_short'],
|
|
||||||
dayNames : settings['days'],
|
|
||||||
dayNamesShort : settings['days_short'],
|
|
||||||
firstDay : settings['first_day'],
|
|
||||||
firstHour : settings['first_hour'],
|
|
||||||
slotMinutes : 60/settings['timeslots'],
|
|
||||||
timeFormat: { '': settings['time_format'] },
|
|
||||||
axisFormat : settings['time_format'],
|
|
||||||
columnFormat: { day: 'dddd ' + settings['date_short'] },
|
|
||||||
titleFormat: { day: 'dddd ' + settings['date_long'] },
|
|
||||||
allDayText: rcmail.gettext('all-day', 'calendar'),
|
|
||||||
currentTimeIndicator: settings.time_indicator,
|
|
||||||
eventRender: fc_event_render,
|
|
||||||
eventClick: function(event, ev, view) {
|
|
||||||
event_show_dialog(event, ev);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.fisheye_date = date;
|
this.fisheye_date = date;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// opens the given calendar in a popup dialog
|
||||||
|
this.quickview = function(id)
|
||||||
|
{
|
||||||
|
$('#quickview-calendar:ui-dialog').dialog('close');
|
||||||
|
|
||||||
|
var dialog, src, cal = this.calendars[id], date = fc.fullCalendar('getDate'),
|
||||||
|
h = $(window).height() - 50,
|
||||||
|
me = this;
|
||||||
|
|
||||||
|
// clone and modify calendar properties
|
||||||
|
src = $.extend({}, cal);
|
||||||
|
src.editable = false;
|
||||||
|
src.url += '&_quickview=1';
|
||||||
|
|
||||||
|
dialog = $('<div>')
|
||||||
|
.attr('id', 'quickview-calendar')
|
||||||
|
.dialog({
|
||||||
|
modal: true,
|
||||||
|
width: Math.min(1000, $(window).width() - 100),
|
||||||
|
height: h,
|
||||||
|
title: cal.name.replace('»', '»').replace(' ', ' '),
|
||||||
|
open: function() {
|
||||||
|
setTimeout(function() { dialog.find('.fc-button-next').first().focus(); }, 10);
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
dialog.dialog('destroy').fullCalendar('destroy').remove();
|
||||||
|
me.quickview_active = null;
|
||||||
|
},
|
||||||
|
resize: function(e) {
|
||||||
|
// adjust height when dialog resizes
|
||||||
|
dialog.fullCalendar('option', 'height', dialog.height() + 8);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fullCalendar($.extend({}, fullcalendar_defaults, {
|
||||||
|
header: {
|
||||||
|
left: 'agendaDay,agendaWeek,month,table',
|
||||||
|
center: 'title',
|
||||||
|
right: 'prev,next today'
|
||||||
|
},
|
||||||
|
height: h - 50,
|
||||||
|
defaultView: fc.fullCalendar('getView').name || fullcalendar_defaults.defaultView,
|
||||||
|
date: date.getDate(),
|
||||||
|
month: date.getMonth(),
|
||||||
|
year: date.getFullYear(),
|
||||||
|
slotMinutes: 60,
|
||||||
|
eventSources: [ src ]
|
||||||
|
}));
|
||||||
|
|
||||||
|
me.quickview_active = id;
|
||||||
|
};
|
||||||
|
|
||||||
//public method to show the print dialog.
|
//public method to show the print dialog.
|
||||||
this.print_calendars = function(view)
|
this.print_calendars = function(view)
|
||||||
{
|
{
|
||||||
|
@ -2464,6 +2556,22 @@ function rcube_calendar_ui(settings)
|
||||||
{
|
{
|
||||||
var source = me.calendars[p.source];
|
var source = me.calendars[p.source];
|
||||||
|
|
||||||
|
// helper function to update the given fullcalendar view
|
||||||
|
function update_view(view, event, source) {
|
||||||
|
var existing = view.fullCalendar('clientEvents', event._id);
|
||||||
|
if (existing.length) {
|
||||||
|
$.extend(existing[0], event);
|
||||||
|
view.fullCalendar('updateEvent', existing[0]);
|
||||||
|
// remove old recurrence instances
|
||||||
|
if (event.recurrence && !event.recurrence_id)
|
||||||
|
view.fullCalendar('removeEvents', function(e){ return e._id.indexOf(event._id+'-') == 0; });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
event.source = source; // link with source
|
||||||
|
view.fullCalendar('renderEvent', event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (source && (p.refetch || (p.update && !source.active))) {
|
if (source && (p.refetch || (p.update && !source.active))) {
|
||||||
// activate event source if new event was added to an invisible calendar
|
// activate event source if new event was added to an invisible calendar
|
||||||
if (!source.active) {
|
if (!source.active) {
|
||||||
|
@ -2473,31 +2581,31 @@ function rcube_calendar_ui(settings)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fc.fullCalendar('refetchEvents', source);
|
fc.fullCalendar('refetchEvents', source);
|
||||||
|
|
||||||
|
if (this.quickview_active)
|
||||||
|
$('#quickview-calendar').fullCalendar('refetchEvents');
|
||||||
}
|
}
|
||||||
// add/update single event object
|
// add/update single event object
|
||||||
else if (source && p.update) {
|
else if (source && p.update) {
|
||||||
var event = p.update;
|
var event = p.update;
|
||||||
event.temp = false;
|
event.temp = false;
|
||||||
|
|
||||||
|
// update quickview
|
||||||
|
if (this.quickview_active)
|
||||||
|
update_view($('#quickview-calendar'), event, source);
|
||||||
|
// update fish-eye view
|
||||||
|
if (this.fisheye_date)
|
||||||
|
update_view($('#fish-eye-view'), event, source);
|
||||||
|
|
||||||
|
// update main view
|
||||||
event.editable = source.editable;
|
event.editable = source.editable;
|
||||||
var existing = fc.fullCalendar('clientEvents', event._id);
|
update_view(fc, event, source);
|
||||||
if (existing.length) {
|
|
||||||
$.extend(existing[0], event);
|
|
||||||
fc.fullCalendar('updateEvent', existing[0]);
|
|
||||||
// remove old recurrence instances
|
|
||||||
if (event.recurrence && !event.recurrence_id)
|
|
||||||
fc.fullCalendar('removeEvents', function(e){ return e._id.indexOf(event._id+'-') == 0; });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
event.source = source; // link with source
|
|
||||||
fc.fullCalendar('renderEvent', event);
|
|
||||||
}
|
|
||||||
// refresh fish-eye view
|
|
||||||
if (me.fisheye_date)
|
|
||||||
me.fisheye_view(me.fisheye_date);
|
|
||||||
}
|
}
|
||||||
// refetch all calendars
|
// refetch all calendars
|
||||||
else if (p.refetch) {
|
else if (p.refetch) {
|
||||||
fc.fullCalendar('refetchEvents');
|
fc.fullCalendar('refetchEvents');
|
||||||
|
if (this.quickview_active)
|
||||||
|
$('#quickview-calendar').fullCalendar('refetchEvents');
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove temp events
|
// remove temp events
|
||||||
|
@ -2811,6 +2919,18 @@ function rcube_calendar_ui(settings)
|
||||||
else
|
else
|
||||||
rcmail.display_message(rcmail.gettext('nocalendarsfound','calendar'), 'info');
|
rcmail.display_message(rcmail.gettext('nocalendarsfound','calendar'), 'info');
|
||||||
});
|
});
|
||||||
|
calendars_list.addEventListener('click-item', function(event) {
|
||||||
|
// handle clicks on quickview icon: temprarily add this source and open in quickview
|
||||||
|
if ($(event.target).hasClass('quickview') && event.data) {
|
||||||
|
if (!me.calendars[event.data.id]) {
|
||||||
|
event.data.readonly = true;
|
||||||
|
event.data.active = false;
|
||||||
|
event.data.subscribed = false;
|
||||||
|
add_calendar_source(event.data);
|
||||||
|
}
|
||||||
|
me.quickview(event.data.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 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){
|
||||||
|
@ -2839,6 +2959,14 @@ function rcube_calendar_ui(settings)
|
||||||
calendars_list.select(this.value);
|
calendars_list.select(this.value);
|
||||||
return rcube_event.cancel(e);
|
return rcube_event.cancel(e);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
// init (delegate) event handler on quickview links
|
||||||
|
.on('click', 'a.quickview', function(e) {
|
||||||
|
var id = $(this).closest('li').attr('id').replace(/^rcmlical/, '');
|
||||||
|
if (me.calendars[id])
|
||||||
|
me.quickview(id);
|
||||||
|
e.stopPropagation();
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// register dbl-click handler to open calendar edit dialog
|
// register dbl-click handler to open calendar edit dialog
|
||||||
|
@ -2859,75 +2987,19 @@ function rcube_calendar_ui(settings)
|
||||||
viewdate.setTime(fromunixtime(rcmail.env.date));
|
viewdate.setTime(fromunixtime(rcmail.env.date));
|
||||||
|
|
||||||
// initalize the fullCalendar plugin
|
// initalize the fullCalendar plugin
|
||||||
var fc = $('#calendar').fullCalendar({
|
var fc = $('#calendar').fullCalendar($.extend({}, fullcalendar_defaults, {
|
||||||
header: {
|
header: {
|
||||||
right: 'prev,next today',
|
right: 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
left: 'agendaDay,agendaWeek,month,table'
|
left: 'agendaDay,agendaWeek,month,table'
|
||||||
},
|
},
|
||||||
aspectRatio: 1,
|
|
||||||
date: viewdate.getDate(),
|
date: viewdate.getDate(),
|
||||||
month: viewdate.getMonth(),
|
month: viewdate.getMonth(),
|
||||||
year: viewdate.getFullYear(),
|
year: viewdate.getFullYear(),
|
||||||
ignoreTimezone: true, // will treat the given date strings as in local (browser's) timezone
|
|
||||||
height: $('#calendar').height(),
|
height: $('#calendar').height(),
|
||||||
eventSources: event_sources,
|
eventSources: event_sources,
|
||||||
monthNames : settings['months'],
|
|
||||||
monthNamesShort : settings['months_short'],
|
|
||||||
dayNames : settings['days'],
|
|
||||||
dayNamesShort : settings['days_short'],
|
|
||||||
firstDay : settings['first_day'],
|
|
||||||
firstHour : settings['first_hour'],
|
|
||||||
slotMinutes : 60/settings['timeslots'],
|
|
||||||
timeFormat: {
|
|
||||||
'': settings['time_format'],
|
|
||||||
agenda: settings['time_format'] + '{ - ' + settings['time_format'] + '}',
|
|
||||||
list: settings['time_format'] + '{ - ' + settings['time_format'] + '}',
|
|
||||||
table: settings['time_format'] + '{ - ' + settings['time_format'] + '}'
|
|
||||||
},
|
|
||||||
axisFormat : settings['time_format'],
|
|
||||||
columnFormat: {
|
|
||||||
month: 'ddd', // Mon
|
|
||||||
week: 'ddd ' + settings['date_short'], // Mon 9/7
|
|
||||||
day: 'dddd ' + settings['date_short'], // Monday 9/7
|
|
||||||
table: settings['date_agenda']
|
|
||||||
},
|
|
||||||
titleFormat: {
|
|
||||||
month: 'MMMM yyyy',
|
|
||||||
week: settings['dates_long'],
|
|
||||||
day: 'dddd ' + settings['date_long'],
|
|
||||||
table: settings['dates_long']
|
|
||||||
},
|
|
||||||
listPage: 1, // advance one day in agenda view
|
|
||||||
listRange: settings['agenda_range'],
|
|
||||||
listSections: settings['agenda_sections'],
|
|
||||||
tableCols: ['handle', 'date', 'time', 'title', 'location'],
|
|
||||||
defaultView: rcmail.env.view || settings['default_view'],
|
|
||||||
allDayText: rcmail.gettext('all-day', 'calendar'),
|
|
||||||
buttonText: {
|
|
||||||
prev: (bw.ie6 ? ' << ' : ' ◄ '),
|
|
||||||
next: (bw.ie6 ? ' >> ' : ' ► '),
|
|
||||||
today: settings['today'],
|
|
||||||
day: rcmail.gettext('day', 'calendar'),
|
|
||||||
week: rcmail.gettext('week', 'calendar'),
|
|
||||||
month: rcmail.gettext('month', 'calendar'),
|
|
||||||
table: rcmail.gettext('agenda', 'calendar')
|
|
||||||
},
|
|
||||||
listTexts: {
|
|
||||||
until: rcmail.gettext('until', 'calendar'),
|
|
||||||
past: rcmail.gettext('pastevents', 'calendar'),
|
|
||||||
today: rcmail.gettext('today', 'calendar'),
|
|
||||||
tomorrow: rcmail.gettext('tomorrow', 'calendar'),
|
|
||||||
thisWeek: rcmail.gettext('thisweek', 'calendar'),
|
|
||||||
nextWeek: rcmail.gettext('nextweek', 'calendar'),
|
|
||||||
thisMonth: rcmail.gettext('thismonth', 'calendar'),
|
|
||||||
nextMonth: rcmail.gettext('nextmonth', 'calendar'),
|
|
||||||
future: rcmail.gettext('futureevents', 'calendar'),
|
|
||||||
week: rcmail.gettext('weekofyear', 'calendar')
|
|
||||||
},
|
|
||||||
selectable: true,
|
selectable: true,
|
||||||
selectHelper: false,
|
selectHelper: false,
|
||||||
currentTimeIndicator: settings.time_indicator,
|
|
||||||
loading: function(isLoading) {
|
loading: function(isLoading) {
|
||||||
me.is_loading = isLoading;
|
me.is_loading = isLoading;
|
||||||
this._rc_loading = rcmail.set_busy(isLoading, 'loading', this._rc_loading);
|
this._rc_loading = rcmail.set_busy(isLoading, 'loading', this._rc_loading);
|
||||||
|
@ -2935,13 +3007,6 @@ function rcube_calendar_ui(settings)
|
||||||
if (!isLoading)
|
if (!isLoading)
|
||||||
me.events_loaded($(this).fullCalendar('clientEvents').length);
|
me.events_loaded($(this).fullCalendar('clientEvents').length);
|
||||||
},
|
},
|
||||||
// event rendering
|
|
||||||
eventRender: fc_event_render,
|
|
||||||
// render element indicating more (invisible) events
|
|
||||||
overflowRender: function(data, element) {
|
|
||||||
element.html(rcmail.gettext('andnmore', 'calendar').replace('$nr', data.count))
|
|
||||||
.click(function(e){ me.fisheye_view(data.date); });
|
|
||||||
},
|
|
||||||
// callback for date range selection
|
// callback for date range selection
|
||||||
select: function(start, end, allDay, e, view) {
|
select: function(start, end, allDay, e, view) {
|
||||||
var range_select = (!allDay || start.getDate() != end.getDate())
|
var range_select = (!allDay || start.getDate() != end.getDate())
|
||||||
|
@ -2966,11 +3031,6 @@ function rcube_calendar_ui(settings)
|
||||||
day_clicked = date.getTime();
|
day_clicked = date.getTime();
|
||||||
day_clicked_ts = now;
|
day_clicked_ts = now;
|
||||||
},
|
},
|
||||||
// callback when a specific event is clicked
|
|
||||||
eventClick: function(event, ev, view) {
|
|
||||||
if (!event.temp)
|
|
||||||
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) {
|
||||||
if (event.end == null || event.end.getTime() < event.start.getTime()) {
|
if (event.end == null || event.end.getTime() < event.start.getTime()) {
|
||||||
|
@ -3040,7 +3100,7 @@ function rcube_calendar_ui(settings)
|
||||||
if (fc && view.name == 'month')
|
if (fc && view.name == 'month')
|
||||||
fc.fullCalendar('option', 'maxHeight', Math.floor((view.element.parent().height()-18) / 6) - 35);
|
fc.fullCalendar('option', 'maxHeight', Math.floor((view.element.parent().height()-18) / 6) - 35);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
// format time string
|
// format time string
|
||||||
var formattime = function(hour, minutes, start) {
|
var formattime = function(hour, minutes, start) {
|
||||||
|
|
|
@ -210,8 +210,10 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get events from the user's free/busy feed
|
// get events from the user's free/busy feed (for quickview only)
|
||||||
|
if (!empty($_REQUEST['_quickview']) && empty($search)) {
|
||||||
$this->fetch_freebusy($limit_changed);
|
$this->fetch_freebusy($limit_changed);
|
||||||
|
}
|
||||||
|
|
||||||
$events = array();
|
$events = array();
|
||||||
foreach ($this->events as $id => $event) {
|
foreach ($this->events as $id => $event) {
|
||||||
|
@ -281,7 +283,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
|
|
||||||
// console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
|
// console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
|
||||||
|
|
||||||
// parse free-busy information using Horde classes
|
// parse free-busy information
|
||||||
$count = 0;
|
$count = 0;
|
||||||
if ($fbdata) {
|
if ($fbdata) {
|
||||||
$ical = $this->cal->get_ical();
|
$ical = $this->cal->get_ical();
|
||||||
|
@ -304,6 +306,7 @@ class kolab_user_calendar extends kolab_calendar
|
||||||
'start' => $from,
|
'start' => $from,
|
||||||
'end' => $to,
|
'end' => $to,
|
||||||
'free_busy' => $statusmap[$type] ?: 'busy',
|
'free_busy' => $statusmap[$type] ?: 'busy',
|
||||||
|
'className' => 'fc-type-freebusy',
|
||||||
'organizer' => array(
|
'organizer' => array(
|
||||||
'email' => $this->userdata['mail'],
|
'email' => $this->userdata['mail'],
|
||||||
'name' => $this->userdata['displayname'],
|
'name' => $this->userdata['displayname'],
|
||||||
|
|
|
@ -308,6 +308,7 @@ class calendar_ui
|
||||||
html::span(array('class' => 'calname', 'id' => $label_id, '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'], 'aria-labelledby' => $label_id), '') .
|
html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') .
|
||||||
|
html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->cal->gettext('quickview'), 'role' => 'checkbox', 'aria-checked' => 'false'), '') .
|
||||||
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '') .
|
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '') .
|
||||||
html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' ')
|
html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' ')
|
||||||
)
|
)
|
||||||
|
|
|
@ -94,6 +94,7 @@ $labels['calsearchresults'] = 'Available Calendars';
|
||||||
$labels['calendarsubscribe'] = 'List permanently';
|
$labels['calendarsubscribe'] = 'List permanently';
|
||||||
$labels['nocalendarsfound'] = 'No calendars found';
|
$labels['nocalendarsfound'] = 'No calendars found';
|
||||||
$labels['nrcalendarsfound'] = '$nr calendars found';
|
$labels['nrcalendarsfound'] = '$nr calendars found';
|
||||||
|
$labels['quickview'] = 'View only this calendar';
|
||||||
|
|
||||||
// agenda view
|
// agenda view
|
||||||
$labels['listrange'] = 'Range to display:';
|
$labels['listrange'] = 'Range to display:';
|
||||||
|
|
|
@ -219,11 +219,11 @@ pre {
|
||||||
|
|
||||||
#calendars .treelist li span.calname {
|
#calendars .treelist li span.calname {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0px 30px 2px 2px;
|
padding: 0px 18px 2px 2px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
left: 38px;
|
left: 38px;
|
||||||
right: 40px;
|
right: 60px;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
background: url(images/calendars.png) right 20px no-repeat;
|
background: url(images/calendars.png) right 20px no-repeat;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -240,7 +240,7 @@ pre {
|
||||||
|
|
||||||
#calendars .treelist.flat li span.calname {
|
#calendars .treelist.flat li span.calname {
|
||||||
left: 24px;
|
left: 24px;
|
||||||
right: 22px;
|
right: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendars .treelist li span.handle {
|
#calendars .treelist li span.handle {
|
||||||
|
@ -288,6 +288,29 @@ pre {
|
||||||
background-position: -16px -110px;
|
background-position: -16px -110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#calendars .treelist li a.quickview {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 42px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 0;
|
||||||
|
background: url(images/calendars.png) -100px 0 no-repeat;
|
||||||
|
overflow: hidden;
|
||||||
|
text-indent: -5000px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#calendars .treelist div > a.quickview:focus,
|
||||||
|
#calendars .treelist li div:hover > a.quickview {
|
||||||
|
background-position: 0 -128px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#calendars .treelist li div.focusview > a.quickview {
|
||||||
|
background-position: -18px -128px;
|
||||||
|
}
|
||||||
|
|
||||||
#calendars .treelist li input {
|
#calendars .treelist li input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
|
@ -1316,9 +1339,26 @@ a.dropdown-link:after {
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#quickview-calendar {
|
||||||
|
padding: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.calendarmain .fc-button,
|
.calendarmain .fc-button,
|
||||||
.calendarmain .fc-button.fc-state-default,
|
.calendarmain .fc-button.fc-state-default,
|
||||||
.calendarmain .fc-button.fc-state-hover {
|
.calendarmain .fc-button.fc-state-hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
|
||||||
|
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
|
||||||
|
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
|
||||||
|
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
|
||||||
|
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendarmain #calendar .fc-button,
|
||||||
|
.calendarmain #calendar .fc-button.fc-state-default,
|
||||||
|
.calendarmain #calendar .fc-button.fc-state-hover {
|
||||||
margin: 0 0 0 0;
|
margin: 0 0 0 0;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
@ -1338,22 +1378,15 @@ a.dropdown-link:after {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-button.fc-state-disabled {
|
.calendarmain #calendar .fc-button.fc-state-disabled {
|
||||||
color: #999;
|
color: #999;
|
||||||
background: #d8d8d8;
|
background: #d8d8d8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-button.fc-state-down {
|
.calendarmain .fc-button.fc-state-active,
|
||||||
margin: 0;
|
.calendarmain .fc-button.fc-state-down,
|
||||||
background: #bababa;
|
.calendarmain #calendar .fc-button.fc-state-active,
|
||||||
background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
.calendarmain #calendar .fc-button.fc-state-down {
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bababa), color-stop(100%,#d8d8d8));
|
|
||||||
background: -o-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
|
||||||
background: -ms-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
|
||||||
background: linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendarmain .fc-button.fc-state-active {
|
|
||||||
color: #333;
|
color: #333;
|
||||||
background: #bababa;
|
background: #bababa;
|
||||||
background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
||||||
|
@ -1363,12 +1396,12 @@ a.dropdown-link:after {
|
||||||
background: linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
background: linear-gradient(top, #bababa 0%, #d8d8d8 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header .fc-button {
|
.calendarmain #calendar .fc-header .fc-button {
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button {
|
.calendarmain #calendar .fc-header-left .fc-button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -1393,58 +1426,58 @@ a.dropdown-link:after {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button:focus {
|
.calendarmain #calendar .fc-header-left .fc-button:focus {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-shadow: 0px 1px 1px #666;
|
text-shadow: 0px 1px 1px #666;
|
||||||
background-color: rgba(30,150,192, 0.5);
|
background-color: rgba(30,150,192, 0.5);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button.fc-state-active {
|
.calendarmain #calendar .fc-header-left .fc-button.fc-state-active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #222;
|
color: #222;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-agendaDay {
|
.calendarmain #calendar .fc-header-left .fc-button-agendaDay {
|
||||||
background-position: center -120px;
|
background-position: center -120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-agendaDay.fc-state-active {
|
.calendarmain #calendar .fc-header-left .fc-button-agendaDay.fc-state-active {
|
||||||
background-position: center -160px;
|
background-position: center -160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-agendaWeek {
|
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek {
|
||||||
background-position: center -200px;
|
background-position: center -200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-agendaWeek.fc-state-active {
|
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek.fc-state-active {
|
||||||
background-position: center -240px;
|
background-position: center -240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-month {
|
.calendarmain #calendar .fc-header-left .fc-button-month {
|
||||||
background-position: center -280px;
|
background-position: center -280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-month.fc-state-active {
|
.calendarmain #calendar .fc-header-left .fc-button-month.fc-state-active {
|
||||||
background-position: center -320px;
|
background-position: center -320px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-table {
|
.calendarmain #calendar .fc-header-left .fc-button-table {
|
||||||
background-position: center -360px;
|
background-position: center -360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-left .fc-button-table.fc-state-active {
|
.calendarmain #calendar .fc-header-left .fc-button-table.fc-state-active {
|
||||||
background-position: center -400px;
|
background-position: center -400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendarmain .fc-header-right {
|
.calendarmain #calendar .fc-header-right {
|
||||||
padding-right: 252px;
|
padding-right: 252px;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-header-title {
|
.calendarmain #calendar .fc-header-title {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1452,6 +1485,39 @@ a.dropdown-link:after {
|
||||||
font-size: 1em !important;
|
font-size: 1em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-type-freebusy {
|
||||||
|
opacity: 0.55;
|
||||||
|
color: #fff !important;
|
||||||
|
|
||||||
|
background: rgba(80,80,80,0.85) !important;
|
||||||
|
background: -moz-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.9) 100%) !important;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(80,80,80,0.85)), color-stop(100%,rgba(48,48,48,0.9))) !important;
|
||||||
|
background: -webkit-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
|
||||||
|
background: -o-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
|
||||||
|
background: -ms-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
|
||||||
|
background: linear-gradient(to bottom, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
|
||||||
|
|
||||||
|
-moz-box-shadow: inset 0px 1px 0 0px #888;
|
||||||
|
-webkit-box-shadow: inset 0px 1px 0 0px #888;
|
||||||
|
-o-box-shadow: inset 0px 1px 0 0px #888;
|
||||||
|
box-shadow: inset 0px 1px 0 0px #888;
|
||||||
|
|
||||||
|
border-color: #444 !important;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-type-freebusy .fc-event-skin,
|
||||||
|
.fc-type-freebusy .fc-event-inner {
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-color: #444 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
text-shadow: 0 1px 1px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-type-freebusy .fc-event-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.calendarmain .fc-event:focus {
|
.calendarmain .fc-event:focus {
|
||||||
outline: 1px solid rgba(71,135,177, 0.4);
|
outline: 1px solid rgba(71,135,177, 0.4);
|
||||||
-webkit-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
|
-webkit-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.6 KiB |
Loading…
Add table
Reference in a new issue