|
|
@@ -11,6 +11,7 @@ function DayEventRenderer() {
|
|
|
// imports
|
|
|
var opt = t.opt;
|
|
|
var trigger = t.trigger;
|
|
|
+ var eventEnd = t.eventEnd;
|
|
|
var reportEventElement = t.reportEventElement;
|
|
|
var showEvents = t.showEvents;
|
|
|
var hideEvents = t.hideEvents;
|
|
|
@@ -23,40 +24,102 @@ function DayEventRenderer() {
|
|
|
var colContentLeft = t.colContentLeft;
|
|
|
var colContentRight = t.colContentRight;
|
|
|
var dayOfWeekCol = t.dayOfWeekCol;
|
|
|
+ var dateCell = t.dateCell;
|
|
|
+ var compileDaySegs = t.compileDaySegs;
|
|
|
var getDaySegmentContainer = t.getDaySegmentContainer;
|
|
|
var bindDaySeg = t.bindDaySeg; //TODO: streamline this
|
|
|
var formatDates = t.calendar.formatDates;
|
|
|
+ var renderDayOverlay = t.renderDayOverlay;
|
|
|
+ var clearOverlays = t.clearOverlays;
|
|
|
+ var clearSelection = t.clearSelection;
|
|
|
|
|
|
|
|
|
|
|
|
/* Rendering
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
function renderDaySegs(segs, modifiedEventId) {
|
|
|
-
|
|
|
- var rtl=opt('isRTL'),
|
|
|
- i, segCnt=segs.length, seg,
|
|
|
- event,
|
|
|
- className,
|
|
|
- left, right,
|
|
|
- html='',
|
|
|
- eventElements,
|
|
|
- eventElement,
|
|
|
- triggerRes,
|
|
|
- hsideCache={},
|
|
|
- vmarginCache={},
|
|
|
- key, val,
|
|
|
- rowI, top, levelI, levelHeight,
|
|
|
- rowDivs=[],
|
|
|
- rowDivTops=[],
|
|
|
- bounds = allDayBounds(),
|
|
|
- minLeft = bounds.left,
|
|
|
- maxLeft = bounds.right,
|
|
|
- rowCnt = getRowCnt(),
|
|
|
- colCnt = getColCnt(),
|
|
|
- segmentContainer = getDaySegmentContainer();
|
|
|
-
|
|
|
+ var segmentContainer = getDaySegmentContainer();
|
|
|
+ var rowDivs;
|
|
|
+ var rowCnt;
|
|
|
+ var i;
|
|
|
+ var rowI;
|
|
|
+ var top;
|
|
|
+ var levelI;
|
|
|
+ var levelHeight;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ segmentContainer[0].innerHTML = daySegHTML(segs); // faster than .html()
|
|
|
+ daySegElementResolve(segs, segmentContainer.children());
|
|
|
+ daySegElementReport(segs);
|
|
|
+ daySegHandlers(segs, segmentContainer, modifiedEventId);
|
|
|
+ daySegCalcHSides(segs);
|
|
|
+ daySegSetWidths(segs);
|
|
|
+ daySegCalcHeights(segs);
|
|
|
+ rowDivs = getRowDivs();
|
|
|
+ rowCnt = rowDivs.length;
|
|
|
+ // set row heights, calculate event tops (in relation to row top)
|
|
|
+ for (i=0, rowI=0; rowI<rowCnt; rowI++) {
|
|
|
+ top = levelI = levelHeight = 0;
|
|
|
+ while (i<segCnt && (seg = segs[i]).row == rowI) {
|
|
|
+ if (seg.level != levelI) {
|
|
|
+ top += levelHeight;
|
|
|
+ levelHeight = 0;
|
|
|
+ levelI++;
|
|
|
+ }
|
|
|
+ levelHeight = Math.max(levelHeight, seg.outerHeight||0);
|
|
|
+ seg.top = top;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ rowDivs[rowI].height(top + levelHeight);
|
|
|
+ }
|
|
|
+ daySegSetTops(segs, getRowTops(rowDivs));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function renderTempDaySegs(segs, adjustRow, adjustTop) {
|
|
|
+ var tempContainer = $("<div/>");
|
|
|
+ var elements;
|
|
|
+ var segmentContainer = getDaySegmentContainer();
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var element;
|
|
|
+ tempContainer[0].innerHTML = daySegHTML(segs); // faster than .html()
|
|
|
+ elements = tempContainer.children();
|
|
|
+ segmentContainer.append(elements);
|
|
|
+ daySegElementResolve(segs, elements);
|
|
|
+ daySegCalcHSides(segs);
|
|
|
+ daySegSetWidths(segs);
|
|
|
+ daySegCalcHeights(segs);
|
|
|
+ daySegSetTops(segs, getRowTops(getRowDivs()));
|
|
|
+ elements = [];
|
|
|
+ for (i=0; i<segCnt; i++) {
|
|
|
+ element = segs[i].element;
|
|
|
+ if (element) {
|
|
|
+ if (segs[i].row === adjustRow) {
|
|
|
+ element.css('top', adjustTop);
|
|
|
+ }
|
|
|
+ elements.push(element[0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $(elements);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function daySegHTML(segs) { // also sets seg.left and seg.outerWidth
|
|
|
+ var rtl = opt('isRTL');
|
|
|
+ var i;
|
|
|
+ var segCnt=segs.length;
|
|
|
+ var seg;
|
|
|
+ var event;
|
|
|
+ var className;
|
|
|
+ var bounds = allDayBounds();
|
|
|
+ var minLeft = bounds.left;
|
|
|
+ var maxLeft = bounds.right;
|
|
|
+ var left;
|
|
|
+ var right;
|
|
|
+ var html = '';
|
|
|
// calculate desired position/dimensions, create html
|
|
|
for (i=0; i<segCnt; i++) {
|
|
|
seg = segs[i];
|
|
|
@@ -91,106 +154,184 @@ function DayEventRenderer() {
|
|
|
:'') +
|
|
|
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
|
|
|
"</a>" +
|
|
|
- ((event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
|
|
|
+ (seg.isEnd && (event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
|
|
|
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
|
|
|
: '') +
|
|
|
"</div>";
|
|
|
seg.left = left;
|
|
|
seg.outerWidth = right - left;
|
|
|
}
|
|
|
- segmentContainer[0].innerHTML = html; // faster than html()
|
|
|
- eventElements = segmentContainer.children();
|
|
|
+ return html;
|
|
|
+ }
|
|
|
|
|
|
- // retrieve elements, run through eventRender callback, bind handlers
|
|
|
+
|
|
|
+ function daySegElementResolve(segs, elements) { // sets seg.element
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var event;
|
|
|
+ var element;
|
|
|
+ var triggerRes;
|
|
|
for (i=0; i<segCnt; i++) {
|
|
|
seg = segs[i];
|
|
|
- eventElement = $(eventElements[i]); // faster than eq()
|
|
|
event = seg.event;
|
|
|
- triggerRes = trigger('eventRender', event, event, eventElement);
|
|
|
+ element = $(elements[i]); // faster than .eq()
|
|
|
+ triggerRes = trigger('eventRender', event, event, element);
|
|
|
if (triggerRes === false) {
|
|
|
- eventElement.remove();
|
|
|
+ element.remove();
|
|
|
}else{
|
|
|
if (triggerRes && triggerRes !== true) {
|
|
|
- eventElement.remove();
|
|
|
- eventElement = $(triggerRes)
|
|
|
+ triggerRes = $(triggerRes)
|
|
|
.css({
|
|
|
position: 'absolute',
|
|
|
left: seg.left
|
|
|
- })
|
|
|
- .appendTo(segmentContainer);
|
|
|
+ });
|
|
|
+ element.replaceWith(triggerRes);
|
|
|
+ element = triggerRes;
|
|
|
}
|
|
|
- seg.element = eventElement;
|
|
|
+ seg.element = element;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function daySegElementReport(segs) {
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var element;
|
|
|
+ for (i=0; i<segCnt; i++) {
|
|
|
+ seg = segs[i];
|
|
|
+ element = seg.element;
|
|
|
+ if (element) {
|
|
|
+ reportEventElement(seg.event, element);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function daySegHandlers(segs, segmentContainer, modifiedEventId) {
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var element;
|
|
|
+ var event;
|
|
|
+ // retrieve elements, run through eventRender callback, bind handlers
|
|
|
+ for (i=0; i<segCnt; i++) {
|
|
|
+ seg = segs[i];
|
|
|
+ element = seg.element;
|
|
|
+ if (element) {
|
|
|
+ event = seg.event;
|
|
|
if (event._id === modifiedEventId) {
|
|
|
- bindDaySeg(event, eventElement, seg);
|
|
|
+ bindDaySeg(event, element, seg);
|
|
|
}else{
|
|
|
- eventElement[0]._fci = i; // for lazySegBind
|
|
|
+ element[0]._fci = i; // for lazySegBind
|
|
|
}
|
|
|
- reportEventElement(event, eventElement);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
lazySegBind(segmentContainer, segs, bindDaySeg);
|
|
|
+ }
|
|
|
|
|
|
+
|
|
|
+ function daySegCalcHSides(segs) { // also sets seg.key
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var element;
|
|
|
+ var key, val;
|
|
|
+ var hsideCache = {};
|
|
|
// record event horizontal sides
|
|
|
for (i=0; i<segCnt; i++) {
|
|
|
seg = segs[i];
|
|
|
- if (eventElement = seg.element) {
|
|
|
- val = hsideCache[key = seg.key = cssKey(eventElement[0])];
|
|
|
- seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
|
|
|
+ element = seg.element;
|
|
|
+ if (element) {
|
|
|
+ key = seg.key = cssKey(element[0]);
|
|
|
+ val = hsideCache[key];
|
|
|
+ if (val === undefined) {
|
|
|
+ val = hsideCache[key] = hsides(element[0], true);
|
|
|
+ }
|
|
|
+ seg.hsides = val;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // set event widths
|
|
|
+
|
|
|
+ function daySegSetWidths(segs) {
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var element;
|
|
|
for (i=0; i<segCnt; i++) {
|
|
|
seg = segs[i];
|
|
|
- if (eventElement = seg.element) {
|
|
|
- eventElement[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';
|
|
|
+ element = seg.element;
|
|
|
+ if (element) {
|
|
|
+ element[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+
|
|
|
+ function daySegCalcHeights(segs) {
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var element;
|
|
|
+ var key, val;
|
|
|
+ var vmarginCache = {};
|
|
|
// record event heights
|
|
|
for (i=0; i<segCnt; i++) {
|
|
|
seg = segs[i];
|
|
|
- if (eventElement = seg.element) {
|
|
|
- val = vmarginCache[key = seg.key];
|
|
|
- seg.outerHeight = eventElement[0].offsetHeight + (
|
|
|
- val === undefined ? (vmarginCache[key] = vmargins(eventElement[0])) : val
|
|
|
- );
|
|
|
+ element = seg.element;
|
|
|
+ if (element) {
|
|
|
+ key = seg.key; // created in daySegCalcHSides
|
|
|
+ val = vmarginCache[key];
|
|
|
+ if (val === undefined) {
|
|
|
+ val = vmarginCache[key] = vmargins(element[0]);
|
|
|
+ }
|
|
|
+ seg.outerHeight = element[0].offsetHeight + val;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // set row heights, calculate event tops (in relation to row top)
|
|
|
- for (i=0, rowI=0; rowI<rowCnt; rowI++) {
|
|
|
- top = levelI = levelHeight = 0;
|
|
|
- while (i<segCnt && (seg = segs[i]).row == rowI) {
|
|
|
- if (seg.level != levelI) {
|
|
|
- top += levelHeight;
|
|
|
- levelHeight = 0;
|
|
|
- levelI++;
|
|
|
- }
|
|
|
- levelHeight = Math.max(levelHeight, seg.outerHeight||0);
|
|
|
- seg.top = top;
|
|
|
- i++;
|
|
|
- }
|
|
|
- rowDivs[rowI] = allDayTR(rowI).find('td:first div.fc-day-content > div') // optimal selector?
|
|
|
- .height(top + levelHeight);
|
|
|
+
|
|
|
+ function getRowDivs() {
|
|
|
+ var i;
|
|
|
+ var rowCnt = getRowCnt();
|
|
|
+ var rowDivs = [];
|
|
|
+ for (i=0; i<rowCnt; i++) {
|
|
|
+ rowDivs[i] = allDayTR(i)
|
|
|
+ .find('td:first div.fc-day-content > div'); // optimal selector?
|
|
|
}
|
|
|
+ return rowDivs;
|
|
|
+ }
|
|
|
|
|
|
- // calculate row tops
|
|
|
- for (rowI=0; rowI<rowCnt; rowI++) {
|
|
|
- rowDivTops[rowI] = rowDivs[rowI][0].offsetTop;
|
|
|
+
|
|
|
+ function getRowTops(rowDivs) {
|
|
|
+ var i;
|
|
|
+ var rowCnt = rowDivs.length;
|
|
|
+ var tops = [];
|
|
|
+ for (i=0; i<rowCnt; i++) {
|
|
|
+ tops[i] = rowDivs[i][0].offsetTop;
|
|
|
}
|
|
|
+ return tops;
|
|
|
+ }
|
|
|
|
|
|
- // set event tops
|
|
|
+
|
|
|
+ function daySegSetTops(segs, rowTops) { // also triggers eventAfterRender
|
|
|
+ var i;
|
|
|
+ var segCnt = segs.length;
|
|
|
+ var seg;
|
|
|
+ var element;
|
|
|
+ var event;
|
|
|
for (i=0; i<segCnt; i++) {
|
|
|
seg = segs[i];
|
|
|
- if (eventElement = seg.element) {
|
|
|
- eventElement[0].style.top = rowDivTops[seg.row] + seg.top + 'px';
|
|
|
+ element = seg.element;
|
|
|
+ if (element) {
|
|
|
+ element[0].style.top = rowTops[seg.row] + (seg.top||0) + 'px';
|
|
|
event = seg.event;
|
|
|
- trigger('eventAfterRender', event, event, eventElement);
|
|
|
+ trigger('eventAfterRender', event, event, element);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -199,30 +340,76 @@ function DayEventRenderer() {
|
|
|
-----------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
- function resizableDayEvent(event, eventElement) {
|
|
|
- if (!opt('disableResizing') && eventElement.resizable) {
|
|
|
- var colWidth = getColWidth();
|
|
|
- eventElement.resizable({
|
|
|
- handles: opt('isRTL') ? {w:'div.ui-resizable-w'} : {e:'div.ui-resizable-e'},
|
|
|
- grid: colWidth,
|
|
|
- minWidth: colWidth/2, // need this or else IE throws errors when too small
|
|
|
- containment: t.element.parent().parent(), // the main element...
|
|
|
- // ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?)
|
|
|
- start: function(ev, ui) {
|
|
|
- eventElement.css('z-index', 9);
|
|
|
- hideEvents(event, eventElement);
|
|
|
- trigger('eventResizeStart', this, event, ev, ui);
|
|
|
- },
|
|
|
- stop: function(ev, ui) {
|
|
|
- trigger('eventResizeStop', this, event, ev, ui);
|
|
|
- // ui.size.width wasn't working with grid correctly, use .width()
|
|
|
- var dayDelta = Math.round((eventElement.width() - ui.originalSize.width) / colWidth);
|
|
|
+ function resizableDayEvent(event, element, seg) {
|
|
|
+ if (!opt('disableResizing') && seg.isEnd) {
|
|
|
+ var rtl = opt('isRTL');
|
|
|
+ var direction = rtl ? 'w' : 'e';
|
|
|
+ var handle = element.find('div.ui-resizable-' + direction);
|
|
|
+ handle.mousedown(function(ev) {
|
|
|
+ if (ev.which != 1) {
|
|
|
+ return; // needs to be left mouse button
|
|
|
+ }
|
|
|
+ var hoverListener = t.getHoverListener();
|
|
|
+ var rowCnt = getRowCnt();
|
|
|
+ var colCnt = getColCnt();
|
|
|
+ var dis = rtl ? -1 : 1;
|
|
|
+ var dit = rtl ? colCnt : 0;
|
|
|
+ var elementTop = element.css('top');
|
|
|
+ var dayDelta;
|
|
|
+ var helpers;
|
|
|
+ var eventCopy = $.extend({}, event);
|
|
|
+ var minCell = dateCell(event.start);
|
|
|
+ clearSelection();
|
|
|
+ $('body')
|
|
|
+ .css('cursor', direction + '-resize')
|
|
|
+ .one('mouseup', mouseup);
|
|
|
+ trigger('eventResizeStart', this, event, ev);
|
|
|
+ hoverListener.start(function(cell, origCell) {
|
|
|
+ if (cell) {
|
|
|
+ var r = Math.max(minCell.row, cell.row);
|
|
|
+ var c = cell.col;
|
|
|
+ if (rowCnt == 1) {
|
|
|
+ r = 0; // hack for all-day area in agenda views
|
|
|
+ }
|
|
|
+ if (r == minCell.row) {
|
|
|
+ if (rtl) {
|
|
|
+ c = Math.min(minCell.col, c);
|
|
|
+ }else{
|
|
|
+ c = Math.max(minCell.col, c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dayDelta = (r * colCnt + c*dis+dit) - (origCell.row * colCnt + origCell.col*dis+dit);
|
|
|
+ var newEnd = addDays(eventEnd(event), dayDelta, true);
|
|
|
+ if (dayDelta) {
|
|
|
+ eventCopy.end = newEnd;
|
|
|
+ var oldHelpers = helpers;
|
|
|
+ helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);
|
|
|
+ helpers.find('*').css('cursor', direction + '-resize');
|
|
|
+ if (oldHelpers) {
|
|
|
+ oldHelpers.remove();
|
|
|
+ }
|
|
|
+ hideEvents(event);
|
|
|
+ }else{
|
|
|
+ if (helpers) {
|
|
|
+ showEvents(event);
|
|
|
+ helpers.remove();
|
|
|
+ helpers = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ clearOverlays();
|
|
|
+ renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start
|
|
|
+ }
|
|
|
+ }, ev);
|
|
|
+ function mouseup(ev) {
|
|
|
+ trigger('eventResizeStop', this, event, ev);
|
|
|
+ $('body').css('cursor', 'auto');
|
|
|
+ hoverListener.stop();
|
|
|
+ clearOverlays();
|
|
|
if (dayDelta) {
|
|
|
- eventResize(this, event, dayDelta, 0, ev, ui);
|
|
|
- }else{
|
|
|
- eventElement.css('z-index', 8);
|
|
|
- showEvents(event, eventElement);
|
|
|
+ eventResize(this, event, dayDelta, 0, ev);
|
|
|
+ // event redraw will clear helpers
|
|
|
}
|
|
|
+ // otherwise, the drag handler already restored the old events
|
|
|
}
|
|
|
});
|
|
|
}
|