event binding optimization, fixed optimization-related mouseover bug

This commit is contained in:
Adam Shaw 2010-02-02 10:50:30 -08:00
parent 0e3e04bbdf
commit 16edfe71e7
3 changed files with 91 additions and 75 deletions

View file

@ -347,7 +347,7 @@ function Agenda(element, options, methods) {
/* Event Rendering
-----------------------------------------------------------------------------*/
function renderEvents(events) {
function renderEvents(events, modifiedEventId) {
view.reportEvents(cachedEvents = events);
var i, len=events.length,
dayEvents=[],
@ -359,14 +359,14 @@ function Agenda(element, options, methods) {
slotEvents.push(events[i]);
}
}
renderDaySegs(compileDaySegs(dayEvents));
renderSlotSegs(compileSlotSegs(slotEvents));
renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);
renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);
}
function rerenderEvents() {
function rerenderEvents(modifiedEventId) {
clearEvents();
renderEvents(cachedEvents);
renderEvents(cachedEvents, modifiedEventId);
}
@ -427,7 +427,7 @@ function Agenda(element, options, methods) {
// renders 'all-day' events at the top
function renderDaySegs(segs) {
function renderDaySegs(segs, modifiedEventId) {
if (options.allDaySlot) {
_renderDaySegs(
segs,
@ -445,7 +445,8 @@ function Agenda(element, options, methods) {
return axisWidth + colContentPositions.right(day2col(dayOfWeek));
},
daySegmentContainer,
bootstrapDayEventHandlers
bindDaySegHandlers,
modifiedEventId
);
updateSize(viewWidth, viewHeight); // might have pushed the body down, so resize
}
@ -455,7 +456,7 @@ function Agenda(element, options, methods) {
// renders events in the 'time slots' at the bottom
function renderSlotSegs(segs) {
function renderSlotSegs(segs, modifiedEventId) {
var i, segCnt=segs.length, seg,
event,
@ -467,7 +468,7 @@ function Agenda(element, options, methods) {
outerWidth,
left,
html='',
_eventElements,
eventElements,
eventElement,
triggerRes,
vsideCache={},
@ -527,13 +528,13 @@ function Agenda(element, options, methods) {
"</div>";
}
slotSegmentContainer[0].innerHTML = html;
_eventElements = $.makeArray(slotSegmentContainer[0].childNodes); // TODO: look at .children() again
eventElements = slotSegmentContainer.children();
// retrieve elements, run through eventRender callback, bind event handlers
for (i=0; i<segCnt; i++) {
seg = segs[i];
event = seg.event;
eventElement = $(_eventElements[i]);
eventElement = $(eventElements[i]); // faster than eq()
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes === false) {
eventElement.remove();
@ -549,11 +550,17 @@ function Agenda(element, options, methods) {
.appendTo(slotSegmentContainer);
}
seg.element = eventElement;
bootstrapSlotEventHandlers(event, seg, eventElement);
if (event._id === modifiedEventId) {
bindSlotSegHandlers(event, eventElement, seg);
}else{
eventElement[0]._fci = i; // for lazySegBind
}
view.reportEventElement(event, eventElement);
}
}
lazySegBind(slotSegmentContainer, segs, bindSlotSegHandlers);
// record event sides and title positions
for (i=0; i<segCnt; i++) {
seg = segs[i];
@ -611,41 +618,27 @@ function Agenda(element, options, methods) {
function bootstrapDayEventHandlers(event, seg, eventElement) {
function mouseover(ev) {
view.trigger('eventMouseover', this, event, ev);
eventElement.unbind('mouseover', mouseover);
setTimeout(function() { // because IE will immediately trigger eventElementHandlers's mouseover
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableDayEvent(event, eventElement, seg.isStart);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
},0);
function bindDaySegHandlers(event, eventElement, seg) {
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableDayEvent(event, eventElement, seg.isStart);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
eventElement.mouseover(mouseover);
}
function bootstrapSlotEventHandlers(event, seg, eventElement) {
function mouseover(ev) {
view.trigger('eventMouseover', this, event, ev);
eventElement.unbind('mouseover', mouseover);
setTimeout(function() { // because IE will immediately trigger eventElementHandlers's mouseover
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
var timeElement = eventElement.find('span.fc-event-time');
draggableSlotEvent(event, eventElement, timeElement);
if (seg.isEnd) {
resizableSlotEvent(event, eventElement, timeElement);
}
}
},0);
function bindSlotSegHandlers(event, eventElement, seg) {
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
var timeElement = eventElement.find('span.fc-event-time');
draggableSlotEvent(event, eventElement, timeElement);
if (seg.isEnd) {
resizableSlotEvent(event, eventElement, timeElement);
}
}
eventElement.mouseover(mouseover);
}

View file

@ -370,9 +370,9 @@ function Grid(element, options, methods) {
}
function rerenderEvents() {
function rerenderEvents(modifiedEventId) {
clearEvents();
renderSegs(compileSegs(cachedEvents));
renderSegs(compileSegs(cachedEvents), modifiedEventId);
}
@ -409,7 +409,7 @@ function Grid(element, options, methods) {
function renderSegs(segs) {
function renderSegs(segs, modifiedEventId) {
_renderDaySegs(
segs,
rowCnt,
@ -420,7 +420,8 @@ function Grid(element, options, methods) {
dayContentPositions.left,
dayContentPositions.right,
segmentContainer,
mouseoverBind
bindSegHandlers,
modifiedEventId
);
}
@ -437,22 +438,14 @@ function Grid(element, options, methods) {
function mouseoverBind(event, seg, eventElement) {
function mouseover(ev) {
eventElement.unbind('mouseover', mouseover);
view.trigger('eventMouseover', this, event, ev);
setTimeout(function() { // because IE will immediately trigger the new mouseover handlers
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableEvent(event, eventElement);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
},0);
function bindSegHandlers(event, eventElement, seg) {
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableEvent(event, eventElement);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
eventElement.mouseover(mouseover);
}
@ -519,7 +512,7 @@ function Grid(element, options, methods) {
};
function _renderDaySegs(segs, rowCnt, view, minLeft, maxLeft, getRow, dayContentLeft, dayContentRight, segmentContainer, mouseoverBind) {
function _renderDaySegs(segs, rowCnt, view, minLeft, maxLeft, getRow, dayContentLeft, dayContentRight, segmentContainer, bindSegHandlers, modifiedEventId) {
var options=view.options,
rtl=options.isRTL,
@ -528,7 +521,7 @@ function _renderDaySegs(segs, rowCnt, view, minLeft, maxLeft, getRow, dayContent
className,
left, right,
html='',
_eventElements,
eventElements,
eventElement,
triggerRes,
hsideCache={},
@ -572,17 +565,20 @@ function _renderDaySegs(segs, rowCnt, view, minLeft, maxLeft, getRow, dayContent
:'') +
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
"</a>" +
((event.editable || event.editable == undefined && options.editable) && !options.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;
_eventElements = $.makeArray(segmentContainer[0].childNodes); // TODO: look at .children() again
eventElements = segmentContainer.children();
// retrieve elements, run through eventRender callback, bind handlers
for (i=0; i<segCnt; i++) {
seg = segs[i];
eventElement = $(_eventElements[i]);
eventElement = $(eventElements[i]); // faster than eq()
event = seg.event;
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes === false) {
@ -598,11 +594,17 @@ function _renderDaySegs(segs, rowCnt, view, minLeft, maxLeft, getRow, dayContent
.appendTo(segmentContainer);
}
seg.element = eventElement;
mouseoverBind(event, seg, eventElement);
if (event._id === modifiedEventId) {
bindSegHandlers(event, eventElement, seg);
}else{
eventElement[0]._fci = i; // for lazySegBind
}
view.reportEventElement(event, eventElement);
}
}
lazySegBind(segmentContainer, segs, bindSegHandlers);
// record event horizontal sides
for (i=0; i<segCnt; i++) {
seg = segs[i];
@ -671,3 +673,23 @@ function cssKey(_element) {
}
function lazySegBind(container, segs, bindHandlers) {
container.unbind('mouseover').mouseover(function(ev) {
var parent=ev.target, e,
i, seg;
while (parent != this) {
e = parent;
parent = parent.parentNode;
}
if ((i = e._fci) != undefined) {
e._fci = undefined;
seg = segs[i];
bindHandlers(seg.event, seg.element, seg);
$(ev.target).trigger(ev);
}
ev.stopPropagation();
});
}

View file

@ -117,27 +117,29 @@ var viewMethods = {
eventDrop: function(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
var view = this,
oldAllDay = event.allDay;
view.moveEvents(view.eventsByID[event._id], dayDelta, minuteDelta, allDay);
oldAllDay = event.allDay,
eventId = event._id;
view.moveEvents(view.eventsByID[eventId], dayDelta, minuteDelta, allDay);
view.trigger('eventDrop', e, event, dayDelta, minuteDelta, allDay, function() { // TODO: change docs
// TODO: investigate cases where this inverse technique might not work
view.moveEvents(view.eventsByID[event._id], -dayDelta, -minuteDelta, oldAllDay);
view.moveEvents(view.eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);
view.rerenderEvents();
}, ev, ui);
view.eventsChanged = true;
view.rerenderEvents();
view.rerenderEvents(eventId);
},
eventResize: function(e, event, dayDelta, minuteDelta, ev, ui) {
var view = this;
view.elongateEvents(view.eventsByID[event._id], dayDelta, minuteDelta);
var view = this,
eventId = event._id;
view.elongateEvents(view.eventsByID[eventId], dayDelta, minuteDelta);
view.trigger('eventResize', e, event, dayDelta, minuteDelta, function() {
// TODO: investigate cases where this inverse technique might not work
view.elongateEvents(view.eventsByID[event._id], -dayDelta, -minuteDelta);
view.elongateEvents(view.eventsByID[eventId], -dayDelta, -minuteDelta);
view.rerenderEvents();
}, ev, ui);
view.eventsChanged = true;
view.rerenderEvents();
view.rerenderEvents(eventId);
},
@ -202,7 +204,7 @@ var viewMethods = {
var view = this;
if (!view.options.disableResizing && eventElement.resizable) {
eventElement.resizable({
handles: view.options.isRTL ? 'w' : 'e',
handles: view.options.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: view.element.parent().parent(), // the main element...
@ -309,7 +311,6 @@ var viewMethods = {
// event rendering calculation utilities
function stackSegs(segs) {