diff --git a/plugins/calendar/lib/fullcalendar-rc.patch b/plugins/calendar/lib/fullcalendar-rc.patch index a886f25d..cf96bdc7 100644 --- a/plugins/calendar/lib/fullcalendar-rc.patch +++ b/plugins/calendar/lib/fullcalendar-rc.patch @@ -1,32 +1,34 @@ ---- js/fullcalendar.js.orig 2011-06-04 13:45:44.000000000 -0600 -+++ js/fullcalendar.js 2011-06-10 09:27:50.000000000 -0600 -@@ -47,12 +47,14 @@ +--- js/fullcalendar.js.orig 2011-04-09 14:13:16.000000000 +0200 ++++ js/fullcalendar.js 2011-07-30 15:25:57.000000000 +0200 +@@ -47,12 +47,16 @@ titleFormat: { month: 'MMMM 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: { month: 'ddd', 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 '': 'h(:mm)t' // default -@@ -73,7 +75,20 @@ +@@ -73,8 +77,28 @@ today: 'today', month: 'month', week: 'week', - day: 'day' + day: 'day', -+ list: 'list' -+ }, ++ list: 'list', ++ table: 'table' + }, + listTexts: { -+ from: 'from', + until: 'until', + past: 'Past events', + today: 'Today', @@ -35,11 +37,19 @@ + nextWeek: 'Next week', + thisMonth: 'This month', + nextMonth: 'Next month', -+ future: 'Future events' - }, ++ future: 'Future events', ++ week: 'W' ++ }, ++ ++ // list/table options ++ listSections: 'month', // false|'day'|'week'|'month'|'smart' ++ listRange: 30, // number of days to be displayed ++ listPage: 7, // number of days to jump when paging ++ tableCols: ['handle', 'date', 'time', 'title'], // jquery-ui theming -@@ -500,8 +515,8 @@ + theme: false, +@@ -500,8 +524,8 @@ } @@ -50,7 +60,16 @@ } -@@ -897,15 +912,16 @@ +@@ -632,6 +656,8 @@ + if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') { + options[name] = value; + updateSize(); ++ } else if (name.indexOf('list') == 0 || name == 'tableCols') { ++ options[name] = value; + } + } + +@@ -897,15 +923,16 @@ } @@ -71,10 +90,79 @@ } } -@@ -5205,4 +5221,309 @@ +@@ -1579,10 +1606,23 @@ + return 'th'; + } + return ['st', 'nd', 'rd'][date%10-1] || 'th'; +- } ++ }, ++ W : function(d) { return iso8601Week(d); } + }; + + ++// Determine the week of the year based on the ISO 8601 definition. ++// copied from jquery UI Datepicker ++var iso8601Week = function(date) { ++ var checkDate = cloneDate(date); ++ // Find Thursday of this week starting on Monday ++ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); ++ var time = checkDate.getTime(); ++ checkDate.setMonth(0); // Compare with Jan 1 ++ checkDate.setDate(1); ++ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; ++}; ++ + + fc.applyAll = applyAll; + +@@ -3762,7 +3802,8 @@ + height, + slotSegmentContainer = getSlotSegmentContainer(), + rtl, dis, dit, +- colCnt = getColCnt(); ++ colCnt = getColCnt(), ++ overlapping = colCnt > 1; + + if (rtl = opt('isRTL')) { + dis = -1; +@@ -3789,8 +3830,11 @@ + outerWidth = availWidth / (levelI + forward + 1); + }else{ + if (forward) { +- // moderately wide, aligned left still +- outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer = ++ if (overlapping) { // moderately wide, aligned left still ++ outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer = ++ }else{ ++ outerWidth = outerWidth = availWidth / (forward + 1); ++ } + }else{ + // can be entire width, aligned left + outerWidth = availWidth; +@@ -3801,7 +3845,7 @@ + * dis + (rtl ? availWidth - outerWidth : 0); // rtl + seg.top = top; + seg.left = left; +- seg.outerWidth = outerWidth; ++ seg.outerWidth = outerWidth - (overlapping ? 0 : 1); + seg.outerHeight = bottom - top; + html += slotSegHtml(event, seg); + } +@@ -4260,7 +4304,7 @@ + + function opt(name, viewNameOverride) { + var v = options[name]; +- if (typeof v == 'object') { ++ if (typeof v == 'object' && !v.length) { + return smartProperty(v, viewNameOverride || viewName); + } + return v; +@@ -5204,5 +5248,558 @@ + }; } - +- ++ + +/* Additional view: list (by bruederli@kolabsys.com) +---------------------------------------------------------------------------------*/ @@ -84,8 +172,11 @@ + + // exports + t.renderEvents = renderEvents; ++ t.renderEventTime = renderEventTime; + t.compileDaySegs = compileSegs; // for DayEventRenderer + t.clearEvents = clearEvents; ++ t.lazySegBind = lazySegBind; ++ t.sortCmp = sortCmp; + + // imports + DayEventRenderer.call(t); @@ -119,9 +210,12 @@ + + function compileSegs(events) { + var segs = []; -+ var colFormat = opt('columnFormat', 'day'); -+ var event, i, dd, md, seg, segHash, curSegHash, segDate, curSeg = -1; ++ var colFormat = opt('titleFormat', 'day'); ++ var firstDay = opt('firstDay'); ++ var segmode = opt('listSections'); ++ var event, i, dd, wd, md, seg, segHash, curSegHash, segDate, curSeg = -1; + var today = clearTime(new Date()); ++ var weekstart = addDays(cloneDate(today), -((today.getDay() - firstDay + 7) % 7)); + + for (i=0; i < events.length; i++) { + event = events[i]; @@ -134,40 +228,41 @@ + // 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); + dd = dayDiff(segDate, today); ++ wd = Math.floor(dayDiff(segDate, weekstart) / 7); + md = segDate.getMonth() + ((segDate.getYear() - today.getYear()) * 12) - today.getMonth(); + -+ // past events -+ if (dd < 0) { -+ segHash = opt('listTexts', 'past'); -+ } -+ // today -+ else if (dd == 0) { -+ segHash = opt('listTexts', 'today'); -+ } -+ else if (dd == 1) { -+ segHash = opt('listTexts', 'tomorrow'); -+ } -+ // this week -+ else if (dd < 7) { -+ segHash = opt('listTexts', 'thisWeek'); -+ } -+ // next week -+ else if (dd >= 7 && dd < 14 && md == 0) { -+ segHash = opt('listTexts', 'nextWeek'); -+ } -+ else if (md == 0) { -+ segHash = opt('listTexts', 'thisMonth'); -+ } -+ else if (md == 1) { -+ segHash = opt('listTexts', 'nextMonth'); -+ } -+ else { ++ // build section title ++ if (segmode == 'smart') { ++ if (dd < 0) { ++ segHash = opt('listTexts', 'past'); ++ } else if (dd == 0) { ++ segHash = opt('listTexts', 'today'); ++ } else if (dd == 1) { ++ segHash = opt('listTexts', 'tomorrow'); ++ } else if (wd == 0) { ++ segHash = opt('listTexts', 'thisWeek'); ++ } else if (wd == 1) { ++ segHash = opt('listTexts', 'nextWeek'); ++ } else if (md == 0) { ++ segHash = opt('listTexts', 'thisMonth'); ++ } else if (md == 1) { ++ segHash = opt('listTexts', 'nextMonth'); ++ } else if (md > 1) { ++ segHash = opt('listTexts', 'future'); ++ } ++ } else if (segmode == 'month') { ++ segHash = formatDate(segDate, 'MMMM yyyy'); ++ } else if (segmode == 'week') { ++ segHash = opt('listTexts', 'week') + formatDate(segDate, ' W'); ++ } else if (segmode == 'day') { + segHash = formatDate(segDate, colFormat); ++ } else { ++ segHash = ''; + } + + // start new segment + 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; + } + @@ -183,54 +278,36 @@ + + function renderSegs(segs, modifiedEventId) { + var tm = opt('theme') ? 'ui' : 'fc'; -+ var timeFormat = opt('timeFormat'); -+ var dateFormat = opt('titleFormat'); + var headerClass = tm + "-widget-header"; + 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, segContainer, eventElements; + + for (j=0; j < segs.length; j++) { + seg = segs[j]; + -+ segHeader = $('
' + htmlEscape(seg.title) + '
').appendTo(getListContainer()); ++ if (seg.title) { ++ $('
' + htmlEscape(seg.title) + '
').appendTo(getListContainer()); ++ } + segContainer = $('
').addClass('fc-list-section ' + contentClass).appendTo(getListContainer()); + 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 + "'" : ''); -+ 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-top', 'fc-corner-bottom'].concat(event.className); + if (event.source && 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 += + "
" + + "
" + + "
" + + "
" + -+ htmlEscape(times.join(' ')) + ++ (times[0] ? '' + times[0] + ' ' : '') + ++ (times[1] ? '' + times[1] + '' : '') + + "
" + + "
" + + "
" + @@ -259,7 +336,7 @@ + eventElement = $(triggerRes).appendTo(segContainer); + } + if (event._id === modifiedEventId) { -+ bindSeg(event, eventElement, seg); ++ eventElementHandlers(event, eventElement, seg); + } else { + eventElement[0]._fci = i; // for lazySegBind + } @@ -267,16 +344,47 @@ + } + } + -+ lazySegBind(segContainer, seg, bindSeg); ++ lazySegBind(segContainer, seg, eventElementHandlers); + } + + markFirstLast(getListContainer()); + } + -+ function bindSeg(event, eventElement, seg) { -+ eventElementHandlers(event, eventElement); ++ // event time/date range to display ++ function renderEventTime(event, seg) { ++ var timeFormat = opt('timeFormat'); ++ var dateFormat = opt('columnFormat'); ++ var segmode = opt('listSections'); ++ var duration = event.end.getTime() - event.start.getTime(); ++ var datestr = '', timestr = ''; ++ ++ if (segmode == 'smart') { ++ 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); ++ } ++ } else if (segmode != 'day') { ++ datestr = formatDates(event.start, event.end, dateFormat + (duration > DAY_MS ? '{ - ' + dateFormat + '}' : '')); ++ } ++ ++ if (!datestr && event.allDay) { ++ timestr = opt('allDayText'); ++ } else if ((duration < DAY_MS || !datestr) && !event.allDay) { ++ timestr = formatDates(event.start, event.end, timeFormat); ++ } ++ ++ return [datestr, timestr]; + } -+ ++ + function lazySegBind(container, seg, bindHandlers) { + container.unbind('mouseover').mouseover(function(ev) { + var parent = ev.target, e = parent, i, event; @@ -333,15 +441,12 @@ + + function render(date, delta) { + if (delta) { -+ addDays(date, delta); -+ if (!opt('weekends')) { -+ skipWeekend(date, delta < 0 ? -1 : 1); -+ } ++ addDays(date, opt('listPage') * delta); + } -+ 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? ++ t.end = addDays(cloneDate(t.start), opt('listPage')); ++ t.visEnd = addDays(cloneDate(t.start), opt('listRange')); ++ t.title = formatDates(date, t.visEnd, opt('titleFormat')); + + updateOptions(); + @@ -379,6 +484,237 @@ + +} + ++ ++/* 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); ++ getListContainer().removeClass('fc-list-smart fc-list-day fc-list-month fc-list-week').addClass('fc-list-' + opt('listSections')); ++ } ++ ++ function renderSegs(segs, modifiedEventId) { ++ var tm = opt('theme') ? 'ui' : 'fc'; ++ var table = getListContainer(); ++ var headerClass = tm + "-widget-header"; ++ var contentClass = tm + "-widget-content"; ++ var tableCols = opt('tableCols'); ++ var timecol = $.inArray('time', tableCols) >= 0; ++ var i, j, seg, event, times, s, skinCss, skinCssAttr, skinClasses, rowClasses, segContainer, eventElements; ++ ++ for (j=0; j < segs.length; j++) { ++ seg = segs[j]; ++ ++ if (seg.title) { ++ $('' + htmlEscape(seg.title) + '').appendTo(table); ++ } ++ segContainer = $('').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'].concat(event.className); ++ 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 += ""; ++ for (var col, c=0; c < tableCols.length; c++) { ++ col = tableCols[c]; ++ if (col == 'handle') { ++ s += "" + ++ "
" + ++ "" + ++ "
"; ++ } else if (col == 'date') { ++ s += "" + htmlEscape(times[0]) + ""; ++ } else if (col == 'time') { ++ if (times[1]) { ++ s += "" + htmlEscape(times[1]) + ""; ++ } ++ } else { ++ s += "" + (htmlEscape(event[col]) || ' ') + ""; ++ } ++ } ++ s += ""; ++ ++ // IE doesn't like innerHTML on tbody elements so we insert every row individually ++ if (document.all) { ++ $(s).appendTo(segContainer); ++ s = ''; ++ } ++ } ++ ++ if (!document.all) ++ 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, opt('listPage') * delta); ++ } ++ t.start = t.visStart = cloneDate(date, true); ++ t.end = addDays(cloneDate(t.start), opt('listPage')); ++ t.visEnd = addDays(cloneDate(t.start), opt('listRange')); ++ t.title = formatDates(date, t.visEnd, opt('titleFormat')); ++ ++ 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 tableCols = opt('tableCols'); ++ var s = ++ "" + ++ ""; ++ for (var c=0; c < tableCols.length; c++) { ++ s += ""; ++ } ++ s += "" + ++ "
"; ++ 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); \ No newline at end of file