Jelajahi Sumber

specifying event data (including duration) for external drag-n-drop

Adam Shaw 11 tahun lalu
induk
melakukan
d414b92c43
2 mengubah file dengan 92 tambahan dan 8 penghapusan
  1. 5 1
      src/EventManager.js
  2. 87 7
      src/common/View.js

+ 5 - 1
src/EventManager.js

@@ -364,7 +364,7 @@ function EventManager(options) { // assumed to be a calendar
 	}
 
 	
-	
+	// returns the expanded events that were created
 	function renderEvent(eventInput, stick) {
 		var abstractEvent = buildEventFromInput(eventInput);
 		var events;
@@ -386,7 +386,11 @@ function EventManager(options) { // assumed to be a calendar
 			}
 
 			reportEvents(cache);
+
+			return events;
 		}
+
+		return [];
 	}
 	
 	

+ 87 - 7
src/common/View.js

@@ -257,9 +257,13 @@ View.prototype = {
 	// Gets called when jqui's 'dragstart' is fired.
 	documentDragStart: function(ev, ui) {
 		var _this = this;
-		var dropDate = null;
+		var calendar = this.calendar;
+		var eventStart = null;
+		var eventEnd = null;
+		var visibleEnd = null; // will be calculated event when no eventEnd
 		var el;
 		var accept;
+		var meta;
 		var dragListener;
 
 		if (this.opt('droppable')) { // only listen if this setting is on
@@ -270,23 +274,45 @@ View.prototype = {
 			accept = this.opt('dropAccept');
 			if ($.isFunction(accept) ? accept.call(el[0], el) : el.is(accept)) {
 
+				meta = getDraggedElMeta(el); // data for possibly creating an event
+
 				// listener that tracks mouse movement over date-associated pixel regions
 				dragListener = new DragListener(this.coordMap, {
-					cellOver: function(cell, date) {
-						dropDate = date;
-						_this.renderDrag(date);
+					cellOver: function(cell, cellDate) {
+						eventStart = cellDate;
+						eventEnd = meta.duration ? eventStart.clone().add(meta.duration) : null;
+						visibleEnd = eventEnd || calendar.getDefaultEventEnd(!eventStart.hasTime(), eventStart);
+						_this.renderDrag(eventStart, visibleEnd);
 					},
 					cellOut: function() {
-						dropDate = null;
+						eventStart = eventEnd = visibleEnd = null;
 						_this.destroyDrag();
 					}
 				});
 
 				// gets called, only once, when jqui drag is finished
 				$(document).one('dragstop', function(ev, ui) {
+					var eventProps = meta.eventProps;
+					var renderedEvents;
+
 					_this.destroyDrag();
-					if (dropDate) {
-						_this.trigger('drop', el[0], dropDate, ev, ui);
+
+					if (eventStart) { // element was dropped on a valid date/time cell
+
+						// if dropped on an all-day cell, and element's metadata specified a time, set it
+						if (meta.startTime && !eventStart.hasTime()) {
+							eventStart.timeDuration(meta.startTime);
+						}
+
+						// trigger 'drop' regardless of whether element represents an event
+						_this.trigger('drop', el[0], eventStart, ev, ui);
+
+						// create an event from the given properties and the newly calculated dates
+						if (eventProps) {
+							$.extend(eventProps, { start: eventStart, end: eventEnd });
+							renderedEvents = calendar.renderEvent(eventProps, meta.stick);
+							_this.trigger('eventReceive', null, renderedEvents[0]); // signal an external event landed
+						}
 					}
 				});
 
@@ -821,3 +847,57 @@ function View(calendar) {
 	}
 
 }
+
+
+/* Utils
+----------------------------------------------------------------------------------------------------------------------*/
+
+// Require all HTML5 data-* attributes used by FullCalendar to have this prefix.
+// A value of '' will query attributes like data-event. A value of 'fc' will query attributes like data-fc-event.
+fc.dataAttrPrefix = '';
+
+// Given a jQuery element that might represent a dragged FullCalendar event, returns an intermediate data structure
+// to be used for Event Object creation.
+// A defined `.eventProps`, even when empty, indicates that an event should be created.
+function getDraggedElMeta(el) {
+	var prefix = fc.dataAttrPrefix;
+	var eventProps; // properties for creating the event, not related to date/time
+	var startTime; // a Duration
+	var duration;
+	var stick;
+
+	if (prefix) { prefix += '-'; }
+	eventProps = el.data(prefix + 'event') || null;
+
+	if (eventProps) {
+		if (typeof eventProps === 'object') {
+			eventProps = $.extend({}, eventProps); // make a copy
+		}
+		else { // something like 1 or true. still signal event creation
+			eventProps = {};
+		}
+
+		// pluck special-cased date/time properties
+		startTime = eventProps.start;
+		if (startTime == null) { startTime = eventProps.time; } // accept 'time' as well
+		duration = eventProps.duration;
+		stick = eventProps.stick;
+		delete eventProps.start;
+		delete eventProps.time;
+		delete eventProps.duration;
+		delete eventProps.stick;
+	}
+
+	// fallback to standalone attribute values for each of the date/time properties
+	if (startTime == null) { startTime = el.data(prefix + 'start'); }
+	if (startTime == null) { startTime = el.data(prefix + 'time'); } // accept 'time' as well
+	if (duration == null) { duration = el.data(prefix + 'duration'); }
+	if (stick == null) { stick = el.data(prefix + 'stick'); }
+
+	// massage into correct data types
+	startTime = startTime != null ? moment.duration(startTime) : null;
+	duration = duration != null ? moment.duration(duration) : null;
+	stick = Boolean(stick);
+
+	return { eventProps: eventProps, startTime: startTime, duration: duration, stick: stick };
+}