/* Methods & Utilities for All Views -----------------------------------------------------------------------------*/ var viewMethods = { /* * Objects inheriting these methods must implement the following properties/methods: * - title * - start * - end * - visStart * - visEnd * - defaultEventEnd(event) * - render(events) * - rerenderEvents() * * * z-index reservations: * 3 - day-overlay * 8 - events * 9 - dragging/resizing events * */ init: function(element, options) { this.element = element; this.options = options; this.eventsByID = {}; this.eventElements = []; this.eventElementsByID = {}; this.usedOverlays = []; this.unusedOverlays = []; }, // triggers an event handler, always append view as last arg trigger: function(name, thisObj) { if (this.options[name]) { return this.options[name].apply(thisObj || this, Array.prototype.slice.call(arguments, 2).concat([this])); } }, // returns a Date object for an event's end eventEnd: function(event) { return event.end ? cloneDate(event.end) : this.defaultEventEnd(event); // TODO: make sure always using copies }, // report when view receives new events reportEvents: function(events) { // events are already normalized at this point var i, len=events.length, event, eventsByID = this.eventsByID = {}; for (i=0; i"); } if (e[0].parentNode != parent[0]) { e.appendTo(parent); } this.usedOverlays.push(e.css(rect).show()); return e; }, clearOverlays: function() { var e; while (e = this.usedOverlays.shift()) { this.unusedOverlays.push(e.hide().unbind()); } }, // common horizontal event resizing resizableDayEvent: function(event, eventElement, colWidth) { var view = this; if (!view.options.disableResizing && eventElement.resizable) { eventElement.resizable({ 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... // ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?) start: function(ev, ui) { eventElement.css('z-index', 9); view.hideEvents(event, eventElement); view.trigger('eventResizeStart', this, event, ev, ui); }, stop: function(ev, ui) { view.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); if (dayDelta) { view.eventResize(this, event, dayDelta, 0, ev, ui); }else{ eventElement.css('z-index', 8); view.showEvents(event, eventElement); } } }); } }, // attaches eventClick, eventMouseover, eventMouseout eventElementHandlers: function(event, eventElement) { var view = this; eventElement .click(function(ev) { if (!eventElement.hasClass('ui-draggable-dragging') && !eventElement.hasClass('ui-resizable-resizing')) { return view.trigger('eventClick', this, event, ev); } }) .hover( function(ev) { view.trigger('eventMouseover', this, event, ev); }, function(ev) { view.trigger('eventMouseout', this, event, ev); } ); }, // get a property from the 'options' object, using smart view naming option: function(name, viewName) { var v = this.options[name]; if (typeof v == 'object') { return smartProperty(v, viewName || this.name); } return v; }, // event rendering utilities sliceSegs: function(events, visEventEnds, start, end) { var segs = [], i, len=events.length, event, eventStart, eventEnd, segStart, segEnd, isStart, isEnd; for (i=0; i start && eventStart < end) { if (eventStart < start) { segStart = cloneDate(start); isStart = false; }else{ segStart = eventStart; isStart = true; } if (eventEnd > end) { segEnd = cloneDate(end); isEnd = false; }else{ segEnd = eventEnd; isEnd = true; } segs.push({ event: event, start: segStart, end: segEnd, isStart: isStart, isEnd: isEnd, msLength: segEnd - segStart }); } } return segs.sort(segCmp); } }; 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(); }); } // event rendering calculation utilities function stackSegs(segs) { var levels = [], i, len = segs.length, seg, j, collide, k; for (i=0; i seg2.start && seg1.start < seg2.end; }