/* bind method: attachToEventCells(cells), attachToDayNode(dayNode) * callback method: updateDropCallback(this, eventCells, delta), createDropCallback(this, dayDate, currentCoordinates); */ var SOGoEventDragDayLength = 24 * 4; /* quarters */ var SOGoEventDragHandleSize = 8; /* handles for dragging mode */ var SOGoEventDragHorizontalOffset = 3; var SOGoEventDragVerticalOffset = 3; /* singleton */ var _sogoEventDragUtilities = null; function SOGoEventDragUtilities() { if (!_sogoEventDragUtilities) _sogoEventDragUtilities = new _SOGoEventDragUtilities(); return _sogoEventDragUtilities; } function _SOGoEventDragUtilities() { } _SOGoEventDragUtilities.prototype = { eventType: null, eventContainerNodes: null, _prepareEventContainerNodes: null, quarterHeight: -1, dayWidth: -1, dayHeight: -1, daysOffset: -1, eventsViewNode: null, eventsViewNodeCumulativeCoordinates: null, reset: function() { this.eventContainerNodes = null; this._prepareEventContainerNodes = null; this.quarterHeight = -1; this.dayWidth = -1; this.dayHeight = -1; this.daysOffset = -1; this.eventsViewNode = null; this.eventsViewNodeCumulativeCoordinates = null; }, setEventType: function(eventType) { var prepareMethods = { "multiday": this._prepareEventMultiDayContainerNodes, "multiday-allday": this._prepareEventMultiDayAllDayContainerNodes, "monthly": this._prepareEventMonthlyContainerNodes, "unknown": null }; this._prepareEventContainerNodes = prepareMethods[eventType]; this.eventType = eventType; }, getEventType: function(eventType) { return this.eventType; }, getEventContainerNodes: function() { if (!this.eventContainerNodes) { this._prepareEventContainerNodes(); } return this.eventContainerNodes; }, _prepareEventMultiDayContainerNodes: function() { this.eventContainerNodes = []; var daysView = $("daysView"); var daysViewSubnodes = daysView.childNodesWithTag("div"); for (var i = 0; i < daysViewSubnodes.length; i++) { var daysViewSubnode = daysViewSubnodes[i]; if (daysViewSubnode.hasClassName("days")) { this.daysOffset = daysViewSubnode.offsetLeft + 2; var daysSubnodes = daysViewSubnode.childNodesWithTag("div"); for (var j = 0; j < daysSubnodes.length; j++) { var daysSubnode = daysSubnodes[j]; if (daysSubnode.hasClassName("day")) { this._appendDayEventsNode(daysSubnode); } } } } }, _prepareEventMultiDayAllDayContainerNodes: function() { this.eventContainerNodes = []; var headerNode = $("calendarHeader"); var headerSubnodes = headerNode.childNodesWithTag("div"); for (var i = 0; i < headerSubnodes.length; i++) { var headerSubnode = headerSubnodes[i]; if (headerSubnode.hasClassName("days")) { this.daysOffset = headerSubnode.offsetLeft + 2; var daysSubnodes = headerSubnode.childNodesWithTag("div"); for (var j = 0; j < daysSubnodes.length; j++) { var daysSubnode = daysSubnodes[j]; if (daysSubnode.hasClassName("day")) this.eventContainerNodes.push(daysSubnode); } } } }, _prepareEventMonthlyContainerNodes: function() { var monthView = $("monthDaysView"); this.eventContainerNodes = monthView.childNodesWithTag("div"); this.daysOffset = this.eventContainerNodes[0].offsetLeft + 2; }, _appendDayEventsNode: function(dayNode) { var daySubnodes = dayNode.childNodesWithTag("div"); for (var i = 0; i < daySubnodes.length; i++) { var daySubnode = daySubnodes[i]; if (daySubnode.hasClassName("events")) { this.eventContainerNodes.push(daySubnode); } } }, getQuarterHeight: function() { if (this.quarterHeight == -1) { var hour0 = $("hour0"); var hour23 = $("hour23"); this.quarterHeight = ((hour23.offsetTop - hour0.offsetTop) / (23 * 4)); } return this.quarterHeight; }, getDaysOffset: function() { if (this.daysOffset == -1) this._prepareEventContainerNodes(); return this.daysOffset; }, getDayWidth: function() { if (this.dayWidth == -1) { var nodes = this.getEventContainerNodes(); if (nodes.length > 1) { if (this.eventType == "monthly") { var total = (nodes[6].cumulativeOffset()[0] - nodes[0].cumulativeOffset()[0]); this.dayWidth = total / 6; } else { var total = (nodes[nodes.length-1].cumulativeOffset()[0] - nodes[0].cumulativeOffset()[0]); this.dayWidth = total / (nodes.length - 1); } } else this.dayWidth = nodes[0].offsetWidth; } return this.dayWidth; }, getDayHeight: function() { /* currently only used for monthly view */ if (this.dayHeight == -1) { var nodes = this.getEventContainerNodes(); if (nodes.length > 1) { var total = (nodes[3*7].cumulativeOffset()[1] - nodes[0].cumulativeOffset()[1]); this.dayHeight = total / 3; } } return this.dayHeight; }, getEventsViewNode: function() { if (!this.eventsViewNode) { if (this.eventType.startsWith("multiday")) this.eventsViewNode = $("daysView"); else if (this.eventType.startsWith("multiday-allday")) { this.eventsViewNode = $("calendarHeader"); } else this.eventsViewNode = $("monthDaysView"); } return this.eventsViewNode; }, getEventsViewNodeCumulativeCoordinates: function() { if (!this.eventsViewNodeCumulativeCoordinates) { this.eventsViewNodeCumulativeCoordinates = new SOGoCoordinates(); var node = this.getEventsViewNode(); var cumulativeOffset = node.cumulativeOffset(); this.eventsViewNodeCumulativeCoordinates.x = cumulativeOffset[0]; this.eventsViewNodeCumulativeCoordinates.y = cumulativeOffset[1]; } return this.eventsViewNodeCumulativeCoordinates; } }; function SOGoEventDragEventCoordinates() { } SOGoEventDragEventCoordinates.prototype = { dayNumber: -1, start: -1, duration: -1, eventType: null, setEventType: function(eventType) { this.eventType = eventType; this._prepareEventType(); }, _prepareEventType: function() { var methods = { "multiday": this.initFromEventCellMultiDay, "multiday-allday": this.initFromEventCellMultiDayAllDay, "monthly": this.initFromEventCellMonthly, "unknown": null }; this.initFromEventCell = methods[this.eventType]; }, initFromEventCellMultiDay: function(eventCell) { var classNames = eventCell.className.split(" "); for (var i = 0; (this.start == -1 || this.duration == -1) && i < classNames.length; i++) { var className = classNames[i]; if (className.startsWith("starts")) { this.start = parseInt(className.substr(6)); } else if (className.startsWith("lasts")) { this.duration = parseInt(className.substr(5)); } } var dayNumber = -1; var dayNode = eventCell.parentNode.parentNode; var classNames = dayNode.className.split(" "); for (var i = 0; dayNumber == -1 && i < classNames.length; i++) { var className = classNames[i]; if (className.startsWith("day") && className.length > 3) { dayNumber = parseInt(className.substr(3)); } } this.dayNumber = dayNumber; }, initFromEventCellMultiDayAllDay: function(eventCell) { this.start = 0; this.duration = SOGoEventDragDayLength; var dayNode = eventCell.parentNode; var classNames = dayNode.className.split(" "); var dayNumber = -1; for (var i = 0; dayNumber == -1 && i < classNames.length; i++) { var className = classNames[i]; if (className.startsWith("day") && className.length > 3) { dayNumber = parseInt(className.substr(3)); } } this.dayNumber = dayNumber; }, initFromEventCellMonthly: function(eventCell) { this.start = 0; this.duration = SOGoEventDragDayLength; var dayNumber = -1; var week = -1; var day = -1; var dayNode = eventCell.parentNode; var classNames = dayNode.className.split(" "); for (var i = 0; (day == -1 || week == -1) && i < classNames.length; i++) { var className = classNames[i]; if (className.startsWith("day") && className.length > 3) { day = parseInt(className.substr(3)); } else if (className.startsWith("week") && !className.startsWith("weekOf") && className != "weekEndDay") { var ofIndex = className.indexOf("of"); if (ofIndex > -1) { var len = ofIndex - 4; week = parseInt(className.substr(4, len)); } } } this.dayNumber = week * 7 + day; }, initFromEventCells: function(eventCells) { this.duration = 0; for (var i = 0; i < eventCells.length; i++) { var current = new SOGoEventDragEventCoordinates(); current.setEventType(this.eventType); current.initFromEventCell(eventCells[i]); if (this.dayNumber == -1 || current.dayNumber < this.dayNumber) { this.dayNumber = current.dayNumber; this.start = current.start; } this.duration += current.duration; } }, getDelta: function(otherCoordinates) { var delta = new SOGoEventDragEventCoordinates(); delta.dayNumber = (this.dayNumber - otherCoordinates.dayNumber); delta.start = (this.start - otherCoordinates.start); delta.duration = (this.duration - otherCoordinates.duration); return delta; }, _quartersToHM: function(quarters) { var minutes = quarters * 15; var hours = Math.floor(minutes / 60); if (hours < 10) hours = "0" + hours; var mins = minutes % 60; if (mins < 10) mins = "0" + mins; return "" + hours + ":" + mins; }, getStartTime: function() { return this._quartersToHM(this.start); }, getEndTime: function() { var end = (this.start + this.duration) % SOGoEventDragDayLength; return this._quartersToHM(end); }, clone: function() { var coordinates = new SOGoEventDragEventCoordinates(); coordinates.dayNumber = this.dayNumber; coordinates.start = this.start; coordinates.duration = this.duration; return coordinates; } }; var SOGoDragGhostInterface = { visible: true, title: null, folderClass: null, inside: null, currentStart: -1, currentDuration: -1, isStartGhost: false, isEndGhost: false, show: function SDGI_show() { if (!this.visible) { this.removeClassName("hidden"); if (this.inside) this.inside.removeClassName("hidden"); this.visible = true; } }, hide: function SDGI_hide() { if (this.visible) { this.addClassName("hidden"); if (this.inside) this.inside.addClassName("hidden"); this.visible = false; } }, setTitle: function SDGI_setTitle(title) { if (this.title != title) { while (this.inside.childNodes.length) { this.inside.removeChild(this.inside.firstChild); } if (title) { this.inside.appendChild(document.createTextNode(title)); } this.title = title; } }, setLocation: function SDGI_setLocation(location) { if (this.location != location) { var spans = this.inside.select("SPAN.location"); if (spans && spans.length > 0) { this.inside.removeChild(spans[0]); } if (location) { this.inside.appendChild(createElement("br")); var span = createElement("span", null, "location"); span.appendChild(document.createTextNode(location)); this.inside.appendChild(span); } this.location = location; } }, setFolderClass: function SDGI_setFolderClass(folderClass) { if (this.folderClass != folderClass) { this.removeClassName(this.folderClass); this.folderClass = folderClass; this.addClassName(this.folderClass); } }, setStart: function SDGI_setStart(start) { if (this.currentStart != start) { if (this.cssHandlesPosition) this.removeClassName("starts" + this.currentStart); this.currentStart = start; if (this.cssHandlesPosition) this.addClassName("starts" + this.currentStart); } }, setDuration: function SDGI_setDuration(duration) { if (this.currentDuration != duration) { if (this.cssHandlesPosition) this.removeClassName("lasts" + this.currentDuration); this.currentDuration = duration; if (this.cssHandlesPosition) this.addClassName("lasts" + this.currentDuration); } }, setStartGhost: function SDGI_setStartGhost() { if (!this.isStartGhost) { this.addClassName("startGhost"); this.isStartGhost = true; } }, unsetStartGhost: function SDGI_unsetStartGhost() { if (this.isStartGhost) { this.removeClassName("startGhost"); this.isStartGhost = false; } }, setEndGhost: function SDGI_setEndGhost() { if (!this.isEndGhost) { this.addClassName("endGhost"); this.isEndGhost = true; } }, unsetEndGhost: function SDGI_unsetEndGhost() { if (this.isEndGhost) { this.removeClassName("endGhost"); this.isEndGhost = false; } } }; function SOGoEventDragGhostController() { } SOGoEventDragGhostController.prototype = { originalCoordinates: null, currentCoordinates: null, originalPointerCoordinates: null, currentPointerCoordinates: null, dragMode: null, startHourPara: null, endHourPara: null, ghosts: null, initWithCoordinates: function SEDGC_initWithCoordinates(coordinates) { this.originalCoordinates = coordinates; this.currentCoordinates = coordinates.clone(); }, setTitle: function SEDGC_setTitle(title) { this.eventTitle = title; }, setLocation: function SEDGC_setLocation(location) { this.eventLocation = location; }, setFolderClass: function SEDGC_setFolderClass(folderClass) { this.folderClass = folderClass; }, setDragMode: function SEDGC_setDragMode(dragMode) { this.dragMode = dragMode; }, setPointerHandler: function SEDGC_setPointerHandler(pointerHandler) { this.pointerHandler = pointerHandler; this.originalPointerCoordinates = null; this.currentPointerCoordinates = null; this.updateFromPointerHandler(); this.originalPointerCoordinates = this.currentPointerCoordinates.clone(); }, updateFromPointerHandler: function SEDGC_updateFromPointerHandler() { var newCoordinates = this.pointerHandler.getEventViewCoordinates(); if (!this.currentPointerCoordinates || !newCoordinates || newCoordinates.x != this.currentPointerCoordinates.x || newCoordinates.y != this.currentPointerCoordinates.y) { this.currentPointerCoordinates = newCoordinates; if (this.originalPointerCoordinates) { if (!newCoordinates) this.currentPointerCoordinates = this.originalPointerCoordinates.clone(); this._updateCoordinates(); if (this.ghosts) { this._updateGhosts(); if (this.startHourPara) this._updateGhostsParas(); } } } }, _updateCoordinates: function SEDGC__updateCoordinates() { var delta = this.currentPointerCoordinates .getDelta(this.originalPointerCoordinates); var deltaQuarters = delta.x * SOGoEventDragDayLength + delta.y; this.currentCoordinates.dayNumber = this.originalCoordinates.dayNumber; // log("dragMode: " + this.dragMode); if (this.dragMode == "move-event") { this.currentCoordinates.start = this.originalCoordinates.start + deltaQuarters; this.currentCoordinates.duration = this.originalCoordinates.duration; // log("start: " + this.currentCoordinates.start); // log(" duration: " + this.currentCoordinates.duration); } else { if (this.dragMode == "change-start") { var newDuration = this.originalCoordinates.duration - deltaQuarters; if (newDuration > 0) { this.currentCoordinates.start = this.originalCoordinates.start + deltaQuarters; this.currentCoordinates.duration = newDuration; } else if (newDuration < 0) { this.currentCoordinates.start = (this.originalCoordinates.start + this.originalCoordinates.duration); this.currentCoordinates.duration = -newDuration; } } else if (this.dragMode == "change-end") { var newDuration = this.originalCoordinates.duration + deltaQuarters; if (newDuration > 0) { this.currentCoordinates.start = this.originalCoordinates.start; this.currentCoordinates.duration = newDuration; } else if (newDuration < 0) { this.currentCoordinates.start = this.originalCoordinates.start + newDuration; this.currentCoordinates.duration = -newDuration; } } } if (this.currentCoordinates.start < 0) { var deltaDays = Math.ceil(-this.currentCoordinates.start / SOGoEventDragDayLength); this.currentCoordinates.start += deltaDays * SOGoEventDragDayLength; this.currentCoordinates.dayNumber -= deltaDays; } else if (this.currentCoordinates.start >= SOGoEventDragDayLength) { var deltaDays = Math.floor(this.currentCoordinates.start / SOGoEventDragDayLength); this.currentCoordinates.start -= deltaDays * SOGoEventDragDayLength; this.currentCoordinates.dayNumber += deltaDays; } }, showGhosts: function SEDGC_showGhosts() { if (!this.ghosts) { this.ghosts = []; var utilities = SOGoEventDragUtilities(); var nodes = utilities.getEventContainerNodes(); var isMultiday = (utilities.getEventType() == "multiday"); for (var i = 0; i < nodes.length; i++) { var newGhost = $(document.createElement("div")); Object.extend(newGhost, SOGoDragGhostInterface); newGhost.className = "event eventDragGhost"; newGhost.cssHandlesPosition = isMultiday; newGhost.hide(); var ghostInside = $(document.createElement("div")); ghostInside.className = "eventInside"; newGhost.inside = ghostInside; newGhost.appendChild(ghostInside); nodes[i].appendChild(newGhost); this.ghosts.push(newGhost); } if (isMultiday) { var ghostHourPara = $(document.createElement("div")); ghostHourPara.setAttribute("id", "ghostStartHour"); this.startHourPara = ghostHourPara; ghostHourPara = $(document.createElement("div")); ghostHourPara.setAttribute("id", "ghostEndHour"); this.endHourPara = ghostHourPara; } this._updateGhosts(); if (this.startHourPara) this._updateGhostsParas(); } }, hideGhosts: function SEDGC_hideGhosts() { if (this.ghosts) { if (this.startHourPara && this.startHourPara.parentNode) this.startHourPara.parentNode.removeChild(this.startHourPara); this.startHourPara = null; if (this.endHourPara && this.endHourPara.parentNode) this.endHourPara.parentNode.removeChild(this.endHourPara); this.endHourPara = null; for (var i = 0; i < this.ghosts.length; i++) { var ghost = this.ghosts[i]; ghost.parentNode.removeChild(ghost); } this.ghosts = null; } }, _updateGhosts: function SEDGC__updateGhosts() { var maxGhosts = this.ghosts.length; var max = this.currentCoordinates.dayNumber; if (max > maxGhosts) max = maxGhosts; for (var i = 0; i < max; i++) { var ghost = this.ghosts[i]; ghost.hide(); ghost.unsetStartGhost(); ghost.unsetEndGhost(); } if (this.currentCoordinates.dayNumber < maxGhosts) { var currentDay = this.currentCoordinates.dayNumber; var durationLeft = this.currentCoordinates.duration; var start = this.currentCoordinates.start; var maxDuration = SOGoEventDragDayLength - start; var duration = durationLeft; if (duration > maxDuration) duration = maxDuration; var ghost = null; if (currentDay > -1) { ghost = this.ghosts[currentDay]; ghost.setStartGhost(); ghost.unsetEndGhost(); ghost.setTitle(this.eventTitle); ghost.setLocation(this.eventLocation); ghost.setFolderClass(this.folderClass); ghost.setStart(this.currentCoordinates.start); ghost.setDuration(duration); ghost.show(); if (this.startHourPara) { var parentNode = this.startHourPara.parentNode; if (parentNode && parentNode != ghost) parentNode.removeChild(this.startHourPara); ghost.appendChild(this.startHourPara); } } durationLeft -= duration; currentDay++; while (durationLeft && currentDay < maxGhosts) { duration = durationLeft; if (duration > SOGoEventDragDayLength) duration = SOGoEventDragDayLength; if (currentDay > -1) { ghost = this.ghosts[currentDay]; ghost.unsetStartGhost(); ghost.unsetEndGhost(); ghost.setTitle(); ghost.setFolderClass(this.folderClass); ghost.setStart(0); ghost.setDuration(duration); ghost.show(); } durationLeft -= duration; currentDay++; } if (!durationLeft) { ghost.setEndGhost(); } if (this.endHourPara) { var parentNode = this.endHourPara.parentNode; if (parentNode && parentNode != ghost) parentNode.removeChild(this.endHourPara); ghost.appendChild(this.endHourPara); } while (currentDay < maxGhosts) { var ghost = this.ghosts[currentDay]; ghost.hide(); ghost.unsetStartGhost(); ghost.unsetEndGhost(); currentDay++; } } }, _updateGhostsParas: function SEDGC__updateGhostsParas() { var para = this.startHourPara; while (para.childNodes.length) para.removeChild(para.childNodes[0]); var time = this.currentCoordinates.getStartTime(); para.appendChild(document.createTextNode(time)); para = this.endHourPara; while (para.childNodes.length) para.removeChild(para.childNodes[0]); time = this.currentCoordinates.getEndTime(); para.appendChild(document.createTextNode(time)); } }; function SOGoCoordinates() { } SOGoCoordinates.prototype = { x: -1, y: -1, getDelta: function SC_getDelta(otherCoordinates) { var delta = new SOGoCoordinates(); delta.x = this.x - otherCoordinates.x; delta.y = this.y - otherCoordinates.y; return delta; }, getDistance: function SC_getDistance(otherCoordinates) { var delta = this.getDelta(otherCoordinates); return Math.sqrt(delta.x * delta.x + delta.y * delta.y); }, clone: function SC_clone() { var coordinates = new SOGoCoordinates(); coordinates.x = this.x; coordinates.y = this.y; return coordinates; } }; function SOGoEventDragPointerHandler() { } SOGoEventDragPointerHandler.prototype = { originalCoordinates: null, currentCoordinates: null, containerCoordinates: null, /* return the day and quarter coordinates of the pointer cursor within the day view */ getEventViewCoordinates: null, initFromEvent: function SEDPH_initFromEvent(event) { this.currentCoordinates = new SOGoCoordinates(); this.updateFromEvent(event); this.originalCoordinates = this.currentCoordinates.clone(); var utilities = SOGoEventDragUtilities(); this.containerCoordinates = utilities.getEventsViewNodeCumulativeCoordinates(); if (utilities.getEventType() == "multiday-allday") { /* a hack */ this.containerCoordinates.x -= SOGoEventDragVerticalOffset; this.containerCoordinates.y -= 40; } }, updateFromEvent: function SEDPH_updateFromEvent(event) { this.currentCoordinates.x = Event.pointerX(event); this.currentCoordinates.y = Event.pointerY(event); }, getContainerBasedCoordinates: function SEDPH_getCBC() { var coordinates = this.currentCoordinates.getDelta(this.containerCoordinates); var container = SOGoEventDragUtilities().getEventsViewNode(); if (coordinates.x < 0 || coordinates.x > container.clientWidth || coordinates.y < 0 || coordinates.y > container.clientHeight) coordinates = null; return coordinates; }, prepareWithEventType: function SEDPH_prepareWithEventType(eventType) { var methods = { "multiday": this.getEventMultiDayViewCoordinates, "multiday-allday": this.getEventMultiDayAllDayViewCoordinates, "monthly": this.getEventMonthlyViewCoordinates, "unknown": null }; var method = methods[eventType]; this.getEventViewCoordinates = method; }, getEventMultiDayViewCoordinates: function SEDPH_gEMultiDayViewC() { var coordinates = this.getEventMultiDayAllDayViewCoordinates(); if (coordinates) { var utilities = SOGoEventDragUtilities(); var quarterHeight = utilities.getQuarterHeight(); var container = utilities.getEventsViewNode(); var pxCoordinates = this.getContainerBasedCoordinates(); pxCoordinates.y += container.scrollTop; coordinates.y = Math.floor((pxCoordinates.y - SOGoEventDragHorizontalOffset) / quarterHeight); var maxY = SOGoEventDragDayLength - 1; if (coordinates.y < 0) coordinates.y = 0; else if (coordinates.y > maxY) coordinates.y = maxY; } return coordinates; }, getEventMultiDayAllDayViewCoordinates: function SEDPH_gEMultiDayADVC() { /* x = day; y = quarter */ var coordinates; var pxCoordinates = this.getContainerBasedCoordinates(); if (pxCoordinates) { coordinates = new SOGoCoordinates(); var utilities = SOGoEventDragUtilities(); var dayWidth = utilities.getDayWidth(); var daysOffset = utilities.getDaysOffset(); coordinates.x = Math.floor((pxCoordinates.x - daysOffset) / dayWidth); var maxX = utilities.getEventContainerNodes().length - 1; if (coordinates.x < 0) coordinates.x = 0; else if (coordinates.x > maxX) coordinates.x = maxX; coordinates.y = 0; } else { coordinates = null; } // logOnly("coordinates.x: " + coordinates.x); return coordinates; }, getEventMonthlyViewCoordinates: function SEDPH_gEMonthlyViewC() { /* x = day; y = quarter */ var coordinates; var pxCoordinates = this.getContainerBasedCoordinates(); if (pxCoordinates) { coordinates = new SOGoCoordinates(); var utilities = SOGoEventDragUtilities(); var daysOffset = utilities.getDaysOffset(); var daysTopOffset = daysOffset; /* change later */ var dayHeight = utilities.getDayHeight(); var daysY = Math.floor((pxCoordinates.y - daysTopOffset) / dayHeight); if (daysY < 0) daysY = 0; var dayWidth = utilities.getDayWidth(); coordinates.x = Math.floor((pxCoordinates.x - daysOffset) / dayWidth); if (coordinates.x < 0) coordinates.x = 0; else if (coordinates.x > 6) coordinates.x = 6; coordinates.x += 7 * daysY; coordinates.y = 0; } else { coordinates = null; } return coordinates; }, getDistance: function SEDPH_getDistance() { return this.currentCoordinates.getDistance(this.originalCoordinates); } }; function SOGoScrollController() { this.init(); } SOGoScrollController.prototype = { pointerHandler: null, scrollView: null, lastScroll: 0, scrollStep: 0, init: function SSC_init() { var utilities = SOGoEventDragUtilities(); this.scrollView = utilities.getEventsViewNode(); this.scrollStep = 6 * utilities.getQuarterHeight(); }, setPointerHandler: function SSC_setPointerHandler(pointerHandler) { this.pointerHandler = pointerHandler; }, updateFromPointerHandler: function SSC_updateFromPointerHandler() { var pointerCoordinates = this.pointerHandler.getContainerBasedCoordinates(); if (pointerCoordinates) { var now = new Date().getTime(); if (!this.lastScroll || now > this.lastScroll + 100) { this.lastScroll = now; var scrollY = pointerCoordinates.y - this.scrollStep; if (scrollY < 0) { var minY = -this.scrollView.scrollTop; if (scrollY < minY) scrollY = minY; this.scrollView.scrollTop += scrollY; } else { scrollY = pointerCoordinates.y + this.scrollStep; var delta = scrollY - this.scrollView.clientHeight; if (delta > 0) { this.scrollView.scrollTop += delta; } } } } } }; function SOGoEventDragController() { } SOGoEventDragController.prototype = { eventCells: null, eventType: null, eventIsInvitation: false, title: null, folderClass: null, draggingModeAreas: null, ghostController: null, hasSelected: false, dragHasStarted: false, dragMode: null, originalDayNumber: -1, pointerHandler: null, dropCallback: null, onDragStartBound: null, onDragStopBound: null, onDragModeBound: null, _determineDragMode: null, attachToEventCells: function SEDC_attachToEventCells(eventCells) { this.eventCells = eventCells; this.ghostController = new SOGoEventDragGhostController(); this._determineEventInvitation(eventCells[0]); this._determineEventType(eventCells[0]); this._prepareEventType(); this._determineTitleAndFolderClass(); this.ghostController.setTitle(this.title); this.ghostController.setLocation(this.location); this.ghostController.setFolderClass(this.folderClass); this.onDragStartBound = this.onDragStart.bindAsEventListener(this); for (var i = 0; i < eventCells.length; i++) { eventCells[i].observe("mousedown", this.onDragStartBound, false); if (eventCells[i].editable && !this.eventIsInvitation) { eventCells[i].addClassName("draggable"); } } if (this.eventType == "multiday") { var topDragGrip = $(document.createElement("div")); topDragGrip.addClassName("topDragGrip"); eventCells[0].appendChild(topDragGrip); var bottomDragGrip = $(document.createElement("div")); bottomDragGrip.addClassName("bottomDragGrip"); eventCells[eventCells.length-1].appendChild(bottomDragGrip); } else { var leftDragGrip = $(document.createElement("div")); leftDragGrip.addClassName("leftDragGrip"); eventCells[0].appendChild(leftDragGrip); var rightDragGrip = $(document.createElement("div")); rightDragGrip.addClassName("rightDragGrip"); eventCells[eventCells.length-1].appendChild(rightDragGrip); } }, attachToDayNode: function SEDC_attachToDayNode(dayNode) { this._determineEventType(dayNode); this._prepareEventType(); this.ghostController = new SOGoEventDragGhostController(); this.ghostController.setTitle(_("New Event")); this.onDragStartBound = this.onDragStart.bindAsEventListener(this); dayNode.observe("mousedown", this.onDragStartBound, false); }, onDragStart: function SEDC_onDragStart(event) { var target = getTarget(event); if (eventIsLeftClick(event) && (target.nodeType == 1)) { if ((!this.eventCells && (target.hasClassName("clickableHourCell") || target.hasClassName("day")) && (target.scrollHeight - target.clientHeight <= 1)) || (this.eventCells && this.eventCells[0].editable && !this.eventIsInvitation)) { var utilities = SOGoEventDragUtilities(); utilities.setEventType(this.eventType); this.pointerHandler = new SOGoEventDragPointerHandler(); this.pointerHandler.prepareWithEventType(this.eventType); this.pointerHandler.initFromEvent(event); var coordinates = new SOGoEventDragEventCoordinates(); coordinates.setEventType(this.eventType); if (this.eventCells) { coordinates.initFromEventCells(this.eventCells); } else { var eventViewCoordinates = this.pointerHandler.getEventViewCoordinates(); coordinates.dayNumber = eventViewCoordinates.x; coordinates.start = eventViewCoordinates.y; coordinates.duration = 1; } this.ghostController.initWithCoordinates(coordinates); if (!this.eventCells) { var folder = getSelectedFolder(); var folderID = folder.readAttribute("id").substr(1); this.ghostController.setFolderClass("calendarFolder" + folderID); } this.ghostController.setDragMode(this._determineDragMode()); this.ghostController.setPointerHandler(this.pointerHandler); if (this.eventType == "multiday") { this.scrollController = new SOGoScrollController(); this.scrollController.setPointerHandler(this.pointerHandler); } this.onDragStopBound = this.onDragStop.bindAsEventListener(this); if (Prototype.Browser.IE) Event.observe(document.body, "mouseup", this.onDragStopBound); else Event.observe(window, "mouseup", this.onDragStopBound); this.onDragModeBound = this.onDragMode.bindAsEventListener(this); Event.observe(document.body, "mousemove", this.onDragModeBound); Event.stop(event); } } return false; }, _determineEventInvitation: function SEDC__determineEventType(node) { var isInvitation = false; for (var i = 0; !isInvitation && i < userStates.length; i++) { var inside = node.select("DIV.eventInside")[0]; if (inside.hasClassName(userStates[i])) isInvitation = true; } this.eventIsInvitation = isInvitation; }, _determineEventType: function SEDC__determineEventType(node) { var type = "unknown"; var dayNode; var currentNode = node; while (!currentNode.hasClassName("day")) currentNode = currentNode.parentNode; dayNode = currentNode; // log("dayNode: " + dayNode.className); var secondParent = dayNode.parentNode; // log("secondParent: " + secondParent.className); if (secondParent.id == "monthDaysView") { type = "monthly"; } else { var thirdParent = secondParent.parentNode; // log("thirdParent: " + thirdParent.id); if (thirdParent.id == "calendarHeader") type = "multiday-allday"; else if (thirdParent.id == "daysView") type = "multiday"; } // log("type: " + type); this.eventType = type; }, _prepareEventType: function SEDC__prepareEventType() { var methods = { "multiday": this._determineDragModeMultiDay, "multiday-allday": this._determineDragModeMultiDayAllDay, "monthly": this._determineDragModeMonthly, "unknown": null }; this._determineDragMode = methods[this.eventType]; }, _determineDragModeMultiDay: function SEDC__determineDragModeMultiDay() { var dragMode; if (this.eventCells) { var coordinates = this.pointerHandler.currentCoordinates.clone(); var utilities = SOGoEventDragUtilities(); var scrollView = utilities.getEventsViewNode(); coordinates.y += scrollView.scrollTop; coordinates.y -= SOGoEventDragVerticalOffset; var firstCell = this.eventCells[0]; var handleCoords = firstCell.cumulativeOffset(); dragMode = "move-event"; if ((handleCoords[0] <= coordinates.x && coordinates.x <= handleCoords[0] + firstCell.clientWidth) && (handleCoords[1] <= coordinates.y && coordinates.y <= handleCoords[1] + SOGoEventDragHandleSize)) dragMode = "change-start"; else { var lastCell = this.eventCells[this.eventCells.length-1]; handleCoords = lastCell.cumulativeOffset(); handleCoords[1] += (lastCell.clientHeight - SOGoEventDragHandleSize - 1); if ((handleCoords[0] <= coordinates.x && coordinates.x <= handleCoords[0] + lastCell.clientWidth) && (handleCoords[1] <= coordinates.y && coordinates.y <= handleCoords[1] + SOGoEventDragHandleSize)) dragMode = "change-end"; } } else { dragMode = "change-end"; } return dragMode; }, _determineDragModeMultiDayAllDay: function SEDC__detDMMultiDayAllDay() { var dragMode; if (this.eventCells) { var coordinates = this.pointerHandler.currentCoordinates.clone(); coordinates.x -= SOGoEventDragHorizontalOffset; coordinates.y -= SOGoEventDragVerticalOffset; var firstCell = this.eventCells[0]; var handleCoords = firstCell.cumulativeOffset(); dragMode = "move-event"; if (handleCoords[0] <= coordinates.x && coordinates.x <= handleCoords[0] + SOGoEventDragHandleSize) dragMode = "change-start"; else { var lastCell = this.eventCells[this.eventCells.length-1]; handleCoords = lastCell.cumulativeOffset(); handleCoords[0] += lastCell.clientWidth; if (handleCoords[0] - SOGoEventDragHandleSize <= coordinates.x && coordinates.x <= handleCoords[0]) dragMode = "change-end"; } } else { dragMode = "change-end"; } return dragMode; }, _determineDragModeMonthly: function SEDC__determineDragModeMultiDay() { var dragMode; if (this.eventCells) { var coordinates = this.pointerHandler.currentCoordinates.clone(); coordinates.x -= SOGoEventDragHorizontalOffset; coordinates.y -= SOGoEventDragVerticalOffset; var firstCell = this.eventCells[0]; var handleCoords = firstCell.cumulativeOffset(); dragMode = "move-event"; var eventHeight = 16; /* arbitrary value */ if (handleCoords[1] <= coordinates.y && coordinates.y <= handleCoords[1] + eventHeight && handleCoords[0] <= coordinates.x && coordinates.x <= handleCoords[0] + SOGoEventDragHandleSize) dragMode = "change-start"; else { var lastCell = this.eventCells[this.eventCells.length-1]; handleCoords = lastCell.cumulativeOffset(); handleCoords[0] += lastCell.clientWidth; if (handleCoords[1] <= coordinates.y && coordinates.y <= handleCoords[1] + eventHeight && handleCoords[0] - SOGoEventDragHandleSize <= coordinates.x && coordinates.x <= handleCoords[0]) dragMode = "change-end"; } } else { dragMode = "change-end"; } return dragMode; }, _determineTitleAndFolderClass: function SEDC__dTAFC() { var title = ""; var folderClass = ""; var location = null; if (this.eventCells) { var firstCell = this.eventCells[0]; var divs = firstCell.childNodesWithTag("div"); for (var i = 0; i < divs.length; i++) { var div = divs[i]; if (div.hasClassName("eventInside")) { var titleDIV = this._determineTitleDIV(div); if (titleDIV) { title = this._determineTitleFromDIV(titleDIV); location = this._determineLocationFromDIV(titleDIV); } folderClass = this._determineFolderClassFromDIV(div); } } } this.title = title; this.location = location; this.folderClass = folderClass; }, _determineTitleDIV: function SEDC__determineTitleDIV(div) { var titleDIV = null; var insideDivs = div.childNodesWithTag("div"); for (var i = 0; titleDIV == null && i < insideDivs.length; i++) { var insideDiv = insideDivs[i]; if (insideDiv.hasClassName("text")) { titleDIV = insideDiv; } } return titleDIV; }, _determineTitleFromDIV: function SEDC__determineTitleFromDIV(titleDIV) { var title = ""; var currentNode = titleDIV.firstChild; while (currentNode) { if (currentNode.nodeType == Node.TEXT_NODE) { title += currentNode.nodeValue; } currentNode = currentNode.nextSibling; } return title.trim(); }, _determineLocationFromDIV: function SEDC__determineLocationFromDIV(titleDIV) { var location = ""; var spans = titleDIV.select("span.location"); if (spans && spans.length > 0) { var locationSPAN = spans[0]; var currentNode = locationSPAN.firstChild; while (currentNode) { if (currentNode.nodeType == Node.TEXT_NODE) { location += currentNode.nodeValue; } currentNode = currentNode.nextSibling; } } return location.trim(); }, _determineFolderClassFromDIV: function SEDC__detFolderClassFromDIV(div) { var folderClass = null; var classes = div.className.split(" "); for (var i = 0; folderClass == null && i < classes.length; i++) { var currentClass = classes[i]; if (currentClass.startsWith("calendarFolder")) { folderClass = currentClass; } } return folderClass; }, onDragStop: function SEDC_onDragStop(event) { if (Prototype.Browser.IE) Event.stopObserving(document.body, "mouseup", this.onDragStopBound); else Event.stopObserving(window, "mouseup", this.onDragStopBound); Event.stopObserving(document.body, "mousemove", this.onDragModeBound); this.onDragStopBound = null; this.onDragModeBound = null; var utilities = SOGoEventDragUtilities(); if (this.dragHasStarted) { this.ghostController.hideGhosts(); this.dragHasStarted = false; if (this.eventCells) { for (var i = 0; i < this.eventCells.length; i++) { var currentCell = this.eventCells[i]; currentCell.removeClassName("dragging"); } var delta = this.ghostController .currentCoordinates .getDelta(this.ghostController .originalCoordinates); this.updateDropCallback(this, this.eventCells, delta); } else { var eventContainerNodes = utilities.getEventContainerNodes(); var dayNode = eventContainerNodes[this.ghostController .currentCoordinates .dayNumber]; if (dayNode.hasClassName("events")) dayNode = dayNode.parentNode; this.createDropCallback(this, dayNode.readAttribute("day"), this.ghostController.currentCoordinates); } } utilities.reset(); Event.stop(event); }, _coordinateToTime: function SEDC_coordinateToTime(coordinate) { var hours = Math.floor(coordinate / 4); var minutes = (coordinate % 4) * 15; if (minutes < 10) minutes = "0" + minutes; var time = hours + ":" + minutes; return time; }, onDragMode: function SEDC_onDragMode(event) { this.pointerHandler.updateFromEvent(event); if (this.scrollController) this.scrollController.updateFromPointerHandler(); if (this.dragHasStarted) { this.ghostController.updateFromPointerHandler(); } else { var distance = this.pointerHandler.getDistance(); if (distance > 3) { $("eventDialog").hide(); this.dragHasStarted = true; if (this.eventCells) { for (var i = 0; i < this.eventCells.length; i++) { var currentCell = this.eventCells[i]; currentCell.addClassName("dragging"); } } this.ghostController.showGhosts(); this.ghostController.updateFromPointerHandler(); } } Event.stop(event); } };