diff --git a/src/common.js b/src/common.js index dd21aad45..cbbb4ce71 100644 --- a/src/common.js +++ b/src/common.js @@ -118,8 +118,7 @@ function inheritParams(currentParams, newParams, $current, $to) { function normalize(keys, values) { var normalized = {}; - forEach(keys, function (name) { - var value = values[name]; + forEach(values, function (value, name) { normalized[name] = (value != null) ? String(value) : null; }); return normalized; @@ -175,7 +174,7 @@ angular.module('ui.router.util', ['ng']); /** * @ngdoc overview * @name ui.router.router - * + * * @requires ui.router.util * * @description @@ -186,7 +185,7 @@ angular.module('ui.router.router', ['ui.router.util']); /** * @ngdoc overview * @name ui.router.router - * + * * @requires ui.router.router * @requires ui.router.util * diff --git a/src/state.js b/src/state.js index 4e6633fa7..3a317c9ec 100644 --- a/src/state.js +++ b/src/state.js @@ -53,9 +53,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ if (isString(url)) { if (url.charAt(0) == '^') { - return $urlMatcherFactory.compile(url.substring(1)); + return $urlMatcherFactory.compile(url.substring(1), state.strict); } - return (state.parent.navigable || root).url.concat(url); + return (state.parent.navigable || root).url.concat(url, state.strict); } if ($urlMatcherFactory.isMatcher(url) || url == null) { @@ -202,7 +202,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ // Register the state in the global state list and with $urlRouter if necessary. if (!state[abstractKey] && state.url) { $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) { - if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) { + if ($state.$current.navigable != state || !equalForKeys($match, $stateParams, state.ownParams)) { $state.transitionTo(state, $match, { location: false }); } }]); @@ -831,10 +831,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ url = "#" + $locationProvider.hashPrefix() + url; } if (options.absolute && url) { - url = $location.protocol() + '://' + - $location.host() + - ($location.port() == 80 || $location.port() == 443 ? '' : ':' + $location.port()) + - (!$locationProvider.html5Mode() && url ? '/' : '') + + url = $location.protocol() + '://' + + $location.host() + + ($location.port() == 80 || $location.port() == 443 ? '' : ':' + $location.port()) + + (!$locationProvider.html5Mode() && url ? '/' : '') + url; } return url; diff --git a/src/urlMatcherFactory.js b/src/urlMatcherFactory.js index ec78c522a..72e51da9c 100644 --- a/src/urlMatcherFactory.js +++ b/src/urlMatcherFactory.js @@ -4,7 +4,7 @@ * of search parameters. Multiple search parameter names are separated by '&'. Search parameters * do not influence whether or not a URL is matched, but their values are passed through into * the matched parameters returned by {@link UrlMatcher#exec exec}. - * + * * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace * syntax, which optionally allows a regular expression for the parameter to be specified: * @@ -15,13 +15,13 @@ * curly braces, they must be in matched pairs or escaped with a backslash. * * Parameter names may contain only word characters (latin letters, digits, and underscore) and - * must be unique within the pattern (across both path and search parameters). For colon + * must be unique within the pattern (across both path and search parameters). For colon * placeholders or curly placeholders without an explicit regexp, a path parameter matches any * number of characters other than '/'. For catch-all placeholders the path parameter matches * any number of characters. - * + * * ### Examples - * + * * * '/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for * trailing slashes, and patterns have to match the entire path, not just a prefix. * * '/user/:id' - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or @@ -36,12 +36,13 @@ * * @constructor * @param {string} pattern the pattern to compile into a matcher. + * @param {boolean} strict the formatting and matching should be strict. * * @property {string} prefix A static prefix of this pattern. The matcher guarantees that any * URL matching this matcher (i.e. any string for which {@link UrlMatcher#exec exec()} returns * non-null) will start with this prefix. */ -function UrlMatcher(pattern) { +function UrlMatcher(pattern, strict) { // Find all placeholders and create a compiled pattern, using either classic or curly syntax: // '*' name @@ -73,6 +74,7 @@ function UrlMatcher(pattern) { } this.source = pattern; + this.strict = typeof strict === 'boolean' ? strict : true; // Split into static segments separated by path parameter placeholders. // The number of segments is always 1 more than the number of parameters. @@ -123,13 +125,14 @@ function UrlMatcher(pattern) { * ``` * * @param {string} pattern The pattern to append. + * @param {boolean} strict the formatting and matching should be strict. * @return {UrlMatcher} A matcher for the concatenated pattern. */ -UrlMatcher.prototype.concat = function (pattern) { +UrlMatcher.prototype.concat = function (pattern, strict) { // Because order of search parameters is irrelevant, we can add our own search // parameters to the end of the new pattern. Parse the new pattern by itself // and then join the bits together, but it's much easier to do this on a string level. - return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch); + return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, strict); }; UrlMatcher.prototype.toString = function () { @@ -166,6 +169,10 @@ UrlMatcher.prototype.exec = function (path, searchParams) { for (i=0; i