Răsfoiți Sursa

refactor mergeOptions/mergeProps

Adam Shaw 11 ani în urmă
părinte
comite
8ce082c181
4 a modificat fișierele cu 64 adăugiri și 48 ștergeri
  1. 11 12
      src/Calendar.js
  2. 1 1
      src/lang.js
  3. 3 35
      src/main.js
  4. 49 0
      src/util.js

+ 11 - 12
src/Calendar.js

@@ -46,12 +46,12 @@ var Calendar = fc.Calendar = Class.extend({
 		this.dirDefaults = dirDefaults;
 		this.langDefaults = langDefaults;
 		this.overrides = overrides;
-		this.options = mergeOptions( // merge defaults and overrides. lowest to highest precedence
+		this.options = mergeOptions([ // merge defaults and overrides. lowest to highest precedence
 			Calendar.defaults, // global defaults
 			dirDefaults,
 			langDefaults,
 			overrides
-		);
+		]);
 		populateInstanceComputableOptions(this.options);
 
 		this.viewSpecCache = {}; // somewhat unrelated
@@ -140,32 +140,31 @@ var Calendar = fc.Calendar = Class.extend({
 				// incorporate options for this. lowest priority
 				if (duration.as(unit) === 1) {
 					spec.singleUnit = unit;
-					overridesChain.unshift(viewOverrides[unit] || {});
+					defaultsChain.unshift(viewOverrides[unit] || {});
 				}
 			}
+		}
 
-			// collapse into single objects
-			spec.defaults = mergeOptions.apply(null, defaultsChain);
-			spec.overrides = mergeOptions.apply(null, overridesChain);
+		spec.defaults = mergeOptions(defaultsChain);
+		spec.overrides = mergeOptions(overridesChain);
 
-			this.buildViewSpecOptions(spec);
-			this.buildViewSpecButtonText(spec, requestedViewType);
+		this.buildViewSpecOptions(spec);
+		this.buildViewSpecButtonText(spec, requestedViewType);
 
-			return spec;
-		}
+		return spec;
 	},
 
 
 	// Builds and assigns a view spec's options object from its already-assigned defaults and overrides
 	buildViewSpecOptions: function(spec) {
-		spec.options = mergeOptions( // lowest to highest priority
+		spec.options = mergeOptions([ // lowest to highest priority
 			Calendar.defaults, // global defaults
 			spec.defaults, // view's defaults (from ViewSubclass.defaults)
 			this.dirDefaults,
 			this.langDefaults, // locale and dir take precedence over view's defaults!
 			this.overrides, // calendar's overrides (options given to constructor)
 			spec.overrides // view's overrides (view-specific options)
-		);
+		]);
 		populateInstanceComputableOptions(spec.options);
 	},
 

+ 1 - 1
src/lang.js

@@ -52,7 +52,7 @@ fc.lang = function(langCode, newFcOptions) {
 
 	// provided new options for this language? merge them in
 	if (newFcOptions) {
-		fcOptions = langOptionHash[langCode] = mergeOptions(fcOptions, newFcOptions);
+		fcOptions = langOptionHash[langCode] = mergeOptions([ fcOptions, newFcOptions ]);
 	}
 
 	// compute language options that weren't defined.

+ 3 - 35
src/main.js

@@ -44,41 +44,9 @@ var complexOptions = [ // names of options that are objects whose properties sho
 ];
 
 
-// Recursively combines all passed-in option-hash arguments into a new single option-hash.
-// Given option-hashes are ordered from lowest to highest priority.
-function mergeOptions() {
-	var chain = Array.prototype.slice.call(arguments); // convert to a real array
-	var complexVals = {}; // hash for each complex option's combined values
-	var i, name;
-	var combinedVal;
-	var j;
-	var val;
-
-	// for each complex option, loop through each option-hash and accumulate the combined values
-	for (i = 0; i < complexOptions.length; i++) {
-		name = complexOptions[i];
-		combinedVal = null; // an object holding the merge of all the values
-
-		for (j = 0; j < chain.length; j++) {
-			val = chain[j][name];
-
-			if ($.isPlainObject(val)) {
-				combinedVal = $.extend(combinedVal || {}, val); // merge new properties
-			}
-			else if (val != null) { // a non-null non-undefined atomic option
-				combinedVal = null; // signal to use the atomic value
-			}
-		}
-
-		// if not null, the final value was a combination of other objects. record it
-		if (combinedVal !== null) {
-			complexVals[name] = combinedVal;
-		}
-	}
-
-	chain.unshift({}); // $.extend will mutate this with the result
-	chain.push(complexVals); // computed complex values are applied last
-	return $.extend.apply($, chain); // combine
+// Merges an array of option objects into a single object
+function mergeOptions(optionObjs) {
+	return mergeProps(optionObjs, complexOptions);
 }
 
 

+ 49 - 0
src/util.js

@@ -484,6 +484,55 @@ function isTimeString(str) {
 var hasOwnPropMethod = {}.hasOwnProperty;
 
 
+// Merges an array of objects into a single object.
+// The second argument allows for an array of property names who's object values will be merged together.
+function mergeProps(propObjs, complexProps) {
+	var dest = {};
+	var i, name;
+	var complexObjs;
+	var j, val;
+	var props;
+
+	if (complexProps) {
+		for (i = 0; i < complexProps.length; i++) {
+			name = complexProps[i];
+			complexObjs = [];
+
+			// collect the trailing object values, stopping when a non-object is discovered
+			for (j = propObjs.length - 1; j >= 0; j--) {
+				val = propObjs[j][name];
+
+				if (typeof val === 'object') {
+					complexObjs.unshift(val);
+				}
+				else if (val !== undefined) {
+					dest[name] = val; // if there were no objects, this value will be used
+					break;
+				}
+			}
+
+			// if the trailing values were objects, use the merged value
+			if (complexObjs.length) {
+				dest[name] = mergeProps(complexObjs);
+			}
+		}
+	}
+
+	// copy values into the destination, going from last to first
+	for (i = propObjs.length - 1; i >= 0; i--) {
+		props = propObjs[i];
+
+		for (name in props) {
+			if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign
+				dest[name] = props[name];
+			}
+		}
+	}
+
+	return dest;
+}
+
+
 // Create an object that has the given prototype. Just like Object.create
 function createObject(proto) {
 	var f = function() {};