summaryrefslogtreecommitdiffstats
path: root/comm/calendar/base/content/widgets/calendar-dnd-widgets.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/calendar/base/content/widgets/calendar-dnd-widgets.js192
1 files changed, 192 insertions, 0 deletions
diff --git a/comm/calendar/base/content/widgets/calendar-dnd-widgets.js b/comm/calendar/base/content/widgets/calendar-dnd-widgets.js
new file mode 100644
index 0000000000..f0d75745b6
--- /dev/null
+++ b/comm/calendar/base/content/widgets/calendar-dnd-widgets.js
@@ -0,0 +1,192 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* globals currentView MozElements MozXULElement */
+
+"use strict";
+
+// Wrap in a block to prevent leaking to window scope.
+{
+ var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+
+ /**
+ * An abstract class to handle drag on drop for calendar.
+ *
+ * @abstract
+ */
+ class CalendarDnDContainer extends MozXULElement {
+ constructor() {
+ super();
+ this.addEventListener("dragstart", this.onDragStart);
+ this.addEventListener("dragover", this.onDragOver);
+ this.addEventListener("dragenter", this.onDragEnter);
+ this.addEventListener("drop", this.onDrop);
+ this.addEventListener("dragend", this.onDragEnd);
+ this.mCalendarView = null;
+ }
+
+ connectedCallback() {
+ if (this.delayConnectedCallback()) {
+ return;
+ }
+ this.hasConnected = true;
+ }
+
+ /**
+ * The ViewController that supports the interface 'calICalendarView'.
+ *
+ * @returns {calICalendarView}
+ */
+ get calendarView() {
+ return this.mCalendarView;
+ }
+
+ set calendarView(val) {
+ this.mCalendarView = val;
+ }
+
+ /**
+ * Method to add individual code e.g to set up the new item during 'ondrop'.
+ */
+ onDropItem(aItem) {
+ // method that may be overridden by derived bindings...
+ }
+
+ /**
+ * Adds the dropshadows to the children of the binding.
+ * The dropshadows are added at the first position of the children.
+ */
+ addDropShadows() {
+ let offset = this.calendarView.mShadowOffset;
+ let shadowStartDate = this.date.clone();
+ shadowStartDate.addDuration(offset);
+ this.calendarView.mDropShadows = [];
+ for (let i = 0; i < this.calendarView.mDropShadowsLength; i++) {
+ let box = this.calendarView.findDayBoxForDate(shadowStartDate);
+ if (box) {
+ box.setDropShadow(true);
+ this.calendarView.mDropShadows.push(box);
+ }
+ shadowStartDate.day += 1;
+ }
+ }
+
+ /**
+ * Removes all dropShadows from the binding.
+ * Dropshadows are recognized as such by carrying an attribute "dropshadow".
+ */
+ removeDropShadows() {
+ // method that may be overwritten by derived bindings...
+ if (this.calendarView.mDropShadows) {
+ for (let box of this.calendarView.mDropShadows) {
+ box.setDropShadow(false);
+ }
+ }
+ this.calendarView.mDropShadows = null;
+ }
+
+ /**
+ * By setting the attribute "dropbox" to "true" or "false" the
+ * dropshadows are added or removed.
+ */
+ setAttribute(aAttr, aVal) {
+ if (aAttr == "dropbox") {
+ let session = cal.dragService.getCurrentSession();
+ if (session) {
+ session.canDrop = true;
+ // no shadows when dragging in the initial position
+ if (aVal == "true" && !this.contains(session.sourceNode)) {
+ this.addDropShadows();
+ } else {
+ this.removeDropShadows();
+ }
+ }
+ }
+ return XULElement.prototype.setAttribute.call(this, aAttr, aVal);
+ }
+
+ onDragStart(event) {
+ let draggedDOMNode = document.monthDragEvent || event.target;
+ if (!draggedDOMNode?.occurrence || !this.contains(draggedDOMNode)) {
+ return;
+ }
+ let item = draggedDOMNode.occurrence.clone();
+ let beginMoveDate = draggedDOMNode.mParentBox.date;
+ let itemStartDate = (item.startDate || item.entryDate || item.dueDate).getInTimezone(
+ this.calendarView.mTimezone
+ );
+ let itemEndDate = (item.endDate || item.dueDate || item.entryDate).getInTimezone(
+ this.calendarView.mTimezone
+ );
+ let oneMoreDay = itemEndDate.hour > 0 || itemEndDate.minute > 0;
+ itemStartDate.isDate = true;
+ itemEndDate.isDate = true;
+ let offsetDuration = itemStartDate.subtractDate(beginMoveDate);
+ let lenDuration = itemEndDate.subtractDate(itemStartDate);
+ let len = lenDuration.weeks * 7 + lenDuration.days;
+
+ this.calendarView.mShadowOffset = offsetDuration;
+ this.calendarView.mDropShadowsLength = oneMoreDay ? len + 1 : len;
+ }
+
+ onDragOver(event) {
+ let session = cal.dragService.getCurrentSession();
+ if (!session?.sourceNode?.sourceObject) {
+ // No source item? Then this is not for us.
+ return;
+ }
+
+ // We handled the event.
+ event.preventDefault();
+ }
+
+ onDragEnter(event) {
+ let session = cal.dragService.getCurrentSession();
+ if (!session?.sourceNode?.sourceObject) {
+ // No source item? Then this is not for us.
+ return;
+ }
+
+ // We can drop now, tell the drag service.
+ event.preventDefault();
+
+ if (!this.hasAttribute("dropbox") || this.getAttribute("dropbox") == "false") {
+ // As it turned out it was not possible to remove the remaining dropshadows
+ // at the "dragleave" event, majorly because it was not reliably
+ // fired.
+ // So we have to remove them at the currentView(). The restriction of course is
+ // that these containers so far may not be used for drag and drop from/to e.g.
+ // the today-pane.
+ currentView().removeDropShadows();
+ }
+ this.setAttribute("dropbox", "true");
+ }
+
+ onDrop(event) {
+ let session = cal.dragService.getCurrentSession();
+ let item = session?.sourceNode?.sourceObject;
+ if (!item) {
+ // No source node? Not our drag.
+ return;
+ }
+ this.setAttribute("dropbox", "false");
+ let newItem = this.onDropItem(item).clone();
+ let newStart = newItem.startDate || newItem.entryDate || newItem.dueDate;
+ let newEnd = newItem.endDate || newItem.dueDate || newItem.entryDate;
+ let offset = this.calendarView.mShadowOffset;
+ newStart.addDuration(offset);
+ newEnd.addDuration(offset);
+ this.calendarView.controller.modifyOccurrence(item, newStart, newEnd);
+
+ // We handled the event.
+ event.stopPropagation();
+ }
+
+ onDragEnd(event) {
+ currentView().removeDropShadows();
+ }
+ }
+
+ MozElements.CalendarDnDContainer = CalendarDnDContainer;
+}