11/**
22 * State-based routing for AngularJS
3- * @version v0.2.14
3+ * @version v0.2.15
44 * @link http://angular-ui.github.com/
55 * @license MIT License, http://www.opensource.org/licenses/MIT
66 */
@@ -1241,15 +1241,14 @@ function $UrlMatcherFactory() {
12411241
12421242 function valToString ( val ) { return val != null ? val . toString ( ) . replace ( / \/ / g, "%2F" ) : val ; }
12431243 function valFromString ( val ) { return val != null ? val . toString ( ) . replace ( / % 2 F / g, "/" ) : val ; }
1244- // TODO: in 1.0, make string .is() return false if value is undefined by default.
1245- // function regexpMatches(val) { /*jshint validthis:true */ return isDefined(val) && this.pattern.test(val); }
1246- function regexpMatches ( val ) { /*jshint validthis:true */ return this . pattern . test ( val ) ; }
12471244
12481245 var $types = { } , enqueue = true , typeQueue = [ ] , injector , defaultTypes = {
12491246 string : {
12501247 encode : valToString ,
12511248 decode : valFromString ,
1252- is : function ( val ) { return typeof val === "string" ; } ,
1249+ // TODO: in 1.0, make string .is() return false if value is undefined/null by default.
1250+ // In 0.2.x, string params are optional by default for backwards compat
1251+ is : function ( val ) { return val == null || ! isDefined ( val ) || typeof val === "string" ; } ,
12531252 pattern : / [ ^ / ] * /
12541253 } ,
12551254 int : {
@@ -1293,7 +1292,6 @@ function $UrlMatcherFactory() {
12931292 any : { // does not encode/decode
12941293 encode : angular . identity ,
12951294 decode : angular . identity ,
1296- is : angular . identity ,
12971295 equals : angular . equals ,
12981296 pattern : / .* /
12991297 }
@@ -2002,7 +2000,8 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) {
20022000 if ( evt && evt . defaultPrevented ) return ;
20032001 var ignoreUpdate = lastPushedUrl && $location . url ( ) === lastPushedUrl ;
20042002 lastPushedUrl = undefined ;
2005- if ( ignoreUpdate ) return true ;
2003+ // TODO: Re-implement this in 1.0 for https://github.com/angular-ui/ui-router/issues/1573
2004+ //if (ignoreUpdate) return true;
20062005
20072006 function check ( rule ) {
20082007 var handled = rule ( $injector , $location ) ;
@@ -3104,7 +3103,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
31043103 * have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
31053104 * use this when you want to force a reload when *everything* is the same, including search params.
31063105 * if String, then will reload the state with the name given in reload, and any children.
3107- * if Object, then a stateObj is expected, will reload the state found in stateObj, and any chhildren .
3106+ * if Object, then a stateObj is expected, will reload the state found in stateObj, and any children .
31083107 *
31093108 * @returns {promise } A promise representing the state of the new transition. See
31103109 * {@link ui.router.state.$state#methods_go $state.go}.
@@ -3152,7 +3151,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
31523151
31533152 // Starting from the root of the path, keep all levels that haven't changed
31543153 var keep = 0 , state = toPath [ keep ] , locals = root . locals , toLocals = [ ] ;
3155- var skipTriggerReloadCheck = false ;
31563154
31573155 if ( ! options . reload ) {
31583156 while ( state && state === fromPath [ keep ] && state . ownParams . $$equals ( toParams , fromParams ) ) {
@@ -3170,8 +3168,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
31703168 throw new Error ( "No such reload state '" + ( isString ( options . reload ) ? options . reload : options . reload . name ) + "'" ) ;
31713169 }
31723170
3173- skipTriggerReloadCheck = true ;
3174-
31753171 while ( state && state === fromPath [ keep ] && state !== reloadState ) {
31763172 locals = toLocals [ keep ] = state . locals ;
31773173 keep ++ ;
@@ -3184,8 +3180,16 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
31843180 // TODO: We may not want to bump 'transition' if we're called from a location change
31853181 // that we've initiated ourselves, because we might accidentally abort a legitimate
31863182 // transition initiated from code?
3187- if ( ! skipTriggerReloadCheck && shouldTriggerReload ( to , from , locals , options ) ) {
3188- if ( to . self . reloadOnSearch !== false ) $urlRouter . update ( ) ;
3183+ if ( shouldSkipReload ( to , toParams , from , fromParams , locals , options ) ) {
3184+ if ( hash ) toParams [ '#' ] = hash ;
3185+ $state . params = toParams ;
3186+ copy ( $state . params , $stateParams ) ;
3187+ if ( options . location && to . navigable && to . navigable . url ) {
3188+ $urlRouter . push ( to . navigable . url , toParams , {
3189+ $$avoidResync : true , replace : options . location === 'replace'
3190+ } ) ;
3191+ $urlRouter . update ( true ) ;
3192+ }
31893193 $state . transition = null ;
31903194 return $q . when ( $state . current ) ;
31913195 }
@@ -3540,39 +3544,66 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
35403544 } ) ] ;
35413545 if ( inherited ) promises . push ( inherited ) ;
35423546
3543- // Resolve template and dependencies for all views.
3544- forEach ( state . views , function ( view , name ) {
3545- var injectables = ( view . resolve && view . resolve !== state . resolve ? view . resolve : { } ) ;
3546- injectables . $template = [ function ( ) {
3547- return $view . load ( name , { view : view , locals : locals , params : $stateParams , notify : options . notify } ) || '' ;
3548- } ] ;
3549-
3550- promises . push ( $resolve . resolve ( injectables , locals , dst . resolve , state ) . then ( function ( result ) {
3551- // References to the controller (only instantiated at link time)
3552- if ( isFunction ( view . controllerProvider ) || isArray ( view . controllerProvider ) ) {
3553- var injectLocals = angular . extend ( { } , injectables , locals , result ) ;
3554- result . $$controller = $injector . invoke ( view . controllerProvider , null , injectLocals ) ;
3555- } else {
3556- result . $$controller = view . controller ;
3557- }
3558- // Provide access to the state itself for internal use
3559- result . $$state = state ;
3560- result . $$controllerAs = view . controllerAs ;
3561- dst [ name ] = result ;
3562- } ) ) ;
3563- } ) ;
3547+ function resolveViews ( ) {
3548+ var viewsPromises = [ ] ;
3549+
3550+ // Resolve template and dependencies for all views.
3551+ forEach ( state . views , function ( view , name ) {
3552+ var injectables = ( view . resolve && view . resolve !== state . resolve ? view . resolve : { } ) ;
3553+ injectables . $template = [ function ( ) {
3554+ return $view . load ( name , { view : view , locals : dst . globals , params : $stateParams , notify : options . notify } ) || '' ;
3555+ } ] ;
3556+
3557+ viewsPromises . push ( $resolve . resolve ( injectables , dst . globals , dst . resolve , state ) . then ( function ( result ) {
3558+ // References to the controller (only instantiated at link time)
3559+ if ( isFunction ( view . controllerProvider ) || isArray ( view . controllerProvider ) ) {
3560+ var injectLocals = angular . extend ( { } , injectables , dst . globals ) ;
3561+ result . $$controller = $injector . invoke ( view . controllerProvider , null , injectLocals ) ;
3562+ } else {
3563+ result . $$controller = view . controller ;
3564+ }
3565+ // Provide access to the state itself for internal use
3566+ result . $$state = state ;
3567+ result . $$controllerAs = view . controllerAs ;
3568+ dst [ name ] = result ;
3569+ } ) ) ;
3570+ } ) ;
3571+
3572+ return $q . all ( viewsPromises ) . then ( function ( ) {
3573+ return dst . globals ;
3574+ } ) ;
3575+ }
35643576
35653577 // Wait for all the promises and then return the activation object
3566- return $q . all ( promises ) . then ( function ( values ) {
3578+ return $q . all ( promises ) . then ( resolveViews ) . then ( function ( values ) {
35673579 return dst ;
35683580 } ) ;
35693581 }
35703582
35713583 return $state ;
35723584 }
35733585
3574- function shouldTriggerReload ( to , from , locals , options ) {
3575- if ( to === from && ( ( locals === from . locals && ! options . reload ) || ( to . self . reloadOnSearch === false ) ) ) {
3586+ function shouldSkipReload ( to , toParams , from , fromParams , locals , options ) {
3587+ // Return true if there are no differences in non-search (path/object) params, false if there are differences
3588+ function nonSearchParamsEqual ( fromAndToState , fromParams , toParams ) {
3589+ // Identify whether all the parameters that differ between `fromParams` and `toParams` were search params.
3590+ function notSearchParam ( key ) {
3591+ return fromAndToState . params [ key ] . location != "search" ;
3592+ }
3593+ var nonQueryParamKeys = fromAndToState . params . $$keys ( ) . filter ( notSearchParam ) ;
3594+ var nonQueryParams = pick . apply ( { } , [ fromAndToState . params ] . concat ( nonQueryParamKeys ) ) ;
3595+ var nonQueryParamSet = new $$UMFP . ParamSet ( nonQueryParams ) ;
3596+ return nonQueryParamSet . $$equals ( fromParams , toParams ) ;
3597+ }
3598+
3599+ // If reload was not explicitly requested
3600+ // and we're transitioning to the same state we're already in
3601+ // and the locals didn't change
3602+ // or they changed in a way that doesn't merit reloading
3603+ // (reloadOnParams:false, or reloadOnSearch.false and only search params changed)
3604+ // Then return true.
3605+ if ( ! options . reload && to === from &&
3606+ ( locals === from . locals || ( to . self . reloadOnSearch === false && nonSearchParamsEqual ( from , fromParams , toParams ) ) ) ) {
35763607 return true ;
35773608 }
35783609 }
0 commit comments