View: 3.4: Fish-Eye View For Busy Days

This commit is contained in:
Thomas 2011-09-07 17:40:20 +02:00
parent def64e251f
commit 0a367cbe29
7 changed files with 181 additions and 52 deletions

View file

@ -25,7 +25,6 @@ function rcube_calendar_ui(settings)
this.selected_event = null;
this.selected_calendar = null;
this.search_request = null;
this.eventcount = [];
this.saving_lock = null;
@ -251,7 +250,7 @@ function rcube_calendar_ui(settings)
// event details dialog (show only)
var event_show_dialog = function(event)
{
var $dialog = $("#eventshow").removeClass().addClass('uidialog');
var $dialog = $("#eventshow").dialog('close').removeClass().addClass('uidialog');
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:false };
me.selected_event = event;
@ -1564,9 +1563,126 @@ function rcube_calendar_ui(settings)
return true;
};
/*** fullcalendar event handlers ***/
var fc_event_render = function(event, element, view) {
if (view.name != 'list' && view.name != 'table') {
var prefix = event.sensitivity != 0 ? String(sensitivitylabels[event.sensitivity]).toUpperCase()+': ' : '';
element.attr('title', prefix + event.title);
}
if (view.name == 'month') {
// limit the number of events displayed
var sday = event.start.getMonth()*120 + event.start.getDate();
var eday = event.end.getMonth()*120 + event.end.getDate();
if (!view._eventcount[sday]) view._eventcount[sday] = 1;
else view._eventcount[sday]++;
if (!view._eventcount[eday]) view._eventcount[eday] = 1;
else if (eday != sday) view._eventcount[eday]++;
if (view._eventcount[sday] >= view._maxevents) {
if (!view._morelink[sday]) {
view._morelink[sday] = view._morelink[event.id] = $('<div>')
.addClass('fc-event-more')
.css({ position:'absolute', left:element.css('left'), width:element.css('width') })
.appendTo(element.parent())
.data('overflow', 1);
}
else {
view._morelink[sday].data('overflow', view._eventcount[sday] - view._maxevents);
return false;
}
}
else if (view._eventcount[eday] >= view._maxevents || view._morelink[event.id]) {
return false;
}
}
else {
if (event.location) {
element.find('div.fc-event-title').after('<div class="fc-event-location">@&nbsp;' + Q(event.location) + '</div>');
}
if (event.sensitivity != 0)
element.find('div.fc-event-time').append('<i class="fc-icon-sensitive"></i>');
if (event.recurrence)
element.find('div.fc-event-time').append('<i class="fc-icon-recurring"></i>');
if (event.alarms)
element.find('div.fc-event-time').append('<i class="fc-icon-alarms"></i>');
}
};
/*** public methods ***/
// opens calendar day-view in a popup
this.fisheye_view = function(date)
{
$('#fish-eye-view').dialog('close');
// create list of active event sources
var src, cals = {}, sources = [];
for (var id in this.calendars) {
src = $.extend({}, this.calendars[id]);
src.editable = false;
src.url = null;
src.events = [];
if (cal.active) {
cals[id] = src;
sources.push(src);
}
}
// copy events already loaded
var events = fc.fullCalendar('clientEvents');
for (var event, i=0; i< events.length; i++) {
event = events[i];
if (event.source && (src = cals[event.source.id])) {
src.events.push(event);
}
}
var h = $(window).height() - 50;
var dialog = $('<div>')
.attr('id', 'fish-eye-view')
.dialog({
modal: true,
width: 680,
height: h,
title: $.fullCalendar.formatDate(date, 'dddd ' + settings['date_long']),
close: function(){
dialog.dialog("destroy");
me.fisheye_date = null;
}
})
.fullCalendar({
header: { left: '', center: '', right: '' },
height: h - 50,
defaultView: 'agendaDay',
date: date.getDate(),
month: date.getMonth(),
year: date.getFullYear(),
ignoreTimezone: true, // will treat the given date strings as in local (browser's) timezone
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'),
eventRender: fc_event_render,
eventClick: function(event) {
event_show_dialog(event);
}
});
this.fisheye_date = date;
};
//public method to show the print dialog.
this.print_calendars = function(view)
{
@ -1813,6 +1929,9 @@ function rcube_calendar_ui(settings)
});
}
}
if (this.fisheye_date)
this.fisheye_view(this.fisheye_date);
};
// resize and reposition (center) the dialog window
@ -1955,37 +2074,19 @@ function rcube_calendar_ui(settings)
me.events_loaded($(this).fullCalendar('clientEvents').length);
},
// event rendering
eventRender: function(event, element, view) {
if (view.name != 'list' && view.name != 'table') {
var prefix = event.sensitivity != 0 ? String(sensitivitylabels[event.sensitivity]).toUpperCase()+': ' : '';
element.attr('title', prefix + event.title);
}
if (view.name == 'month') {
/* attempt to limit the number of events displayed
(could also be used to init fish-eye-view)
var max = 4; // to be derrived from window size
var sday = event.start.getMonth()*12 + event.start.getDate();
var eday = event.end.getMonth()*12 + event.end.getDate();
if (!me.eventcount[sday]) me.eventcount[sday] = 1;
else me.eventcount[sday]++;
if (!me.eventcount[eday]) me.eventcount[eday] = 1;
else if (eday != sday) me.eventcount[eday]++;
if (me.eventcount[sday] > max || me.eventcount[eday] > max)
return false;
*/
}
else {
if (event.location) {
element.find('div.fc-event-title').after('<div class="fc-event-location">@&nbsp;' + Q(event.location) + '</div>');
}
if (event.sensitivity != 0)
element.find('div.fc-event-time').append('<i class="fc-icon-sensitive"></i>');
if (event.recurrence)
element.find('div.fc-event-time').append('<i class="fc-icon-recurring"></i>');
if (event.alarms)
element.find('div.fc-event-time').append('<i class="fc-icon-alarms"></i>');
eventRender: fc_event_render,
eventAfterRender: function(event, element, view) {
// adjust position of the more... element
var link;
if (view.name == 'month' && (link = view._morelink[event.id]) && !link.data('date') && link.data('overflow') > 1) {
link.html(rcmail.gettext('andnmore', 'calendar').replace('$nr', link.data('overflow')))
.css({ left:element.css('left'), top:element.css('top') })
.data('date', new Date(event.start.getTime()))
.click(function(e){ me.fisheye_view($(this).data('date')); });
element.remove();
}
else if (link)
link.remove();
},
// callback for date range selection
select: function(start, end, allDay, e, view) {
@ -2066,14 +2167,13 @@ function rcube_calendar_ui(settings)
update_event_confirm('resize', event, data);
},
viewDisplay: function(view) {
me.eventcount = [];
if (!bw.ie)
window.setTimeout(function(){ $('div.fc-content').css('overflow', view.name == 'month' ? 'auto' : 'hidden') }, 10);
if (minical)
window.setTimeout(function(){ minical.datepicker('setDate', fc.fullCalendar('getDate')); }, exec_deferred);
},
windowResize: function(view) {
me.eventcount = [];
viewRender: function(view) {
view._maxevents = Math.floor((view.element.parent().height()-18) / 108) - 1;
view._eventcount = [];
view._morelink = [];
}
});
@ -2387,6 +2487,10 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
event.source = source; // link with source
fc.fullCalendar('renderEvent', event);
}
// refresh fish-eye view
if (cal.fisheye_date)
cal.fisheye_view(cal.fisheye_date);
}
// remove temp events

