Selaa lähdekoodia

EventPointing

Adam Shaw 8 vuotta sitten
vanhempi
sitoutus
49584dbc2e

+ 1 - 0
src.json

@@ -21,6 +21,7 @@
     "common/GlobalEmitter.js",
     "common/MouseFollower.js",
     "common/ChronoComponent.js",
+    "common/EventPointing.js",
     "common/CoordChronoComponentMixin.js",
     "common/CoordChronoComponentMixin.day-click.js",
     "common/CoordChronoComponentMixin.day-selection.js",

+ 5 - 1
src/common/CoordChronoComponentMixin.event-dragging.js

@@ -56,7 +56,11 @@ $.extend(CoordChronoComponentMixin, {
 					view.selectEventInstance(eventInstance);
 				}
 				isDragging = true;
-				_this.handleSegMouseout(seg, ev); // ensure a mouseout on the manipulated event has been reported
+
+				// ensure a mouseout on the manipulated event has been reported
+				// TODO: okay to call this?
+				_this.eventPointing.handleMouseout(seg, ev);
+
 				_this.segDragStart(seg, ev);
 				view.hideEventsWithId(eventDef.id); // hide all event segments. our mouseFollower will take over
 			},

+ 5 - 1
src/common/CoordChronoComponentMixin.event-resizing.js

