Skip to content

Commit 9136fec

Browse files
fix($urlMatcherFactory): fixed ParamSet.$$keys() ordering
- paramset uses prototypal inheritance, but ordering was not retained correctly. Add a $$parent property so we can enumerate the properties of the prototypal chain appropriately.
1 parent 872d085 commit 9136fec

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

src/state.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
7575

7676
// Derive parameters for this state and ensure they're a super-set of parent's parameters
7777
params: function(state) {
78-
var parentParams = state.parent && state.parent.params || new $$UMFP.ParamSet();
79-
return inherit(parentParams, state.ownParams);
78+
return state.parent && state.parent.params ? extend(state.parent.params.$$new(), state.ownParams) : new $$UMFP.ParamSet();
8079
},
8180

8281
// If there is no explicit multi-view configuration, make one up so we don't have

src/urlMatcherFactory.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ var $$UMFP; // reference to $UrlMatcherFactoryProvider
4242
*
4343
* @param {string} pattern The pattern to compile into a matcher.
4444
* @param {Object} config A configuration object hash:
45+
* @param {Object=} parentMatcher Used to concatenate the pattern/config onto
46+
* an existing UrlMatcher
4547
*
4648
* * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
4749
* * `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`.
@@ -61,7 +63,7 @@ var $$UMFP; // reference to $UrlMatcherFactoryProvider
6163
*
6264
* @returns {Object} New `UrlMatcher` object
6365
*/
64-
function UrlMatcher(pattern, config) {
66+
function UrlMatcher(pattern, config, parentMatcher) {
6567
config = extend({ params: {} }, isObject(config) ? config : {});
6668

6769
// Find all placeholders and create a compiled pattern, using either classic or curly syntax:
@@ -81,9 +83,11 @@ function UrlMatcher(pattern, config) {
8183
searchPlaceholder = /([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
8284
compiled = '^', last = 0, m,
8385
segments = this.segments = [],
84-
params = this.params = new $$UMFP.ParamSet();
86+
parentParams = parentMatcher ? parentMatcher.params : {},
87+
params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet();
8588

8689
function addParameter(id, type, config, isSearch) {
90+
if (parentParams[id]) return parentParams[id];
8791
if (!/^\w+(-+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
8892
if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
8993
params[id] = new $$UMFP.Param(id, type, config, isSearch);
@@ -189,7 +193,7 @@ UrlMatcher.prototype.concat = function (pattern, config) {
189193
strict: $$UMFP.strictMode(),
190194
squash: $$UMFP.defaultSquashPolicy()
191195
};
192-
return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config));
196+
return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this);
193197
};
194198

195199
UrlMatcher.prototype.toString = function () {
@@ -265,7 +269,7 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
265269
* pattern has no parameters, an empty array is returned.
266270
*/
267271
UrlMatcher.prototype.parameters = function (param) {
268-
if (!isDefined(param)) return objectKeys(this.params);
272+
if (!isDefined(param)) return this.params.$$keys();
269273
return this.params[param] || null;
270274
};
271275

@@ -919,8 +923,20 @@ function $UrlMatcherFactory() {
919923
}
920924

921925
ParamSet.prototype = {
926+
$$new: function() {
927+
return inherit(this, extend(new ParamSet(), { $$parent: this}));
928+
},
922929
$$keys: function () {
923-
return protoKeys(this, ["$$keys", "$$values", "$$equals", "$$validates"]);
930+
var keys = [], chain = [], parent = this,
931+
ignore = ["$$keys", "$$values", "$$equals", "$$validates", "$$parent"];
932+
while (parent) { chain.push(parent); parent = parent.$$parent; }
933+
chain.reverse();
934+
forEach(chain, function(paramset) {
935+
forEach(objectKeys(paramset), function(key) {
936+
if (keys.indexOf(key) === -1 && ignore.indexOf(key) === -1) keys.push(key);
937+
});
938+
});
939+
return keys;
924940
},
925941
$$values: function(paramValues) {
926942
var values = {}, self = this;

0 commit comments

Comments
 (0)