Fixed smart event segmentation in list view; added table view (derived from list view) as alternative
This commit is contained in:
parent
5f7e3b6029
commit
b45566de9e
7 changed files with 405 additions and 72 deletions
|
@ -739,7 +739,7 @@ function rcube_calendar(settings)
|
||||||
header: {
|
header: {
|
||||||
left: 'prev,next today',
|
left: 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
right: 'agendaDay,agendaWeek,month,list'
|
right: 'agendaDay,agendaWeek,month,list,table'
|
||||||
},
|
},
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
ignoreTimezone: false, // will translate event dates to the client's timezone
|
ignoreTimezone: false, // will translate event dates to the client's timezone
|
||||||
|
@ -754,20 +754,25 @@ function rcube_calendar(settings)
|
||||||
slotMinutes : 60/settings['timeslots'],
|
slotMinutes : 60/settings['timeslots'],
|
||||||
timeFormat: {
|
timeFormat: {
|
||||||
'': settings['time_format'],
|
'': settings['time_format'],
|
||||||
list: settings['time_format'] + '{ - ' + settings['time_format'] + '}'
|
list: settings['time_format'] + '{ - ' + settings['time_format'] + '}',
|
||||||
|
table: settings['time_format'] + '{ - ' + settings['time_format'] + '}'
|
||||||
},
|
},
|
||||||
axisFormat : settings['time_format'],
|
axisFormat : settings['time_format'],
|
||||||
columnFormat: {
|
columnFormat: {
|
||||||
month: 'ddd', // Mon
|
month: 'ddd', // Mon
|
||||||
week: 'ddd ' + settings['date_short'], // Mon 9/7
|
week: 'ddd ' + settings['date_short'], // Mon 9/7
|
||||||
day: 'dddd ' + settings['date_short'] // Monday 9/7
|
day: 'dddd ' + settings['date_short'], // Monday 9/7
|
||||||
|
list: settings['date_agena'],
|
||||||
|
table: settings['date_agena']
|
||||||
},
|
},
|
||||||
titleFormat: {
|
titleFormat: {
|
||||||
month: 'MMMM yyyy',
|
month: 'MMMM yyyy',
|
||||||
week: settings['date_long'].replace(/ yyyy/, '[ yyyy]') + "{ '—' " + settings['date_long'] + "}",
|
week: settings['date_long'].replace(/ yyyy/, '[ yyyy]') + "{ '—' " + settings['date_long'] + "}",
|
||||||
day: 'dddd ' + settings['date_long'],
|
day: 'dddd ' + settings['date_long'],
|
||||||
list: settings['date_long']
|
list: settings['date_long'],
|
||||||
|
table: settings['date_long']
|
||||||
},
|
},
|
||||||
|
smartSections: true,
|
||||||
defaultView: settings['default_view'],
|
defaultView: settings['default_view'],
|
||||||
allDayText: rcmail.gettext('all-day', 'calendar'),
|
allDayText: rcmail.gettext('all-day', 'calendar'),
|
||||||
buttonText: {
|
buttonText: {
|
||||||
|
@ -776,7 +781,7 @@ function rcube_calendar(settings)
|
||||||
week: rcmail.gettext('week', 'calendar'),
|
week: rcmail.gettext('week', 'calendar'),
|
||||||
month: rcmail.gettext('month', 'calendar'),
|
month: rcmail.gettext('month', 'calendar'),
|
||||||
list: rcmail.gettext('agenda', 'calendar'),
|
list: rcmail.gettext('agenda', 'calendar'),
|
||||||
basicDay: 'basic'
|
table: rcmail.gettext('table', 'calendar')
|
||||||
},
|
},
|
||||||
selectable: true,
|
selectable: true,
|
||||||
selectHelper: true,
|
selectHelper: true,
|
||||||
|
@ -785,7 +790,7 @@ function rcube_calendar(settings)
|
||||||
},
|
},
|
||||||
// event rendering
|
// event rendering
|
||||||
eventRender: function(event, element, view) {
|
eventRender: function(event, element, view) {
|
||||||
if (view.name != 'list')
|
if (view.name != 'list' && view.name != 'table')
|
||||||
element.attr('title', event.title);
|
element.attr('title', event.title);
|
||||||
if (view.name == 'month') {
|
if (view.name == 'month') {
|
||||||
/* attempt to limit the number of events displayed
|
/* attempt to limit the number of events displayed
|
||||||
|
@ -940,7 +945,7 @@ function rcube_calendar(settings)
|
||||||
var shift_enddate = function(dateText) {
|
var shift_enddate = function(dateText) {
|
||||||
var newstart = parse_datetime('0', dateText);
|
var newstart = parse_datetime('0', dateText);
|
||||||
var newend = new Date(newstart.getTime() + $('#edit-startdate').data('duration') * 1000);
|
var newend = new Date(newstart.getTime() + $('#edit-startdate').data('duration') * 1000);
|
||||||
$('#edit-enddate').val($.fullCalendar.formatDate(newend, cal.settings['date_format']));
|
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format']));
|
||||||
};
|
};
|
||||||
|
|
||||||
// init event dialog
|
// init event dialog
|
||||||
|
|
|
@ -370,6 +370,7 @@ class calendar extends rcube_plugin
|
||||||
else
|
else
|
||||||
$this->rc->output->show_message('calendar.errorsaving', 'error');
|
$this->rc->output->show_message('calendar.errorsaving', 'error');
|
||||||
|
|
||||||
|
// TODO: keep view and date selection
|
||||||
if ($success && $reload)
|
if ($success && $reload)
|
||||||
$this->rc->output->redirect('');
|
$this->rc->output->redirect('');
|
||||||
}
|
}
|
||||||
|
@ -478,6 +479,7 @@ class calendar extends rcube_plugin
|
||||||
$settings['date_format'] = (string)$this->rc->config->get('calendar_date_format', "yyyy/MM/dd");
|
$settings['date_format'] = (string)$this->rc->config->get('calendar_date_format', "yyyy/MM/dd");
|
||||||
$settings['date_short'] = (string)$this->rc->config->get('calendar_date_short', "M/d");
|
$settings['date_short'] = (string)$this->rc->config->get('calendar_date_short', "M/d");
|
||||||
$settings['date_long'] = (string)$this->rc->config->get('calendar_date_long', "M d yyyy");
|
$settings['date_long'] = (string)$this->rc->config->get('calendar_date_long', "M d yyyy");
|
||||||
|
$settings['date_agena'] = (string)$this->rc->config->get('calendar_date_agenda', "ddd M d");
|
||||||
$settings['time_format'] = (string)$this->rc->config->get('calendar_time_format', "HH:mm");
|
$settings['time_format'] = (string)$this->rc->config->get('calendar_time_format', "HH:mm");
|
||||||
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', 2);
|
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', 2);
|
||||||
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', 1);
|
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', 1);
|
||||||
|
|
|
@ -40,6 +40,9 @@ $rcmail_config['calendar_date_short'] = 'M-d';
|
||||||
// long date format (used for calendar title)
|
// long date format (used for calendar title)
|
||||||
$rcmail_config['calendar_date_long'] = 'MMM d yyyy';
|
$rcmail_config['calendar_date_long'] = 'MMM d yyyy';
|
||||||
|
|
||||||
|
// date format used for agenda view
|
||||||
|
$rcmail_config['calendar_date_agenda'] = 'ddd MM-dd';
|
||||||
|
|
||||||
// timeslots per hour (1, 2, 3, 4, 6)
|
// timeslots per hour (1, 2, 3, 4, 6)
|
||||||
$rcmail_config['calendar_timeslots'] = 2;
|
$rcmail_config['calendar_timeslots'] = 2;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
--- js/fullcalendar.js.orig 2011-06-04 13:45:44.000000000 -0600
|
--- js/fullcalendar.js.orig 2011-06-04 13:45:44.000000000 -0600
|
||||||
+++ js/fullcalendar.js 2011-06-08 14:30:33.000000000 -0600
|
+++ js/fullcalendar.js 2011-06-10 09:27:50.000000000 -0600
|
||||||
@@ -47,12 +47,14 @@
|
@@ -47,12 +47,14 @@
|
||||||
titleFormat: {
|
titleFormat: {
|
||||||
month: 'MMMM yyyy',
|
month: 'MMMM yyyy',
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
+ thisWeek: 'This week',
|
+ thisWeek: 'This week',
|
||||||
+ nextWeek: 'Next week',
|
+ nextWeek: 'Next week',
|
||||||
+ thisMonth: 'This month',
|
+ thisMonth: 'This month',
|
||||||
+ nextMonth: 'Next Month',
|
+ nextMonth: 'Next month',
|
||||||
+ future: 'Future events'
|
+ future: 'Future events'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -59,19 +59,19 @@
|
||||||
rangeStart = start;
|
rangeStart = start;
|
||||||
rangeEnd = end;
|
rangeEnd = end;
|
||||||
- cache = [];
|
- cache = [];
|
||||||
+ cache = typeof src != 'undefined' ? $.grep(cache, function(e) { return !isSourcesEqual(e.source, source); }) : [];
|
+ cache = typeof src != 'undefined' ? $.grep(cache, function(e) { return !isSourcesEqual(e.source, src); }) : [];
|
||||||
var fetchID = ++currentFetchID;
|
var fetchID = ++currentFetchID;
|
||||||
var len = sources.length;
|
var len = sources.length;
|
||||||
- pendingSourceCnt = len;
|
- pendingSourceCnt = len;
|
||||||
+ pendingSourceCnt = typeof src == 'undefined' ? len : 1;
|
+ pendingSourceCnt = typeof src == 'undefined' ? len : 1;
|
||||||
for (var i=0; i<len; i++) {
|
for (var i=0; i<len; i++) {
|
||||||
- fetchEventSource(sources[i], fetchID);
|
- fetchEventSource(sources[i], fetchID);
|
||||||
+ if (typeof src == 'undefined' || src == sources[i])
|
+ if (typeof src == 'undefined' || isSourcesEqual(sources[i], src))
|
||||||
+ fetchEventSource(sources[i], fetchID);
|
+ fetchEventSource(sources[i], fetchID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5205,4 +5221,307 @@
|
@@ -5205,4 +5221,309 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +269,8 @@
|
||||||
+
|
+
|
||||||
+ lazySegBind(segContainer, seg, bindSeg);
|
+ lazySegBind(segContainer, seg, bindSeg);
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
|
+ markFirstLast(getListContainer());
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ function bindSeg(event, eventElement, seg) {
|
+ function bindSeg(event, eventElement, seg) {
|
||||||
|
@ -364,7 +366,7 @@
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ function setHeight(height, dateChanged) {
|
+ function setHeight(height, dateChanged) {
|
||||||
+ body.css('height', height+'px').css('overflow', 'auto');
|
+ body.css('height', (height-1)+'px').css('overflow', 'auto');
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ function setWidth(width) {
|
+ function setWidth(width) {
|
||||||
|
|
|
@ -48,13 +48,15 @@ var defaults = {
|
||||||
month: 'MMMM yyyy',
|
month: 'MMMM yyyy',
|
||||||
week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}",
|
week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}",
|
||||||
day: 'dddd, MMM d, yyyy',
|
day: 'dddd, MMM d, yyyy',
|
||||||
list: 'MMM d, yyyy'
|
list: 'MMM d, yyyy',
|
||||||
|
table: 'MMM d, yyyy'
|
||||||
},
|
},
|
||||||
columnFormat: {
|
columnFormat: {
|
||||||
month: 'ddd',
|
month: 'ddd',
|
||||||
week: 'ddd M/d',
|
week: 'ddd M/d',
|
||||||
day: 'dddd M/d',
|
day: 'dddd M/d',
|
||||||
list: 'dddd, yyyy'
|
list: 'dddd, MMM d, yyyy',
|
||||||
|
table: 'dddd, MMM d, yyyy'
|
||||||
},
|
},
|
||||||
timeFormat: { // for event elements
|
timeFormat: { // for event elements
|
||||||
'': 'h(:mm)t' // default
|
'': 'h(:mm)t' // default
|
||||||
|
@ -76,7 +78,8 @@ var defaults = {
|
||||||
month: 'month',
|
month: 'month',
|
||||||
week: 'week',
|
week: 'week',
|
||||||
day: 'day',
|
day: 'day',
|
||||||
list: 'list'
|
list: 'list',
|
||||||
|
table: 'table'
|
||||||
},
|
},
|
||||||
listTexts: {
|
listTexts: {
|
||||||
from: 'from',
|
from: 'from',
|
||||||
|
@ -91,6 +94,9 @@ var defaults = {
|
||||||
future: 'Future events'
|
future: 'Future events'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// list options
|
||||||
|
smartSections: false,
|
||||||
|
|
||||||
// jquery-ui theming
|
// jquery-ui theming
|
||||||
theme: false,
|
theme: false,
|
||||||
buttonIcons: {
|
buttonIcons: {
|
||||||
|
@ -5230,8 +5236,11 @@ function ListEventRenderer() {
|
||||||
|
|
||||||
// exports
|
// exports
|
||||||
t.renderEvents = renderEvents;
|
t.renderEvents = renderEvents;
|
||||||
|
t.renderEventTime = renderEventTime;
|
||||||
t.compileDaySegs = compileSegs; // for DayEventRenderer
|
t.compileDaySegs = compileSegs; // for DayEventRenderer
|
||||||
t.clearEvents = clearEvents;
|
t.clearEvents = clearEvents;
|
||||||
|
t.lazySegBind = lazySegBind;
|
||||||
|
t.sortCmp = sortCmp;
|
||||||
|
|
||||||
// imports
|
// imports
|
||||||
DayEventRenderer.call(t);
|
DayEventRenderer.call(t);
|
||||||
|
@ -5265,9 +5274,12 @@ function ListEventRenderer() {
|
||||||
|
|
||||||
function compileSegs(events) {
|
function compileSegs(events) {
|
||||||
var segs = [];
|
var segs = [];
|
||||||
var colFormat = opt('columnFormat', 'day');
|
var colFormat = opt('titleFormat', 'day');
|
||||||
var event, i, dd, md, seg, segHash, curSegHash, segDate, curSeg = -1;
|
var firstDay = opt('firstDay');
|
||||||
|
var smartSegs = opt('smartSections');
|
||||||
|
var event, i, dd, wd, md, seg, segHash, curSegHash, segDate, curSeg = -1;
|
||||||
var today = clearTime(new Date());
|
var today = clearTime(new Date());
|
||||||
|
var weekstart = addDays(cloneDate(today), -((today.getDay() - firstDay + 7) % 7));
|
||||||
|
|
||||||
for (i=0; i < events.length; i++) {
|
for (i=0; i < events.length; i++) {
|
||||||
event = events[i];
|
event = events[i];
|
||||||
|
@ -5280,40 +5292,33 @@ function ListEventRenderer() {
|
||||||
// create smart sections such as today, tomorrow, this week, next week, next month, ect.
|
// create smart sections such as today, tomorrow, this week, next week, next month, ect.
|
||||||
segDate = cloneDate(event.start < t.start && event.end > t.start ? t.start : event.start, true);
|
segDate = cloneDate(event.start < t.start && event.end > t.start ? t.start : event.start, true);
|
||||||
dd = dayDiff(segDate, today);
|
dd = dayDiff(segDate, today);
|
||||||
|
wd = Math.floor(dayDiff(segDate, weekstart) / 7);
|
||||||
md = segDate.getMonth() + ((segDate.getYear() - today.getYear()) * 12) - today.getMonth();
|
md = segDate.getMonth() + ((segDate.getYear() - today.getYear()) * 12) - today.getMonth();
|
||||||
|
|
||||||
// past events
|
// build section title
|
||||||
if (dd < 0) {
|
if (!smartSegs) {
|
||||||
|
segHash = formatDate(segDate, colFormat);
|
||||||
|
} else if (dd < 0) {
|
||||||
segHash = opt('listTexts', 'past');
|
segHash = opt('listTexts', 'past');
|
||||||
}
|
} else if (dd == 0) {
|
||||||
// today
|
|
||||||
else if (dd == 0) {
|
|
||||||
segHash = opt('listTexts', 'today');
|
segHash = opt('listTexts', 'today');
|
||||||
}
|
} else if (dd == 1) {
|
||||||
else if (dd == 1) {
|
|
||||||
segHash = opt('listTexts', 'tomorrow');
|
segHash = opt('listTexts', 'tomorrow');
|
||||||
}
|
} else if (wd == 0) {
|
||||||
// this week
|
|
||||||
else if (dd < 7) {
|
|
||||||
segHash = opt('listTexts', 'thisWeek');
|
segHash = opt('listTexts', 'thisWeek');
|
||||||
}
|
} else if (wd == 1) {
|
||||||
// next week
|
|
||||||
else if (dd >= 7 && dd < 14 && md == 0) {
|
|
||||||
segHash = opt('listTexts', 'nextWeek');
|
segHash = opt('listTexts', 'nextWeek');
|
||||||
}
|
} else if (md == 0) {
|
||||||
else if (md == 0) {
|
|
||||||
segHash = opt('listTexts', 'thisMonth');
|
segHash = opt('listTexts', 'thisMonth');
|
||||||
}
|
} else if (md == 1) {
|
||||||
else if (md == 1) {
|
|
||||||
segHash = opt('listTexts', 'nextMonth');
|
segHash = opt('listTexts', 'nextMonth');
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
segHash = formatDate(segDate, colFormat);
|
segHash = formatDate(segDate, colFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// start new segment
|
// start new segment
|
||||||
if (segHash != curSegHash) {
|
if (segHash != curSegHash) {
|
||||||
segs[++curSeg] = { events: [], start: segDate, title: segHash, daydiff: dd };
|
segs[++curSeg] = { events: [], start: segDate, title: segHash, daydiff: dd, weekdiff: wd, monthdiff: md };
|
||||||
curSegHash = segHash;
|
curSegHash = segHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5329,11 +5334,9 @@ function ListEventRenderer() {
|
||||||
|
|
||||||
function renderSegs(segs, modifiedEventId) {
|
function renderSegs(segs, modifiedEventId) {
|
||||||
var tm = opt('theme') ? 'ui' : 'fc';
|
var tm = opt('theme') ? 'ui' : 'fc';
|
||||||
var timeFormat = opt('timeFormat');
|
|
||||||
var dateFormat = opt('titleFormat');
|
|
||||||
var headerClass = tm + "-widget-header";
|
var headerClass = tm + "-widget-header";
|
||||||
var contentClass = tm + "-widget-content";
|
var contentClass = tm + "-widget-content";
|
||||||
var i, j, seg, event, duration, s, skinCss, skinCssAttr, classes, time, segHeader, segContainer, eventElements;
|
var i, j, seg, event, times, s, skinCss, skinCssAttr, classes, segHeader, segContainer, eventElements;
|
||||||
|
|
||||||
for (j=0; j < segs.length; j++) {
|
for (j=0; j < segs.length; j++) {
|
||||||
seg = segs[j];
|
seg = segs[j];
|
||||||
|
@ -5344,7 +5347,7 @@ function ListEventRenderer() {
|
||||||
|
|
||||||
for (i=0; i < seg.events.length; i++) {
|
for (i=0; i < seg.events.length; i++) {
|
||||||
event = seg.events[i];
|
event = seg.events[i];
|
||||||
|
times = renderEventTime(event, seg);
|
||||||
skinCss = getSkinCss(event, opt);
|
skinCss = getSkinCss(event, opt);
|
||||||
skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
|
skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
|
||||||
classes = ['fc-event', 'fc-event-skin', 'fc-event-vert', 'fc-corner-left', 'fc-corner-right', 'fc-corner-top', 'fc-corner-bottom'];
|
classes = ['fc-event', 'fc-event-skin', 'fc-event-vert', 'fc-corner-left', 'fc-corner-right', 'fc-corner-top', 'fc-corner-bottom'];
|
||||||
|
@ -5352,31 +5355,13 @@ function ListEventRenderer() {
|
||||||
classes = classes.concat(event.source.className);
|
classes = classes.concat(event.source.className);
|
||||||
}
|
}
|
||||||
|
|
||||||
// event time/date range to display
|
|
||||||
times = [];
|
|
||||||
duration = event.end.getTime() - event.start.getTime();
|
|
||||||
if (event.start < seg.start) {
|
|
||||||
times.push(opt('listTexts', 'until') + ' ' + formatDate(event.end, (event.allDay || event.end.getDate() != seg.start.getDate()) ? dateFormat : timeFormat));
|
|
||||||
} else if (duration > DAY_MS) {
|
|
||||||
times.push(formatDates(event.start, event.end, dateFormat + '[ - ' + dateFormat + ']'));
|
|
||||||
} else if (seg.daydiff > 1 && seg.daydiff < 7) {
|
|
||||||
times.push(formatDate(event.start, 'ddd'));
|
|
||||||
} else if (seg.daydiff > 1 || seg.daydiff < 0) {
|
|
||||||
times.push(formatDate(event.start, dateFormat));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!times.length && event.allDay) {
|
|
||||||
times.push(opt('allDayText'));
|
|
||||||
} else if (duration < DAY_MS && !event.allDay) {
|
|
||||||
times.push(formatDates(event.start, event.end, timeFormat))
|
|
||||||
}
|
|
||||||
|
|
||||||
s +=
|
s +=
|
||||||
"<div class='" + classes.join(' ') + "'" + skinCssAttr + ">" +
|
"<div class='" + classes.join(' ') + "'" + skinCssAttr + ">" +
|
||||||
"<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
|
"<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
|
||||||
"<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
|
"<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
|
||||||
"<div class='fc-event-time'>" +
|
"<div class='fc-event-time'>" +
|
||||||
htmlEscape(times.join(' ')) +
|
(times[0] ? '<span class="fc-col-date">' + times[0] + '</span> ' : '') +
|
||||||
|
(times[1] ? '<span class="fc-col-time">' + times[1] + '</span>' : '') +
|
||||||
"</div>" +
|
"</div>" +
|
||||||
"</div>" +
|
"</div>" +
|
||||||
"<div class='fc-event-content'>" +
|
"<div class='fc-event-content'>" +
|
||||||
|
@ -5405,7 +5390,7 @@ function ListEventRenderer() {
|
||||||
eventElement = $(triggerRes).appendTo(segContainer);
|
eventElement = $(triggerRes).appendTo(segContainer);
|
||||||
}
|
}
|
||||||
if (event._id === modifiedEventId) {
|
if (event._id === modifiedEventId) {
|
||||||
bindSeg(event, eventElement, seg);
|
eventElementHandlers(event, eventElement, seg);
|
||||||
} else {
|
} else {
|
||||||
eventElement[0]._fci = i; // for lazySegBind
|
eventElement[0]._fci = i; // for lazySegBind
|
||||||
}
|
}
|
||||||
|
@ -5413,14 +5398,42 @@ function ListEventRenderer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazySegBind(segContainer, seg, bindSeg);
|
lazySegBind(segContainer, seg, eventElementHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
markFirstLast(getListContainer());
|
markFirstLast(getListContainer());
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindSeg(event, eventElement, seg) {
|
// event time/date range to display
|
||||||
eventElementHandlers(event, eventElement);
|
function renderEventTime(event, seg) {
|
||||||
|
var timeFormat = opt('timeFormat');
|
||||||
|
var dateFormat = opt('columnFormat');
|
||||||
|
var duration = event.end.getTime() - event.start.getTime();
|
||||||
|
var datestr = '', timestr = '';
|
||||||
|
|
||||||
|
if (!opt('smartSections')) {
|
||||||
|
// no date display if grouped by day
|
||||||
|
} else if (event.start < seg.start) {
|
||||||
|
datestr = opt('listTexts', 'until') + ' ' + formatDate(event.end, (event.allDay || event.end.getDate() != seg.start.getDate()) ? dateFormat : timeFormat);
|
||||||
|
} else if (duration > DAY_MS) {
|
||||||
|
datestr = formatDates(event.start, event.end, dateFormat + '[ - ' + dateFormat + ']');
|
||||||
|
} else if (seg.daydiff == 0) {
|
||||||
|
datestr = opt('listTexts', 'today');
|
||||||
|
} else if (seg.daydiff == 1) {
|
||||||
|
datestr = opt('listTexts', 'tomorrow');
|
||||||
|
} else if (seg.weekdiff == 0 || seg.weekdiff == 1) {
|
||||||
|
datestr = formatDate(event.start, 'dddd');
|
||||||
|
} else if (seg.daydiff > 1 || seg.daydiff < 0) {
|
||||||
|
datestr = formatDate(event.start, dateFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!datestr && event.allDay) {
|
||||||
|
timestr = opt('allDayText');
|
||||||
|
} else if (duration < DAY_MS && !event.allDay) {
|
||||||
|
timestr = formatDates(event.start, event.end, timeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [datestr, timestr];
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazySegBind(container, seg, bindHandlers) {
|
function lazySegBind(container, seg, bindHandlers) {
|
||||||
|
@ -5526,4 +5539,226 @@ function ListView(element, calendar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Additional view: table (by bruederli@kolabsys.com)
|
||||||
|
---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function TableEventRenderer() {
|
||||||
|
var t = this;
|
||||||
|
|
||||||
|
// imports
|
||||||
|
ListEventRenderer.call(t);
|
||||||
|
var opt = t.opt;
|
||||||
|
var sortCmp = t.sortCmp;
|
||||||
|
var trigger = t.trigger;
|
||||||
|
var compileSegs = t.compileDaySegs;
|
||||||
|
var reportEvents = t.reportEvents;
|
||||||
|
var reportEventClear = t.reportEventClear;
|
||||||
|
var reportEventElement = t.reportEventElement;
|
||||||
|
var eventElementHandlers = t.eventElementHandlers;
|
||||||
|
var renderEventTime = t.renderEventTime;
|
||||||
|
var showEvents = t.showEvents;
|
||||||
|
var hideEvents = t.hideEvents;
|
||||||
|
var getListContainer = t.getDaySegmentContainer;
|
||||||
|
var lazySegBind = t.lazySegBind;
|
||||||
|
var calendar = t.calendar;
|
||||||
|
var formatDate = calendar.formatDate;
|
||||||
|
var formatDates = calendar.formatDates;
|
||||||
|
|
||||||
|
// exports
|
||||||
|
t.renderEvents = renderEvents;
|
||||||
|
t.clearEvents = clearEvents;
|
||||||
|
|
||||||
|
|
||||||
|
/* Rendering
|
||||||
|
--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function clearEvents() {
|
||||||
|
reportEventClear();
|
||||||
|
getListContainer().children('tbody').remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderEvents(events, modifiedEventId) {
|
||||||
|
events.sort(sortCmp);
|
||||||
|
reportEvents(events);
|
||||||
|
renderSegs(compileSegs(events), modifiedEventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSegs(segs, modifiedEventId) {
|
||||||
|
var tm = opt('theme') ? 'ui' : 'fc';
|
||||||
|
var table = getListContainer();
|
||||||
|
var headerClass = tm + "-widget-header";
|
||||||
|
var contentClass = tm + "-widget-content";
|
||||||
|
var i, j, seg, event, times, s, skinCss, skinCssAttr, skinClasses, rowClasses, segHeader, segContainer, eventElements;
|
||||||
|
|
||||||
|
for (j=0; j < segs.length; j++) {
|
||||||
|
seg = segs[j];
|
||||||
|
|
||||||
|
segHeader = $('<tbody class="fc-list-header"><tr><td class="fc-list-header ' + headerClass + '" colspan="5">' + htmlEscape(seg.title) + '</td></tr></tbody>').appendTo(table);
|
||||||
|
segContainer = $('<tbody>').addClass('fc-list-section ' + contentClass).appendTo(table);
|
||||||
|
s = '';
|
||||||
|
|
||||||
|
for (i=0; i < seg.events.length; i++) {
|
||||||
|
event = seg.events[i];
|
||||||
|
times = renderEventTime(event, seg);
|
||||||
|
skinCss = getSkinCss(event, opt);
|
||||||
|
skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
|
||||||
|
skinClasses = ['fc-event-skin', 'fc-corner-left', 'fc-corner-right', 'fc-corner-top', 'fc-corner-bottom'];
|
||||||
|
if (event.source && event.source.className) {
|
||||||
|
skinClasses = skinClasses.concat(event.source.className);
|
||||||
|
}
|
||||||
|
rowClasses = ['fc-event', 'fc-event-row', 'fc-'+dayIDs[event.start.getDay()]];
|
||||||
|
if (seg.daydiff == 0) {
|
||||||
|
rowClasses.push('fc-today');
|
||||||
|
}
|
||||||
|
|
||||||
|
s +=
|
||||||
|
"<tr class='" + rowClasses.join(' ') + "'>" +
|
||||||
|
"<td class='fc-event-handle'>" +
|
||||||
|
"<div class='" + skinClasses.join(' ') + "'" + skinCssAttr + ">" +
|
||||||
|
"<span class='fc-event-inner'></span>" +
|
||||||
|
"</div></td>" +
|
||||||
|
"<td class='fc-event-date'>" +
|
||||||
|
htmlEscape(times[0]) +
|
||||||
|
"</td>" +
|
||||||
|
"<td class='fc-event-time'>" +
|
||||||
|
htmlEscape(times[1]) +
|
||||||
|
"</td>" +
|
||||||
|
"<td class='fc-event-title'>" +
|
||||||
|
htmlEscape(event.title) +
|
||||||
|
"</td>" +
|
||||||
|
"<td class='fc-event-location'>" +
|
||||||
|
htmlEscape(event.location) +
|
||||||
|
"</td>" +
|
||||||
|
"</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
segContainer[0].innerHTML = s;
|
||||||
|
eventElements = segContainer.children();
|
||||||
|
|
||||||
|
// retrieve elements, run through eventRender callback, bind event handlers
|
||||||
|
for (i=0; i < seg.events.length; i++) {
|
||||||
|
event = seg.events[i];
|
||||||
|
eventElement = $(eventElements[i]); // faster than eq()
|
||||||
|
triggerRes = trigger('eventRender', event, event, eventElement);
|
||||||
|
if (triggerRes === false) {
|
||||||
|
eventElement.remove();
|
||||||
|
} else {
|
||||||
|
if (triggerRes && triggerRes !== true) {
|
||||||
|
eventElement.remove();
|
||||||
|
eventElement = $(triggerRes).appendTo(segContainer);
|
||||||
|
}
|
||||||
|
if (event._id === modifiedEventId) {
|
||||||
|
eventElementHandlers(event, eventElement, seg);
|
||||||
|
} else {
|
||||||
|
eventElement[0]._fci = i; // for lazySegBind
|
||||||
|
}
|
||||||
|
reportEventElement(event, eventElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazySegBind(segContainer, seg, eventElementHandlers);
|
||||||
|
markFirstLast(segContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//markFirstLast(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fcViews.table = TableView;
|
||||||
|
|
||||||
|
|
||||||
|
function TableView(element, calendar) {
|
||||||
|
var t = this;
|
||||||
|
|
||||||
|
// exports
|
||||||
|
t.render = render;
|
||||||
|
t.select = dummy;
|
||||||
|
t.unselect = dummy;
|
||||||
|
t.getDaySegmentContainer = function(){ return table; };
|
||||||
|
|
||||||
|
// imports
|
||||||
|
View.call(t, element, calendar, 'table');
|
||||||
|
TableEventRenderer.call(t);
|
||||||
|
var opt = t.opt;
|
||||||
|
var trigger = t.trigger;
|
||||||
|
var clearEvents = t.clearEvents;
|
||||||
|
var reportEventClear = t.reportEventClear;
|
||||||
|
var formatDates = calendar.formatDates;
|
||||||
|
var formatDate = calendar.formatDate;
|
||||||
|
|
||||||
|
// overrides
|
||||||
|
t.setWidth = setWidth;
|
||||||
|
t.setHeight = setHeight;
|
||||||
|
|
||||||
|
// locals
|
||||||
|
var div;
|
||||||
|
var table;
|
||||||
|
var firstDay;
|
||||||
|
var nwe;
|
||||||
|
var tm;
|
||||||
|
var colFormat;
|
||||||
|
|
||||||
|
|
||||||
|
function render(date, delta) {
|
||||||
|
if (delta) {
|
||||||
|
addDays(date, delta);
|
||||||
|
if (!opt('weekends')) {
|
||||||
|
skipWeekend(date, delta < 0 ? -1 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.title = opt('listTexts', 'from') + ' ' + formatDate(date, opt('titleFormat'));
|
||||||
|
t.start = t.visStart = cloneDate(date, true);
|
||||||
|
t.end = addDays(cloneDate(t.start), 1);
|
||||||
|
t.visEnd = addMonths(cloneDate(t.start), 1); // show events one month ahead. Enough?
|
||||||
|
|
||||||
|
updateOptions();
|
||||||
|
|
||||||
|
if (!table) {
|
||||||
|
buildSkeleton();
|
||||||
|
} else {
|
||||||
|
clearEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateOptions() {
|
||||||
|
firstDay = opt('firstDay');
|
||||||
|
nwe = opt('weekends') ? 0 : 1;
|
||||||
|
tm = opt('theme') ? 'ui' : 'fc';
|
||||||
|
colFormat = opt('columnFormat');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildSkeleton() {
|
||||||
|
var s =
|
||||||
|
"<table class='fc-border-separate' style='width:100%' cellspacing='0'>" +
|
||||||
|
"<colgroup>" +
|
||||||
|
"<col class='fc-event-handle' />" +
|
||||||
|
"<col class='fc-event-date' />" +
|
||||||
|
"<col class='fc-event-time' />" +
|
||||||
|
"<col class='fc-event-title' />" +
|
||||||
|
"<col class='fc-event-location' />" +
|
||||||
|
"</colgroup>" +
|
||||||
|
"</table>";
|
||||||
|
div = $('<div>').addClass('fc-list-content').appendTo(element);
|
||||||
|
table = $(s).appendTo(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHeight(height, dateChanged) {
|
||||||
|
div.css('height', (height-1)+'px').css('overflow', 'auto');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setWidth(width) {
|
||||||
|
// nothing to be done here
|
||||||
|
}
|
||||||
|
|
||||||
|
function dummy() {
|
||||||
|
// Stub.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
|
@ -461,16 +461,21 @@ a.alarm-action-snooze:after {
|
||||||
|
|
||||||
.fc-event-hori .fc-event-time {
|
.fc-event-hori .fc-event-time {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-weight: normal;
|
font-weight: normal !important;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
padding-right: 0.6em;
|
padding-right: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-grid .fc-event-time {
|
||||||
|
font-weight: normal !important;
|
||||||
|
padding-right: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
.fc-event-cateories {
|
.fc-event-cateories {
|
||||||
font-style:italic;
|
font-style:italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-event-location {
|
div.fc-event-location {
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,6 +509,27 @@ a.alarm-action-snooze:after {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-view-list div.fc-list-header,
|
||||||
|
.fc-view-table td.fc-list-header {
|
||||||
|
padding: 3px;
|
||||||
|
background: #dddddd;
|
||||||
|
background-image: -moz-linear-gradient(center top, #f4f4f4, #d2d2d2);
|
||||||
|
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0.00, #f4f4f4), color-stop(1.00, #d2d2d2));
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(enabled='true', startColorstr=#f4f4f4, endColorstr=#d2d2d2, GradientType=1);
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-list .fc-event-skin .fc-event-content {
|
||||||
|
background: #F6F6F6;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-list .fc-event-skin .fc-event-title,
|
||||||
|
.fc-view-list .fc-event-skin .fc-event-location {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
/* Settings section */
|
/* Settings section */
|
||||||
|
|
||||||
fieldset #calendarcategories div {
|
fieldset #calendarcategories div {
|
||||||
|
|
|
@ -619,18 +619,28 @@ table.fc-border-separate {
|
||||||
/* List view (by bruederli@kolabsys.com)
|
/* List view (by bruederli@kolabsys.com)
|
||||||
------------------------------------------------------------------------*/
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
.fc-view-list {
|
.fc-view-list,
|
||||||
|
.fc-view-table {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
width: 99%;
|
width: 99%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-view-list .fc-list-header {
|
.fc-view-list .fc-list-header,
|
||||||
|
.fc-view-table td.fc-list-header {
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
border-bottom-width: 1px;
|
border-bottom-width: 1px;
|
||||||
padding: 2px;
|
padding: 3px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-view-table td.fc-list-header {
|
||||||
|
_border-top-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table .fc-first td.fc-list-header {
|
||||||
|
border-top-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.fc-list-section {
|
.fc-list-section {
|
||||||
padding: 4px 2px;
|
padding: 4px 2px;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
@ -645,3 +655,53 @@ table.fc-border-separate {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 1px 2px 3px 2px;
|
margin: 1px 2px 3px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-view-table tr.fc-event td {
|
||||||
|
padding: 2px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table tr.fc-event td.fc-event-handle {
|
||||||
|
padding: 3px 8px 3px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table .fc-event-handle .fc-event-skin {
|
||||||
|
border-radius: 2px;
|
||||||
|
-moz-border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table .fc-event-handle .fc-event-inner {
|
||||||
|
display: block;
|
||||||
|
width: 8px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
-moz-border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table table {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table col.fc-event-handle {
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table col.fc-event-date {
|
||||||
|
width: 7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table col.fc-event-time {
|
||||||
|
width: 8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table col.fc-event-location {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view-table td.fc-event-date,
|
||||||
|
.fc-view-table td.fc-event-time {
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue