Implement quickview for calendars, showing free-busy data for other user's calendars (#3043)

This commit is contained in:
Thomas Bruederli 2014-06-26 17:42:32 +02:00
parent 30c6840269
commit ab43057b1f
7 changed files with 289 additions and 157 deletions

View file

@ -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;
} }

View file

@ -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: '&nbsp;&#9668;&nbsp;',
next: '&nbsp;&#9658;&nbsp;',
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('&raquo;', '»').replace('&nbsp;', ' '),
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 ? '&nbsp;&lt;&lt;&nbsp;' : '&nbsp;&#9668;&nbsp;'),
next: (bw.ie6 ? '&nbsp;&gt;&gt;&nbsp;' : '&nbsp;&#9658;&nbsp;'),
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) {

View file

@ -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'],

View file

@ -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')), '&nbsp;') html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), '&nbsp;')
) )

View file

@ -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:';

View file

@ -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