@@ -43,7 +43,11 @@ $.extend(CoordChronoComponentMixin, {
 			},
 			dragStart: function(ev) {
 				isDragging = true;
-				_this.handleSegMouseout(seg, ev); // ensure a mouseout on the manipulated event has been reported
+
+				// ensure a mouseout on the manipulated event has been reported
+				// TODO: okay to call this?
+				_this.eventPointing.handleMouseout(seg, ev);
+
 				_this.segResizeStart(seg, ev);
 			},
 			hitOver: function(hit, isOrig, origHit) {

+ 15 - 76
src/common/CoordChronoComponentMixin.js

@@ -4,8 +4,6 @@ var CoordChronoComponentMixin = {
 	// self-config, overridable by subclasses
 	segSelector: '.fc-event-container > *', // what constitutes an event element?
 
-	mousedOverSeg: null, // the segment object the user's mouse is over. null if over nothing
-
 	// if defined, holds the unit identified (ex: "year" or "month") that determines the level of granularity
 	// of the date areas. if not defined, assumes to be day and time granularity.
 	// TODO: port isTimeScale into same system?
@@ -22,6 +20,9 @@ var CoordChronoComponentMixin = {
 
 	dragListeners: null,
 
+	eventPointingClass: EventPointing,
+	eventPointing: null,
+
 
 	initCoordChronoComponent: function() {
 		this.dragListeners = [];
@@ -78,9 +79,12 @@ var CoordChronoComponentMixin = {
 			new DateSelecting(this);
 		}
 
+		this.eventPointing = new this.eventPointingClass(this);
+
+		// for NON-EventPointing interactions.....
 		// attach event-element-related handlers. in Grid.events
 		// same garbage collection note as above.
-		this.bindSegHandlers();
+		this.bindSegHandlersToEl(this.el);
 	},
 
 
@@ -123,6 +127,7 @@ var CoordChronoComponentMixin = {
 	},
 
 
+	// TODO: move this into Day*Pointing* ?
 	bindDayHandler: function(name, handler) {
 		var _this = this;
 
@@ -143,34 +148,20 @@ var CoordChronoComponentMixin = {
 	},
 
 
-	// Attaches event-element-related handlers for *all* rendered event segments of the view.
-	bindSegHandlers: function() {
-		this.bindSegHandlersToEl(this.el);
-	},
-
-
 	// Attaches event-element-related handlers to an arbitrary container element. leverages bubbling.
 	bindSegHandlersToEl: function(el) {
 		this.bindSegHandlerToEl(el, 'touchstart', this.handleSegTouchStart);
 		this.bindSegHandlerToEl(el, 'mousedown', this.handleSegMousedown);
-
-		// nothing to do with "coord"component
-		this.bindSegHandlerToEl(el, 'mouseenter', this.handleSegMouseover);
-		this.bindSegHandlerToEl(el, 'mouseleave', this.handleSegMouseout);
-		this.bindSegHandlerToEl(el, 'click', this.handleSegClick);
 	},
 
 
-	// Executes a handler for any a user-interaction on a segment.
-	// Handler gets called with (seg, ev), and with the `this` context of the Grid
 	bindSegHandlerToEl: function(el, name, handler) {
 		var _this = this;
 
 		el.on(name, this.segSelector, function(ev) {
 			var seg = $(this).data('fc-seg'); // grab segment data. put there by View::renderEventsPayload
 
-			// only call the handlers if there is not a drag/resize in progress
-			if (seg && !_this.isDraggingSeg && !_this.isResizingSeg) {
+			if (seg && !_this.shouldIgnoreEventPointing()) {
 				return handler.call(_this, seg, ev); // context will be the Grid
 			}
 		});
@@ -193,6 +184,12 @@ var CoordChronoComponentMixin = {
 	},
 
 
+	shouldIgnoreEventPointing: function() {
+		// only call the handlers if there is not a drag/resize in progress
+		return this.isDraggingSeg || this.isResizingSeg;
+	},
+
+
 	registerDragListener: function(dragListener) {
 		this.dragListeners.push(dragListener);
 	},
@@ -202,64 +199,6 @@ var CoordChronoComponentMixin = {
 	------------------------------------------------------------------------------------------------------------------*/
 
 
-	handleSegClick: function(seg, ev) {
-		var view = this._getView();
-		var res = this.publiclyTrigger('eventClick', { // can return `false` to cancel
-			context: seg.el[0],
-			args: [ seg.footprint.getEventLegacy(), ev, view ]
-		});
-
-		if (res === false) {
-			ev.preventDefault();
-		}
-	},
-
-
-	// Updates internal state and triggers handlers for when an event element is moused over
-	handleSegMouseover: function(seg, ev) {
-		var view = this._getView();
-
-		if (
-			!GlobalEmitter.get().shouldIgnoreMouse() &&
-			!this.mousedOverSeg
-		) {
-			this.mousedOverSeg = seg;
-
-			if (view.isEventDefResizable(seg.footprint.eventDef)) {
-				seg.el.addClass('fc-allow-mouse-resize');
-			}
-
-			this.publiclyTrigger('eventMouseover', {
-				context: seg.el[0],
-				args: [ seg.footprint.getEventLegacy(), ev, view ]
-			});
-		}
-	},
-
-
-	// Updates internal state and triggers handlers for when an event element is moused out.
-	// Can be given no arguments, in which case it will mouseout the segment that was previously moused over.
-	handleSegMouseout: function(seg, ev) {
-		var view = this._getView();
-
-		ev = ev || {}; // if given no args, make a mock mouse event
-
-		if (this.mousedOverSeg) {
-			seg = seg || this.mousedOverSeg; // if given no args, use the currently moused-over segment
-			this.mousedOverSeg = null;
-
-			if (view.isEventDefResizable(seg.footprint.eventDef)) {
-				seg.el.removeClass('fc-allow-mouse-resize');
-			}
-
-			this.publiclyTrigger('eventMouseout', {
-				context: seg.el[0],
-				args: [ seg.footprint.getEventLegacy(), ev, view ]
-			});
-		}
-	},
-
-
 	handleSegMousedown: function(seg, ev) {
 		var view = this._getView();
 		var isResizing = this.startSegResize(seg, ev, { distance: 5 });

+ 2 - 1
src/common/DayGrid.limit.js

@@ -290,7 +290,8 @@ DayGrid.mixin({
 
 		// the popover doesn't live within the grid's container element, and thus won't get the event
 		// delegated-handlers for free. attach event-related handlers to the popover.
-		this.bindSegHandlersToEl(this.segPopover.el);
+		this.bindSegHandlersToEl(this.segPopover.el); // TODO: eventually remove!
+		this.eventPointing.bindToEl(this.segPopover.el);
 	},
 
 

+ 92 - 0
src/common/EventPointing.js

@@ -0,0 +1,92 @@
+
+var EventPointing = Class.extend({
+
+	view: null,
+	component: null, // CoordComponent
+	mousedOverSeg: null, // the segment object the user's mouse is over. null if over nothing
+
+
+	/*
+	component must implement:
+		- publiclyTrigger
+	*/
+	constructor: function(component) {
+		this.view = component.view;
+		this.component = component;
+
+		this.bind();
+	},
+
+
+	bind: function() {
+		this.bindToEl(this.component.el);
+	},
+
+
+	bindToEl: function(el) {
+		var component = this.component;
+
+		component.bindSegHandlerToEl(el, 'click', this.handleClick.bind(this));
+		component.bindSegHandlerToEl(el, 'mouseenter', this.handleMouseover.bind(this));
+		component.bindSegHandlerToEl(el, 'mouseleave', this.handleMouseout.bind(this));
+	},
+
+
+	handleClick: function(seg, ev) {
+		var res = this.component.publiclyTrigger('eventClick', { // can return `false` to cancel
+			context: seg.el[0],
+			args: [ seg.footprint.getEventLegacy(), ev, this.view ]
+		});
+
+		if (res === false) {
+			ev.preventDefault();
+		}
+	},
+
+
+	// Updates internal state and triggers handlers for when an event element is moused over
+	handleMouseover: function(seg, ev) {
+		if (
+			!GlobalEmitter.get().shouldIgnoreMouse() &&
+			!this.mousedOverSeg
+		) {
+			this.mousedOverSeg = seg;
+
+			// TODO: move to EventSelecting's responsibility
+			if (this.view.isEventDefResizable(seg.footprint.eventDef)) {
+				seg.el.addClass('fc-allow-mouse-resize');
+			}
+
+			this.component.publiclyTrigger('eventMouseover', {
+				context: seg.el[0],
+				args: [ seg.footprint.getEventLegacy(), ev, this.view ]
+			});
+		}
+	},
+
+
+	// Updates internal state and triggers handlers for when an event element is moused out.
+	// Can be given no arguments, in which case it will mouseout the segment that was previously moused over.
+	handleMouseout: function(seg, ev) {
+		if (this.mousedOverSeg) {
+
+			seg = seg || this.mousedOverSeg; // if given no args, use the currently moused-over segment
+			this.mousedOverSeg = null;
+
+			// TODO: move to EventSelecting's responsibility
+			if (this.view.isEventDefResizable(seg.footprint.eventDef)) {
+				seg.el.removeClass('fc-allow-mouse-resize');
+			}
+
+			this.component.publiclyTrigger('eventMouseout', {
+				context: seg.el[0],
+				args: [
+					seg.footprint.getEventLegacy(),
+					ev || {}, // if given no arg, make a mock mouse event
+					this.view
+				]
+			});
+		}
+	}
+
+});

+ 4 - 2
src/common/SegChronoComponentMixin.js

@@ -62,8 +62,10 @@ var SegChronoComponentMixin = {
 
 	// Unrenders all events currently rendered on the grid
 	unrenderEvents: function() {
-		this.handleSegMouseout(); // trigger an eventMouseout if user's mouse is over an event
-		// ^ part of CoordChronoComponent :(
+
+		// ensure a mouseout on the manipulated event has been reported
+		// TODO: okay to call this?
+		this.eventPointing.handleMouseout();
 
 		this.unrenderFgSegs();
 		this.unrenderBgSegs();

+ 15 - 11
src/list/ListView.js

@@ -210,22 +210,26 @@ var ListView = View.extend(CoordChronoComponentMixin, SegChronoComponentMixin, {
 	}),
 
 
-	// for events with a url, the whole <tr> should be clickable,
-	// but it's impossible to wrap with an <a> tag. simulate this.
-	handleSegClick: function(seg, ev) {
-		var url;
+	eventPointingClass: EventPointing.extend({
 
-		CoordChronoComponentMixin.handleSegClick.apply(this, arguments); // super. might prevent the default action
+		// for events with a url, the whole <tr> should be clickable,
+		// but it's impossible to wrap with an <a> tag. simulate this.
+		handleClick: function(seg, ev) {
+			var url;
 
-		// not clicking on or within an <a> with an href
-		if (!$(ev.target).closest('a[href]').length) {
-			url = seg.footprint.eventDef.url;
+			EventPointing.prototype.handleClick.apply(this, arguments); // super. might prevent the default action
 
-			if (url && !ev.isDefaultPrevented()) { // jsEvent not cancelled in handler
-				window.location.href = url; // simulate link click
+			// not clicking on or within an <a> with an href
+			if (!$(ev.target).closest('a[href]').length) {
+				url = seg.footprint.eventDef.url;
+
+				if (url && !ev.isDefaultPrevented()) { // jsEvent not cancelled in handler
+					window.location.href = url; // simulate link click
+				}
 			}
 		}
-	},
+
+	}),
 
 
 	// returns list of foreground segs that were actually rendered