Skip to content

Commit 3626516

Browse files
author
Derek Gould
committed
fake release
1 parent 26117db commit 3626516

File tree

2 files changed

+89
-36
lines changed

2 files changed

+89
-36
lines changed

release/angular-ui-router.js

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* State-based routing for AngularJS
3-
* @version v0.2.13
3+
* @version v0.2.13-dev-2015-01-29
44
* @link http://angular-ui.github.com/
55
* @license MIT License, http://www.opensource.org/licenses/MIT
66
*/
@@ -39,6 +39,27 @@ function merge(dst) {
3939
return dst;
4040
}
4141

42+
function copyParams(src, dest) {
43+
var params = {};
44+
forEach(src, function(param, key) {
45+
var segments = key.split('.');
46+
var tmp = params;
47+
forEach(segments, function(segment, index) {
48+
if (index < segments.length-1) {
49+
if (!tmp[segment]) {
50+
tmp[segment] = {};
51+
}
52+
if (!isObject(tmp[segment])) throw new Error("State parameter '" + key + "' is invalid: '" + segments.slice(0,index ).join('.') + "' is already defined.");
53+
tmp = tmp[segment];
54+
} else {
55+
if (isObject(tmp[segment])) throw new Error("Unexpected parameter '" + key + "': it already has sub-parameters.");
56+
tmp[segment] = param;
57+
}
58+
});
59+
});
60+
copy(params, dest);
61+
}
62+
4263
/**
4364
* Finds the common ancestor path between two states.
4465
*
@@ -68,7 +89,7 @@ function objectKeys(object) {
6889
}
6990
var result = [];
7091

71-
angular.forEach(object, function(val, key) {
92+
forEach(object, function(val, key) {
7293
result.push(key);
7394
});
7495
return result;
@@ -752,7 +773,7 @@ function UrlMatcher(pattern, config, parentMatcher) {
752773
// \\. - a backslash escape
753774
// \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms
754775
var placeholder = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
755-
searchPlaceholder = /([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
776+
searchPlaceholder = /([:]?)([\w\[\]\.-]+)|\{([\w\[\]\.-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
756777
compiled = '^', last = 0, m,
757778
segments = this.segments = [],
758779
parentParams = parentMatcher ? parentMatcher.params : {},
@@ -762,19 +783,19 @@ function UrlMatcher(pattern, config, parentMatcher) {
762783
function addParameter(id, type, config, location) {
763784
paramNames.push(id);
764785
if (parentParams[id]) return parentParams[id];
765-
if (!/^\w+(-+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
786+
if (!/^\w+((-+\w+)*|(\.\w+)*)?(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
766787
if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
767788
params[id] = new $$UMFP.Param(id, type, config, location);
768789
return params[id];
769790
}
770791

771-
function quoteRegExp(string, pattern, squash) {
792+
function quoteRegExp(string, pattern, squash, optional) {
772793
var surroundPattern = ['',''], result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
773794
if (!pattern) return result;
774795
switch(squash) {
775-
case false: surroundPattern = ['(', ')']; break;
796+
case false: surroundPattern = ['(', ')' + (optional ? "?" : "")]; break;
776797
case true: surroundPattern = ['?(', ')?']; break;
777-
default: surroundPattern = ['(' + squash + "|", ')?']; break;
798+
default: surroundPattern = ['(' + squash + "|", ')?']; break;
778799
}
779800
return result + surroundPattern[0] + pattern + surroundPattern[1];
780801
}
@@ -801,7 +822,7 @@ function UrlMatcher(pattern, config, parentMatcher) {
801822
if (p.segment.indexOf('?') >= 0) break; // we're into the search part
802823

803824
param = addParameter(p.id, p.type, p.cfg, "path");
804-
compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash);
825+
compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash, param.isOptional);
805826
segments.push(p.segment);
806827
last = placeholder.lastIndex;
807828
}
@@ -819,6 +840,7 @@ function UrlMatcher(pattern, config, parentMatcher) {
819840
last = 0;
820841
while ((m = searchPlaceholder.exec(search))) {
821842
p = matchDetails(m, true);
843+
822844
param = addParameter(p.id, p.type, p.cfg, "search");
823845
last = placeholder.lastIndex;
824846
// check if ?&
@@ -912,7 +934,7 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
912934

913935
function decodePathArray(string) {
914936
function reverseString(str) { return str.split("").reverse().join(""); }
915-
function unquoteDashes(str) { return str.replace(/\\-/, "-"); }
937+
function unquoteDashes(str) { return str.replace(/\\-/g, "-"); }
916938

917939
var split = reverseString(string).split(/-(?!\\)/);
918940
var allReversed = map(split, reverseString);
@@ -1150,6 +1172,11 @@ Type.prototype.pattern = /.*/;
11501172

