Răsfoiți Sursa

revamp EventDef parsing

Adam Shaw 8 ani în urmă
părinte
comite
c451ab15e0

+ 137 - 47
src/models/event/EventDef.js

@@ -26,6 +26,7 @@ var EventDef = Class.extend({
 
 
 	constructor: function(source) {
+		this.uid = String(EventDef.uuid++);
 		this.source = source;
 		this.className = [];
 		this.miscProps = {};
@@ -49,7 +50,7 @@ var EventDef = Class.extend({
 		copy.rawId = this.rawId;
 		copy.uid = this.uid; // not really unique anymore :(
 
-		EventDef.copyVerbatimProps(this, copy);
+		EventDef.copyVerbatimStandardProps(this, copy);
 
 		copy.className = this.className; // should clone?
 		copy.miscProps = $.extend({}, this.miscProps);
@@ -117,34 +118,109 @@ var EventDef = Class.extend({
 			obj.id = this.rawId;
 		}
 
-		EventDef.copyVerbatimProps(this, obj);
+		EventDef.copyVerbatimStandardProps(this, obj);
 
 		return obj;
+	},
+
+
+	// Standard Prop Parsing System, for the INSTANCE
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	handledStandardPropMap: {},
+	verbatimStandardPropMap: {},
+	standardPropHandlers: [],
+
+
+	isStandardProp: function(propName) {
+		return this.verbatimStandardPropMap[propName] ||
+			this.handledStandardPropMap[propName];
+	},
+
+
+	applyStandardProps: function(rawProps) {
+		var handlers = this.standardPropHandlers;
+		var rawHandled = {}; // to be handled
+		var propName;
+		var i;
+
+		for (propName in this.handledStandardPropMap) {
+			if (rawProps[propName] != null) {
+				rawHandled[propName] = rawProps[propName];
+			}
+		}
+
+		for (i = 0; i < handlers.length; i++) {
+			if (handlers[i].call(this, rawProps) === false) {
+				return false;
+			}
+		}
+
+		for (propName in this.verbatimStandardPropMap) {
+			if (rawProps[propName] != null) {
+				this[propName] = rawProps[propName];
+			}
+		}
 	}
 
 });
 
 
+// ID
+// ---------------------------------------------------------------------------------------------------------------------
+
+
 EventDef.uuid = 0;
 
 
-// Verbatim Properties
+EventDef.normalizeId = function(id) {
+	return String(id);
+};
+
+
+EventDef.generateId = function() {
+	return '_fc' + (EventDef.uuid++);
+};
+
+
+// Standard Prop Parsing System, for class self-definition
 // ---------------------------------------------------------------------------------------------------------------------
 
 
-EventDef.VERBATIM_PROPS = [
-	'title', 'url', 'rendering', 'constraint', 'overlap',
-	'editable', 'startEditable', 'durationEditable', 'resourceEditable',
-	'color', 'backgroundColor', 'borderColor', 'textColor'
-];
+EventDef.defineStandardPropHandler = function(propNames, handler) {
+	var proto = this.prototype;
+	var map = proto.handledStandardPropMap = $.extend({}, proto.handledStandardPropMap);
+	var i;
+
+	for (i = 0; i < propNames.length; i++) {
+		map[propNames[i]] = true;
+	}
+
+	proto.standardPropHandlers = proto.standardPropHandlers.concat(handler);
+};
+
+
+EventDef.defineVerbatimStandardProps = function(propNames) {
+	var proto = this.prototype;
+	var map = proto.verbatimStandardPropMap = $.extend({}, proto.verbatimStandardPropMap);
+	var i;
+
+	for (i = 0; i < propNames.length; i++) {
+		map[propNames[i]] = true;
+	}
+};
 
 
-EventDef.copyVerbatimProps = function(src, dest) {
-	this.VERBATIM_PROPS.forEach(function(propName) {
+EventDef.copyVerbatimStandardProps = function(src, dest) {
+	var map = this.prototype.verbatimStandardPropMap;
+	var propName;
+
+	for (propName in map) {
 		if (src[propName] != null) {
 			dest[propName] = src[propName];
 		}
-	});
+	}
 };
 
 
@@ -153,8 +229,12 @@ EventDef.copyVerbatimProps = function(src, dest) {
 
 
 EventDef.parse = function(rawInput, source) {
+	var def = new this(source);
 	var calendarTransform = source.calendar.opt('eventDataTransform');
 	var sourceTransform = source.eventDataTransform;
+	var rawStandardProps = {};
+	var miscProps = {};
+	var propName;
 
 	if (calendarTransform) {
 		rawInput = calendarTransform(rawInput);
@@ -163,54 +243,64 @@ EventDef.parse = function(rawInput, source) {
 		rawInput = sourceTransform(rawInput);
 	}
 
-	return this.pluckAndParse($.extend({}, rawInput), source);
+	for (propName in rawInput) {
+		if (def.isStandardProp(propName)) {
+			rawStandardProps[propName] = rawInput[propName];
+		}
+		else {
+			miscProps[propName] = rawInput[propName];
+		}
+	}
+
+	if (def.applyStandardProps(rawStandardProps) === false) {
+		return false;
+	}
+
+	def.miscProps = miscProps;
+
+	return def;
 };
 
 
-EventDef.pluckAndParse = function(rawProps, source) {
-	// pluck
-	var rawId = pluckProp(rawProps, 'id');
-	var className = pluckProp(rawProps, 'className');
+// Definitions for this abstract EventDef class
+// ---------------------------------------------------------------------------------------------------------------------
 
-	// instantiate and parse...
-	var def = new this(source);
 
-	def.uid = String(EventDef.uuid++);
+EventDef.defineStandardPropHandler([
+	'id',
+	'className',
+	'source' // will ignored
+], function(rawProps) {
 
-	if (rawId == null) {
-		def.id = EventDef.generateId();
+	if (rawProps.id == null) {
+		this.id = EventDef.generateId();
 	}
 	else {
-		def.id = EventDef.normalizeId((def.rawId = rawId));
+		this.id = EventDef.normalizeId((this.rawId = rawProps.id));
 	}
 
 	// can make DRY with EventSource
-	if (typeof className === 'string') {
-		def.className = className.split(/\s+/);
+	if ($.isArray(rawProps.className)) {
+		this.className = rawProps.className;
 	}
-	else if ($.isArray(className)) {
-		def.className = className;
+	else if (typeof rawProps.className === 'string') {
+		this.className = rawProps.className.split(/\s+/);
 	}
-
-	// transfer all other simple props
-	$.extend(def, pluckProps(rawProps, EventDef.VERBATIM_PROPS));
-
-	// raw input object might have specified
-	// intercepted earlier
-	delete rawProps.source;
-
-	// leftovers are misc props
-	def.miscProps = rawProps;
-
-	return def;
-};
-
-
-EventDef.normalizeId = function(id) {
-	return String(id);
-};
+});
 
 
-EventDef.generateId = function() {
-	return '_fc' + (EventDef.uuid++);
-};
+EventDef.defineVerbatimStandardProps([
+	'title',
+	'url',
+	'rendering',
+	'constraint',
+	'overlap',
+	'editable',
+	'startEditable',
+	'durationEditable',
+	'resourceEditable',
+	'color',
+	'backgroundColor',
+	'borderColor',
+	'textColor'
+]);

+ 8 - 22
src/models/event/EventDefDateMutation.js

@@ -103,24 +103,10 @@ var EventDefDateMutation = Class.extend({
 });
 
 
-EventDefDateMutation.createFromRawProps = function(eventInstance, newRawProps, largeUnit) {
-	var newDateProfile = EventDateProfile.parse(
-		newRawProps,
-		eventInstance.def.source.calendar
-	);
-
-	return EventDefDateMutation.createFromDiff(
-		eventInstance.dateProfile,
-		newDateProfile,
-		largeUnit
-	);
-};
-
-
-EventDefDateMutation.createFromDiff = function(dateProfile0, dateProfile2, largeUnit) {
-	var clearEnd = dateProfile0.end && !dateProfile2.end;
-	var forceTimed = dateProfile0.isAllDay() && !dateProfile2.isAllDay();
-	var forceAllDay = !dateProfile0.isAllDay() && dateProfile2.isAllDay();
+EventDefDateMutation.createFromDiff = function(dateProfile0, dateProfile1, largeUnit) {
+	var clearEnd = dateProfile0.end && !dateProfile1.end;
+	var forceTimed = dateProfile0.isAllDay() && !dateProfile1.isAllDay();
+	var forceAllDay = !dateProfile0.isAllDay() && dateProfile1.isAllDay();
 	var dateDelta;
 	var endDiff;
 	var endDelta;
@@ -131,7 +117,7 @@ EventDefDateMutation.createFromDiff = function(dateProfile0, dateProfile2, large
 		if (largeUnit) {
 			return diffByUnit(date1, date0, largeUnit); // poorly named
 		}
-		else if (dateProfile2.isAllDay()) {
+		else if (dateProfile1.isAllDay()) {
 			return diffDay(date1, date0); // poorly named
 		}
 		else {
@@ -139,10 +125,10 @@ EventDefDateMutation.createFromDiff = function(dateProfile0, dateProfile2, large
 		}
 	}
 
-	dateDelta = subtractDates(dateProfile2.start, dateProfile0.start);
+	dateDelta = subtractDates(dateProfile1.start, dateProfile0.start);
 
-	if (dateProfile2.end) {
-		endDiff = subtractDates(dateProfile2.end, dateProfile0.getEnd());
+	if (dateProfile1.end) {
+		endDiff = subtractDates(dateProfile1.end, dateProfile0.getEnd());
 		endDelta = endDiff.subtract(dateDelta);
 	}
 

+ 39 - 63
src/models/event/EventDefMutation.js

@@ -1,107 +1,83 @@
 
 var EventDefMutation = Class.extend({
 
-	newTitle: null,
-	newRendering: null,
-	newConstraint: null,
-	newOverlap: null,
-	newClassName: null, // array or null
-
-	additionalMiscProps: null,
 	dateMutation: null,
 
+	// hacks to get updateEvent/createFromRawProps to work.
+	// not undo-able and not considered in isEmpty.
+	standardProps: null, // raw (pre-parse-like)
+	miscProps: null,
+
 
 	/*
 	eventDef assumed to be a SingleEventDef.
 	returns an undo function.
 	*/
 	mutateSingle: function(eventDef) {
-		var origTitle = eventDef.title;
-		var origRendering = eventDef.rendering;
-		var origConstraint = eventDef.constraint;
-		var origOverlap = eventDef.overlap;
-		var origClassName = eventDef.className;
-		var origMiscProps = eventDef.miscProps;
 		var undoDateMutation;
 
-		if (this.newTitle != null) {
-			eventDef.title = this.newTitle;
-		}
-
-		if (this.newRendering != null) {
-			eventDef.rendering = this.newRendering;
-		}
-
-		if (this.newConstraint != null) {
-			eventDef.constraint = this.newConstraint;
+		if (this.dateMutation) {
+			undoDateMutation = this.dateMutation.mutateSingle(eventDef);
 		}
 
-		if (this.newOverlap != null) {
-			eventDef.overlap = this.newOverlap;
+		// can't undo
+		if (this.standardProps) {
+			eventDef.applyStandardProps(this.standardProps);
 		}
 
-		if (this.newClassName != null) {
-			eventDef.className = this.newClassName;
+		// can't undo
+		if (this.miscProps) {
+			eventDef.miscProps = this.miscProps;
 		}
 
-		if (this.additionalMiscProps != null) {
-			// create a new object, so that "orig" stays intact
-			eventDef.miscProps = $.extend({}, eventDef.miscProps, this.additionalMiscProps);
+		if (undoDateMutation) {
+			return undoDateMutation;
 		}
-
-		if (this.dateMutation) {
-			undoDateMutation = this.dateMutation.mutateSingle(eventDef);
+		else {
+			return function() { };
 		}
-
-		return function() {
-			eventDef.title = origTitle;
-			eventDef.rendering = origRendering;
-			eventDef.constraint = origConstraint;
-			eventDef.overlap = origOverlap;
-			eventDef.className = origClassName;
-			eventDef.miscProps = origMiscProps;
-
-			if (undoDateMutation) {
-				undoDateMutation();
-			}
-		};
 	},
 
 
 	isEmpty: function() {
-		return this.newTitle == null &&
-			this.newRendering == null &&
-			this.newConstraint == null &&
-			this.newOverlap == null &&
-			this.newClassName == null &&
-			this.additionalMiscProps == null &&
-			(!this.dateMutation || this.dateMutation.isEmpty());
+		return !this.dateMutation || this.dateMutation.isEmpty();
 	}
 
 });
 
 
 EventDefMutation.createFromRawProps = function(eventInstance, newRawProps, largeUnit) {
-	var additionalMiscProps = {};
+	var eventDef = eventInstance.def;
+	var calendar = eventDef.source.calendar;
+	var standardProps = {};
+	var miscProps = {};
 	var propName;
+	var newDateProfile;
 	var dateMutation;
 	var defMutation;
 
 	for (propName in newRawProps) {
-		if (!eventInstance.def.isStandardProp(propName)) {
-			additionalMiscProps[propName] = newRawProps[propName];
+		if (propName !== 'start' && propName !== 'end') {
+			if (eventDef.isStandardProp(propName)) {
+				standardProps[propName] = newRawProps[propName];
+			}
+			else {
+				miscProps[propName] = newRawProps[propName];
+			}
 		}
 	}
 
-	dateMutation = EventDefDateMutation.createFromRawProps(eventInstance, newRawProps, largeUnit);
+	// the 'start' and 'end' props will be leveraged
+	newDateProfile = EventDateProfile.parse(newRawProps, calendar);
+	dateMutation = EventDefDateMutation.createFromDiff(
+		eventInstance.dateProfile,
+		newDateProfile,
+		largeUnit
+	);
 
 	defMutation = new EventDefMutation();
-	defMutation.newTitle = newRawProps.title;
-	defMutation.newRendering = newRawProps.rendering;
-	defMutation.newConstraint = newRawProps.constraint;
-	defMutation.newOverlap = newRawProps.overlap;
-	defMutation.newClassName = newRawProps.className;
-	defMutation.additionalMiscProps = additionalMiscProps;
+	defMutation.standardProps = standardProps;
+	defMutation.miscProps = miscProps;
 	defMutation.dateMutation = dateMutation;
 
 	return defMutation;

+ 13 - 18
src/models/event/RecurringEventDef.js

@@ -87,26 +87,21 @@ var RecurringEventDef = EventDef.extend({
 // ---------------------------------------------------------------------------------------------------------------------
 
 
-RecurringEventDef.pluckAndParse = function(rawProps, source) {
-	// pluck from rawProps before sending to super-method
-	var startInput = pluckProp(rawProps, 'start');
-	var endInput = pluckProp(rawProps, 'end');
-	var dow = pluckProp(rawProps, 'dow');
-
-	// instantiate and parse...
-	var def = EventDef.pluckAndParse.call(this, rawProps, source); // a RecurringEventDef
-
-	if (startInput) {
-		def.startTime = moment.duration(startInput);
+RecurringEventDef.defineStandardPropHandler([
+	'start',
+	'end',
+	'dow'
+], function(rawProps) {
+
+	if (rawProps.start) {
+		this.startTime = moment.duration(rawProps.start);
 	}
 
-	if (endInput) {
-		def.endTime = moment.duration(endInput);
+	if (rawProps.end) {
+		this.endTime = moment.duration(rawProps.end);
 	}
 
-	if (dow) {
-		def.setDow(dow);
+	if (rawProps.dow) {
+		this.setDow(rawProps.dow);
 	}
-
-	return def;
-};
+});

+ 14 - 19
src/models/event/SingleEventDef.js

@@ -45,20 +45,18 @@ var SingleEventDef = EventDef.extend(EventStartEndMixin, {
 // ---------------------------------------------------------------------------------------------------------------------
 
 
-SingleEventDef.pluckAndParse = function(rawProps, source) {
-	// pluck from rawProps before sending to super-method
-	var startInput = pluckProp(rawProps, 'start');
-	var dateInput = pluckProp(rawProps, 'date'); // 'date' is an alias for start
-	var endInput = pluckProp(rawProps, 'end');
-	var forcedAllDay = pluckProp(rawProps, 'allDay');
-
-	// instantiate and parse...
-	var def = EventDef.pluckAndParse.call(this, rawProps, source); // a SingleEventDef
-
+SingleEventDef.defineStandardPropHandler([
+	'start',
+	'date', // alias for 'start'
+	'end',
+	'allDay'
+], function(rawProps) {
+	var source = this.source;
 	var calendar = source.calendar;
-	var start = calendar.moment(startInput || dateInput);
-	var end = endInput ? calendar.moment(endInput) : null;
-	var forceEventDuration;
+	var start = calendar.moment(rawProps.start || rawProps.date);
+	var end = rawProps.end ? calendar.moment(rawProps.end) : null;
+	var forcedAllDay = rawProps.allDay;
+	var forceEventDuration = calendar.opt('forceEventDuration');
 
 	if (!start.isValid()) {
 		return false;
@@ -90,13 +88,10 @@ SingleEventDef.pluckAndParse = function(rawProps, source) {
 		}
 	}
 
-	forceEventDuration = calendar.opt('forceEventDuration');
 	if (!end && forceEventDuration) {
 		end = calendar.getDefaultEventEnd(!start.hasTime(), start);
 	}
 
-	def.start = start;
-	def.end = end;
-
-	return def;
-};
+	this.start = start;
+	this.end = end;
+});