Sfoglia il codice sorgente

event resizing, more modular, beginnings of eventResizableFromStart

Adam Shaw 11 anni fa
parent
commit
921d4ead6b
5 ha cambiato i file con 142 aggiunte e 47 eliminazioni
  1. 11 4
      src/common/DayGrid.events.js
  2. 104 36
      src/common/Grid.events.js
  3. 11 4
      src/common/TimeGrid.events.js
  4. 15 3
      src/common/View.js
  5. 1 0
      src/defaults.js

+ 11 - 4
src/common/DayGrid.events.js

@@ -93,8 +93,11 @@ DayGrid.mixin({
 		var view = this.view;
 		var event = seg.event;
 		var isDraggable = view.isEventDraggable(event);
-		var isResizable = !disableResizing && event.allDay && seg.isEnd && view.isEventResizable(event);
-		var classes = this.getSegClasses(seg, isDraggable, isResizable);
+		var isResizableFromStart = !disableResizing && event.allDay &&
+			seg.isStart && view.isEventResizableFromStart(event);
+		var isResizableFromEnd = !disableResizing && event.allDay &&
+			seg.isEnd && view.isEventResizableFromEnd(event);
+		var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
 		var skinCss = this.getEventSkinCss(event);
 		var timeHtml = '';
 		var timeText;
@@ -131,8 +134,12 @@ DayGrid.mixin({
 						timeHtml + ' ' + titleHtml   //
 						) +
 				'</div>' +
-				(isResizable ?
-					'<div class="fc-resizer"/>' :
+				(isResizableFromStart ?
+					'<div class="fc-resizer fc-start-resizer" />' :
+					''
+					) +
+				(isResizableFromEnd ?
+					'<div class="fc-resizer fc-end-resizer" />' :
 					''
 					) +
 			'</a>';

+ 104 - 36
src/common/Grid.events.js

@@ -200,7 +200,7 @@ Grid.mixin({
 				},
 				mousedown: function(seg, ev) {
 					if ($(ev.target).is('.fc-resizer') && view.isEventResizable(seg.event)) {
-						_this.segResizeMousedown(seg, ev);
+						_this.segResizeMousedown(seg, ev, $(ev.target).is('.fc-start-resizer'));
 					}
 					else if (view.isEventDraggable(seg.event)) {
 						_this.segDragMousedown(seg, ev);
@@ -516,22 +516,15 @@ Grid.mixin({
 
 	// Called when the user does a mousedown on an event's resizer, which might lead to resizing.
 	// Generic enough to work with any type of Grid.
-	segResizeMousedown: function(seg, ev) {
+	segResizeMousedown: function(seg, ev, isStart) {
 		var _this = this;
 		var view = this.view;
 		var calendar = view.calendar;
 		var el = seg.el;
 		var event = seg.event;
-		var start = event.start;
-		var oldEnd = calendar.getEventEnd(event);
-		var newEnd; // falsy if invalid resize
+		var eventEnd = calendar.getEventEnd(event);
 		var dragListener;
-
-		function destroy() { // resets the rendering to show the original event
-			_this.destroyEventResize();
-			view.showEvent(event);
-			enableCursor();
-		}
+		var resizeLocation; // falsy if invalid resize
 
 		// Tracks mouse movement over the *grid's* coordinate map
 		dragListener = new CellDragListener(this.coordMap, {
@@ -540,41 +533,42 @@ Grid.mixin({
 			subjectEl: el,
 			dragStart: function(ev) {
 				_this.triggerSegMouseout(seg, ev); // ensure a mouseout on the manipulated event has been reported
-				_this.isResizingSeg = true;
-				view.trigger('eventResizeStart', el[0], event, ev, {}); // last argument is jqui dummy
+				_this.segResizeStart(seg, ev);
 			},
-			cellOver: function(cell) {
-				newEnd = cell.end;
-
-				if (!newEnd.isAfter(start)) { // was end moved before start?
-					newEnd = start.clone().add( // make the event span a single slot
-						diffDayTime(cell.end, cell.start) // assumes all slot durations are the same
-					);
+			cellOver: function(cell, isOrig, origCell) {
+				resizeLocation = isStart ?
+					_this.computeEventStartResize(origCell, cell, event) :
+					_this.computeEventEndResize(origCell, cell, event);
+
+				if (resizeLocation) {
+					if (!calendar.isEventRangeAllowed(resizeLocation, event)) {
+						disableCursor();
+						resizeLocation = null;
+					}
+					// no change? (TODO: how does this work with timezones?)
+					else if (resizeLocation.start.isSame(event.start) && resizeLocation.end.isSame(eventEnd)) {
+						resizeLocation = null;
+					}
 				}
 
-				if (newEnd.isSame(oldEnd)) {
-					newEnd = null;
-				}
-				else if (!calendar.isEventRangeAllowed({ start: start, end: newEnd }, event)) {
-					newEnd = null;
-					disableCursor();
-				}
-				else {
-					_this.renderEventResize({ start: start, end: newEnd }, seg);
+				if (resizeLocation) {
 					view.hideEvent(event);
+					_this.renderEventResize(resizeLocation, seg);
 				}
 			},
 			cellOut: function() { // called before mouse moves to a different cell OR moved out of all cells
-				newEnd = null;
-				destroy();
+				resizeLocation = null;
+			},
+			cellDone: function() { // resets the rendering to show the original event
+				_this.destroyEventResize();
+				view.showEvent(event);
+				enableCursor();
 			},
 			dragStop: function(ev) {
-				_this.isResizingSeg = false;
-				destroy();
-				view.trigger('eventResizeStop', el[0], event, ev, {}); // last argument is jqui dummy
+				_this.segResizeStop(seg, ev);
 
-				if (newEnd) { // valid date to resize to?
-					view.reportEventResize(event, newEnd, this.largeUnit, el, ev);
+				if (resizeLocation) { // valid date to resize to?
+					view.reportEventResize(event, resizeLocation, this.largeUnit, el, ev);
 				}
 			}
 		});
@@ -583,6 +577,80 @@ Grid.mixin({
 	},
 
 
+	// Called before event segment resizing starts
+	segResizeStart: function(seg, ev) {
+		this.isResizingSeg = true;
+		this.view.trigger('eventResizeStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
+	},
+
+
+	// Called after event segment resizing stops
+	segResizeStop: function(seg, ev) {
+		this.isResizingSeg = false;
+		this.view.trigger('eventResizeStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
+	},
+
+
+	// Returns new date-information for an event segment being resized from its start
+	computeEventStartResize: function(startCell, endCell, event) {
+		return this.computeEventResize('start', startCell, endCell, event);
+	},
+
+
+	// Returns new date-information for an event segment being resized from its end
+	computeEventEndResize: function(startCell, endCell, event) {
+		return this.computeEventResize('end', startCell, endCell, event);
+	},
+
+
+	// Returns new date-information for an event segment being resized from its start OR end
+	// `type` is either 'start' or 'end'
+	computeEventResize: function(type, startCell, endCell, event) {
+		var calendar = this.view.calendar;
+		var delta = this.diffDates(endCell[type], startCell[type]);
+		var range;
+		var defaultDuration;
+
+		// build original values to work from, guaranteeing a start and end
+		range = {
+			start: event.start.clone(),
+			end: calendar.getEventEnd(event),
+			allDay: event.allDay
+		};
+
+		// if an all-day event was in a timed area and was resized to a time, adjust start/end to have times
+		if (range.allDay && durationHasTime(delta)) {
+			range.allDay = false;
+			calendar.normalizeEventRangeTimes(range);
+		}
+
+		range[type].add(delta); // apply delta to start or end
+
+		// if the event was compressed too small, find a new reasonable duration for it
+		if (!range.start.isBefore(range.end)) {
+
+			defaultDuration = event.allDay ?
+				calendar.defaultAllDayEventDuration :
+				calendar.defaultTimedEventDuration;
+
+			// between the cell's duration and the event's default duration, use the smaller of the two.
+			// example: if year-length slots, and compressed to one slot, we don't want the event to be a year long
+			if (this.cellDuration && this.cellDuration < defaultDuration) {
+				defaultDuration = this.cellDuration;
+			}
+
+			if (type == 'start') { // resizing the start?
+				range.start = range.end.clone().subtract(defaultDuration);
+			}
+			else { // resizing the end?
+				range.end = range.start.clone().add(defaultDuration);
+			}
+		}
+
+		return range;
+	},
+
+
 	// Renders a visual indication of an event being resized.
 	// `range` has the updated dates of the event. `seg` is the original segment object involved in the drag.
 	renderEventResize: function(range, seg) {

+ 11 - 4
src/common/TimeGrid.events.js

@@ -104,8 +104,9 @@ TimeGrid.mixin({
 		var view = this.view;
 		var event = seg.event;
 		var isDraggable = view.isEventDraggable(event);
-		var isResizable = !disableResizing && seg.isEnd && view.isEventResizable(event);
-		var classes = this.getSegClasses(seg, isDraggable, isResizable);
+		var isResizableFromStart = !disableResizing && seg.isStart && view.isEventResizableFromStart(event);
+		var isResizableFromEnd = !disableResizing && seg.isEnd && view.isEventResizableFromEnd(event);
+		var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
 		var skinCss = this.getEventSkinCss(event);
 		var timeText;
 		var fullTimeText; // more verbose time text. for the print stylesheet
@@ -157,8 +158,14 @@ TimeGrid.mixin({
 						) +
 				'</div>' +
 				'<div class="fc-bg"/>' +
-				(isResizable ?
-					'<div class="fc-resizer"/>' :
+				/* TODO: write CSS for this
+				(isResizableFromStart ?
+					'<div class="fc-resizer fc-start-resizer" />' :
+					''
+					) +
+				*/
+				(isResizableFromEnd ?
+					'<div class="fc-resizer fc-end-resizer" />' :
 					''
 					) +
 			'</a>';

+ 15 - 3
src/common/View.js

@@ -694,7 +694,19 @@ var View = fc.View = Class.extend({
 	------------------------------------------------------------------------------------------------------------------*/
 
 
-	// Computes if the given event is allowed to be resize by the user
+	// Computes if the given event is allowed to be resized from its starting edge
+	isEventResizableFromStart: function(event) {
+		return this.opt('eventResizableFromStart') && this.isEventResizable(event);
+	},
+
+
+	// Computes if the given event is allowed to be resized from its ending edge
+	isEventResizableFromEnd: function(event) {
+		return this.isEventResizable(event);
+	},
+
+
+	// Computes if the given event is allowed to be resized by the user at all
 	isEventResizable: function(event) {
 		var source = event.source || {};
 
@@ -710,9 +722,9 @@ var View = fc.View = Class.extend({
 
 
 	// Must be called when an event in the view has been resized to a new length
-	reportEventResize: function(event, newEnd, largeUnit, el, ev) {
+	reportEventResize: function(event, resizeLocation, largeUnit, el, ev) {
 		var calendar = this.calendar;
-		var mutateResult = calendar.mutateEvent(event, { end: newEnd }, largeUnit);
+		var mutateResult = calendar.mutateEvent(event, resizeLocation, largeUnit);
 		var undoFunc = function() {
 			mutateResult.undo();
 			calendar.reportEventChange();

+ 1 - 0
src/defaults.js

@@ -64,6 +64,7 @@ Calendar.defaults = {
 		nextYear: 'seek-next'
 	},
 
+	//eventResizableFromStart: false,
 	dragOpacity: .75,
 	dragRevertDuration: 500,
 	dragScroll: true,