11511173
Type.prototype.toString = function() { return "{Type:" + this.name + "}"; };
11521174

1175+
/** Given an encoded string, or a decoded object, returns a decoded object */
1176+
Type.prototype.$normalize = function(val) {
1177+
return this.is(val) ? val : this.decode(val);
1178+
};
1179+
11531180
/*
11541181
* Wraps an existing custom Type as an array of Type, depending on 'mode'.
11551182
* e.g.:
@@ -1163,7 +1190,6 @@ Type.prototype.toString = function() { return "{Type:" + this.name + "}"; };
11631190
Type.prototype.$asArray = function(mode, isSearch) {
11641191
if (!mode) return this;
11651192
if (mode === "auto" && !isSearch) throw new Error("'auto' array mode is for query parameters only");
1166-
return new ArrayType(this, mode);
11671193

11681194
function ArrayType(type, mode) {
11691195
function bindTo(type, callbackName) {
@@ -1212,8 +1238,12 @@ Type.prototype.$asArray = function(mode, isSearch) {
12121238
this.is = arrayHandler(bindTo(type, 'is'), true);
12131239
this.equals = arrayEqualsHandler(bindTo(type, 'equals'));
12141240
this.pattern = type.pattern;
1241+
this.$normalize = arrayHandler(bindTo(type, '$normalize'));
1242+
this.name = type.name;
12151243
this.$arrayMode = mode;
12161244
}
1245+
1246+
return new ArrayType(this, mode);
12171247
};
12181248

12191249

@@ -1241,7 +1271,7 @@ function $UrlMatcherFactory() {
12411271
string: {
12421272
encode: valToString,
12431273
decode: valFromString,
1244-
is: regexpMatches,
1274+
is: function(val) { return typeof val === "string"; },
12451275
pattern: /[^/]*/
12461276
},
12471277
int: {
@@ -1615,7 +1645,10 @@ function $UrlMatcherFactory() {
16151645
*/
16161646
function $$getDefaultValue() {
16171647
if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
1618-
return injector.invoke(config.$$fn);
1648+
var defaultValue = injector.invoke(config.$$fn);
1649+
if (defaultValue !== null && defaultValue !== undefined && !self.type.is(defaultValue))
1650+
throw new Error("Default value (" + defaultValue + ") for parameter '" + self.id + "' is not an instance of Type (" + self.type.name + ")");
1651+
return defaultValue;
16191652
}
16201653

16211654
/**
@@ -1629,7 +1662,7 @@ function $UrlMatcherFactory() {
16291662
return replacement.length ? replacement[0] : value;
16301663
}
16311664
value = $replace(value);
1632-
return isDefined(value) ? self.type.decode(value) : $$getDefaultValue();
1665+
return !isDefined(value) ? $$getDefaultValue() : self.type.$normalize(value);
16331666
}
16341667

16351668
function toString() { return "{Param:" + id + " " + type + " squash: '" + squash + "' optional: " + isOptional + "}"; }
@@ -1685,15 +1718,20 @@ function $UrlMatcherFactory() {
16851718
return equal;
16861719
},
16871720
$$validates: function $$validate(paramValues) {
1688-
var result = true, isOptional, val, param, self = this;
1689-
1690-
forEach(this.$$keys(), function(key) {
1691-
param = self[key];
1692-
val = paramValues[key];
1693-
isOptional = !val && param.isOptional;
1694-
result = result && (isOptional || !!param.type.is(val));
1695-
});
1696-
return result;
1721+
var keys = this.$$keys(), i, param, rawVal, normalized, encoded;
1722+
for (i = 0; i < keys.length; i++) {
1723+
param = this[keys[i]];
1724+
rawVal = paramValues[keys[i]];
1725+
if ((rawVal === undefined || rawVal === null) && param.isOptional)
1726+
break; // There was no parameter value, but the param is optional
1727+
normalized = param.type.$normalize(rawVal);
1728+
if (!param.type.is(normalized))
1729+
return false; // The value was not of the correct Type, and could not be decoded to the correct Type
1730+
encoded = param.type.encode(normalized);
1731+
if (angular.isString(encoded) && !param.type.pattern.exec(encoded))
1732+
return false; // The value was of the correct type, but when encoded, did not match the Type's regexp
1733+
}
1734+
return true;
16971735
},
16981736
$$parent: undefined
16991737
};
@@ -2336,6 +2374,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
23362374
var globSegments = glob.split('.'),
23372375
segments = $state.$current.name.split('.');
23382376

2377+
//match single stars
2378+
for (var i = 0, l = globSegments.length; i < l; i++) {
2379+
if (globSegments[i] === '*') {
2380+
segments[i] = '*';
2381+
}
2382+
}
2383+
23392384
//match greedy starts
23402385
if (globSegments[0] === '**') {
23412386
segments = segments.slice(indexOf(segments, globSegments[1]));
@@ -2351,13 +2396,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
23512396
return false;
23522397
}
23532398

2354-
//match single stars
2355-
for (var i = 0, l = globSegments.length; i < l; i++) {
2356-
if (globSegments[i] === '*') {
2357-
segments[i] = '*';
2358-
}
2359-
}
2360-
23612399
return segments.join('') === globSegments.join('');
23622400
}
23632401

@@ -2566,6 +2604,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
25662604
* published to scope under the controllerAs name.
25672605
* <pre>controllerAs: "myCtrl"</pre>
25682606
*
2607+
* @param {string|object=} stateConfig.parent
2608+
* <a id='parent'></a>
2609+
* Optionally specifies the parent state of this state.
2610+
*
2611+
* <pre>parent: 'parentState'</pre>
2612+
* <pre>parent: parentState // JS variable</pre>
2613+
*
25692614
* @param {object=} stateConfig.resolve
25702615
* <a id='resolve'></a>
25712616
*
@@ -2597,15 +2642,19 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
25972642
* transitioned to, the `$stateParams` service will be populated with any
25982643
* parameters that were passed.
25992644
*
2645+
* (See {@link ui.router.util.type:UrlMatcher UrlMatcher} `UrlMatcher`} for
2646+
* more details on acceptable patterns )
2647+
*
26002648
* examples:
26012649
* <pre>url: "/home"
26022650
* url: "/users/:userid"
26032651
* url: "/books/{bookid:[a-zA-Z_-]}"
26042652
* url: "/books/{categoryid:int}"
26052653
* url: "/books/{publishername:string}/{categoryid:int}"
26062654
* url: "/messages?before&after"
2607-
* url: "/messages?{before:date}&{after:date}"</pre>
2655+
* url: "/messages?{before:date}&{after:date}"
26082656
* url: "/messages/:mailboxid?{before:date}&{after:date}"
2657+
* </pre>
26092658
*
26102659
* @param {object=} stateConfig.views
26112660
* <a id='views'></a>
@@ -3191,7 +3240,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
31913240
$state.$current = to;
31923241
$state.current = to.self;
31933242
$state.params = toParams;
3194-
copy($state.params, $stateParams);
3243+
copyParams($state.params, $stateParams);
31953244
$state.transition = null;
31963245

31973246
if (options.location && to.navigable) {
@@ -3609,7 +3658,7 @@ function $ViewScrollProvider() {
36093658
}
36103659

36113660
return function ($element) {
3612-
$timeout(function () {
3661+
return $timeout(function () {
36133662
$element[0].scrollIntoView();
36143663
}, 0, false);
36153664
};
@@ -3894,6 +3943,7 @@ function $ViewDirectiveFill ( $compile, $controller, $state, $interpolate
38943943

38953944
if (locals.$$controller) {
38963945
locals.$scope = scope;
3946+
locals.$element = $element;
38973947
var controller = $controller(locals.$$controller, locals);
38983948
if (locals.$$controllerAs) {
38993949
scope[locals.$$controllerAs] = controller;
@@ -4009,9 +4059,12 @@ function $StateRefDirective($state, $timeout) {
40094059
link: function(scope, element, attrs, uiSrefActive) {
40104060
var ref = parseStateRef(attrs.uiSref, $state.current.name);
40114061
var params = null, url = null, base = stateContext(element) || $state.$current;
4012-
var newHref = null, isAnchor = element.prop("tagName") === "A";
4062+
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
4063+
var hrefKind = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
4064+
'xlink:href' : 'href';
4065+
var newHref = null, isAnchor = element.prop("tagName").toUpperCase() === "A";
40134066
var isForm = element[0].nodeName === "FORM";
4014-
var attr = isForm ? "action" : "href", nav = true;
4067+
var attr = isForm ? "action" : hrefKind, nav = true;
40154068

40164069
var options = { relative: base, inherit: true };
40174070
var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {};

0 commit comments

Comments
 (0)