View file

@ -1,5 +1,5 @@
--- js/fullcalendar.js.orig 2011-04-09 14:13:16.000000000 +0200
+++ js/fullcalendar.js 2011-08-07 18:43:34.000000000 +0200
+++ js/fullcalendar.js 2011-09-07 11:53:03.000000000 +0200
@@ -47,12 +47,16 @@
titleFormat: {
month: 'MMMM yyyy',
@ -49,7 +49,15 @@
// jquery-ui theming
theme: false,
@@ -500,8 +524,8 @@
@@ -424,6 +448,7 @@
setSize();
unselect();
currentView.clearEvents();
+ currentView.trigger('viewRender', currentView);
currentView.renderEvents(events);
currentView.sizeDirty = false;
}
@@ -500,8 +525,8 @@
}
@ -60,7 +68,15 @@
}
@@ -632,6 +656,8 @@
@@ -523,6 +548,7 @@
markEventsDirty();
if (elementVisible()) {
currentView.clearEvents();
+ currentView.trigger('viewRender', currentView);
currentView.renderEvents(events, modifiedEventID);
currentView.eventsDirty = false;
}
@@ -632,6 +658,8 @@
if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
options[name] = value;
updateSize();
@ -69,7 +85,7 @@
}
}
@@ -897,15 +923,16 @@
@@ -897,15 +925,16 @@
}
@ -90,7 +106,7 @@
}
}
@@ -1579,10 +1606,23 @@
@@ -1579,10 +1608,23 @@
return 'th';
}
return ['st', 'nd', 'rd'][date%10-1] || 'th';
@ -115,7 +131,7 @@
fc.applyAll = applyAll;
@@ -3534,10 +3574,10 @@
@@ -3534,10 +3576,10 @@
function slotSelectionMousedown(ev) {
if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button
unselect(ev);
@ -128,7 +144,7 @@
var d1 = cellDate(origCell);
var d2 = cellDate(cell);
dates = [
@@ -3762,7 +3802,8 @@
@@ -3762,7 +3804,8 @@
height,
slotSegmentContainer = getSlotSegmentContainer(),
rtl, dis, dit,
@ -138,7 +154,7 @@
if (rtl = opt('isRTL')) {
dis = -1;
@@ -3789,8 +3830,11 @@
@@ -3789,8 +3832,11 @@
outerWidth = availWidth / (levelI + forward + 1);
}else{
if (forward) {
@ -152,7 +168,7 @@
}else{
// can be entire width, aligned left
outerWidth = availWidth;
@@ -3801,7 +3845,7 @@
@@ -3801,7 +3847,7 @@
* dis + (rtl ? availWidth - outerWidth : 0); // rtl
seg.top = top;
seg.left = left;
@ -161,7 +177,7 @@
seg.outerHeight = bottom - top;
html += slotSegHtml(event, seg);
}
@@ -4260,7 +4304,7 @@
@@ -4260,7 +4306,7 @@
function opt(name, viewNameOverride) {
var v = options[name];
@ -170,7 +186,7 @@
return smartProperty(v, viewNameOverride || viewName);
}
return v;
@@ -5204,5 +5248,561 @@
@@ -5204,5 +5250,561 @@
};
}

View file

@ -448,6 +448,7 @@ function Calendar(element, options, eventSources) {
setSize();
unselect();
currentView.clearEvents();
currentView.trigger('viewRender', currentView);
currentView.renderEvents(events);
currentView.sizeDirty = false;
}
@ -547,6 +548,7 @@ function Calendar(element, options, eventSources) {
markEventsDirty();
if (elementVisible()) {
currentView.clearEvents();
currentView.trigger('viewRender', currentView);
currentView.renderEvents(events, modifiedEventID);
currentView.eventsDirty = false;
}

View file

@ -64,7 +64,7 @@ $labels['printdescriptions'] = 'Beschrieb drucken';
$labels['parentcalendar'] = 'Übergeordneter Kalender';
$labels['searchearlierdates'] = '« Frühere Termine suchen';
$labels['searchlaterdates'] = 'Spätere Termine suchen »';
$labels['andnmore'] = 'und $nr weitere';
$labels['andnmore'] = '$nr weitere...';
$labels['togglerole'] = 'Klick zum Ändern der Rolle';
// alarm/reminder settings

View file

@ -64,7 +64,7 @@ $labels['printdescriptions'] = 'Beschrieb drucken';
$labels['parentcalendar'] = 'Übergeordneter Kalender';
$labels['searchearlierdates'] = '« Frühere Termine suchen';
$labels['searchlaterdates'] = 'Spätere Termine suchen »';
$labels['andnmore'] = 'und $nr weitere';
$labels['andnmore'] = '$nr weitere...';
// alarm/reminder settings
$labels['showalarms'] = 'Erinnerungen anzeigen';

View file

@ -64,7 +64,7 @@ $labels['printdescriptions'] = 'Print descriptions';
$labels['parentcalendar'] = 'Superior calendar';
$labels['searchearlierdates'] = '« Search for earlier events';
$labels['searchlaterdates'] = 'Search for later events »';
$labels['andnmore'] = 'and $nr more';
$labels['andnmore'] = '$nr more...';
$labels['togglerole'] = 'Click to toggle role';
// alarm/reminder settings

View file

@ -1026,6 +1026,13 @@ div.fc-event-location {
font-size: 90%;
}
.fc-event-more {
color: #999;
font-size: 90%;
padding-top: 1px;
cursor: pointer;
}
.fc-agenda-slots td div {
height: 22px;
}