11/**
22 * State-based routing for AngularJS
3- * @version v0.3.1
3+ * @version v0.3.2
44 * @link http://angular-ui.github.com/
55 * @license MIT License, http://www.opensource.org/licenses/MIT
66 */
@@ -222,6 +222,11 @@ function map(collection, callback) {
222222 return result ;
223223}
224224
225+ // issue #2676 #2889
226+ function silenceUncaughtInPromise ( promise ) {
227+ return promise . then ( undefined , function ( ) { } ) && promise ;
228+ }
229+
225230/**
226231 * @ngdoc overview
227232 * @name ui.router.util
@@ -1266,8 +1271,8 @@ function $UrlMatcherFactory() {
12661271 // If the slashes are simply URLEncoded, the browser can choose to pre-decode them,
12671272 // and bidirectional encoding/decoding fails.
12681273 // Tilde was chosen because it's not a RFC 3986 section 2.2 Reserved Character
1269- function valToString ( val ) { return val != null ? val . toString ( ) . replace ( / ~ / g, "~~" ) . replace ( / \/ / g , " ~2F" ) : val ; }
1270- function valFromString ( val ) { return val != null ? val . toString ( ) . replace ( / ~ 2 F / g, "/" ) . replace ( / ~ ~ / g , "~" ) : val ; }
1274+ function valToString ( val ) { return val != null ? val . toString ( ) . replace ( / ( ~ | \/ ) / g, function ( m ) { return { '~' : '~~' , '/' : ' ~2F' } [ m ] ; } ) : val ; }
1275+ function valFromString ( val ) { return val != null ? val . toString ( ) . replace ( / ( ~ ~ | ~ 2 F ) / g, function ( m ) { return { '~~' : '~' , '~2F' : '/' } [ m ] ; } ) : val ; }
12711276
12721277 var $types = { } , enqueue = true , typeQueue = [ ] , injector , defaultTypes = {
12731278 "string" : {
@@ -2901,10 +2906,12 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
29012906 $get . $inject = [ '$rootScope' , '$q' , '$view' , '$injector' , '$resolve' , '$stateParams' , '$urlRouter' , '$location' , '$urlMatcherFactory' ] ;
29022907 function $get ( $rootScope , $q , $view , $injector , $resolve , $stateParams , $urlRouter , $location , $urlMatcherFactory ) {
29032908
2904- var TransitionSuperseded = $q . reject ( new Error ( 'transition superseded' ) ) ;
2905- var TransitionPrevented = $q . reject ( new Error ( 'transition prevented' ) ) ;
2906- var TransitionAborted = $q . reject ( new Error ( 'transition aborted' ) ) ;
2907- var TransitionFailed = $q . reject ( new Error ( 'transition failed' ) ) ;
2909+ var TransitionSupersededError = new Error ( 'transition superseded' ) ;
2910+
2911+ var TransitionSuperseded = silenceUncaughtInPromise ( $q . reject ( TransitionSupersededError ) ) ;
2912+ var TransitionPrevented = silenceUncaughtInPromise ( $q . reject ( new Error ( 'transition prevented' ) ) ) ;
2913+ var TransitionAborted = silenceUncaughtInPromise ( $q . reject ( new Error ( 'transition aborted' ) ) ) ;
2914+ var TransitionFailed = silenceUncaughtInPromise ( $q . reject ( new Error ( 'transition failed' ) ) ) ;
29082915
29092916 // Handles the case where a state which is the target of a transition is not found, and the user
29102917 // can optionally retry or defer the transition
@@ -2960,7 +2967,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
29602967 var retryTransition = $state . transition = $q . when ( evt . retry ) ;
29612968
29622969 retryTransition . then ( function ( ) {
2963- if ( retryTransition !== $state . transition ) return TransitionSuperseded ;
2970+ if ( retryTransition !== $state . transition ) {
2971+ $rootScope . $broadcast ( '$stateChangeCancel' , redirect . to , redirect . toParams , state , params ) ;
2972+ return TransitionSuperseded ;
2973+ }
29642974 redirect . options . $retry = true ;
29652975 return $state . transitionTo ( redirect . to , redirect . toParams , redirect . options ) ;
29662976 } , function ( ) {
@@ -3299,7 +3309,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
32993309 var transition = $state . transition = resolved . then ( function ( ) {
33003310 var l , entering , exiting ;
33013311
3302- if ( $state . transition !== transition ) return TransitionSuperseded ;
3312+ if ( $state . transition !== transition ) {
3313+ $rootScope . $broadcast ( '$stateChangeCancel' , to . self , toParams , from . self , fromParams ) ;
3314+ return TransitionSuperseded ;
3315+ }
33033316
33043317 // Exit 'from' states not kept
33053318 for ( l = fromPath . length - 1 ; l >= keep ; l -- ) {
@@ -3320,7 +3333,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
33203333 }
33213334
33223335 // Run it again, to catch any transitions in callbacks
3323- if ( $state . transition !== transition ) return TransitionSuperseded ;
3336+ if ( $state . transition !== transition ) {
3337+ $rootScope . $broadcast ( '$stateChangeCancel' , to . self , toParams , from . self , fromParams ) ;
3338+ return TransitionSuperseded ;
3339+ }
33243340
33253341 // Update globals in $state
33263342 $state . $current = to ;
@@ -3356,7 +3372,14 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
33563372
33573373 return $state . current ;
33583374 } ) . then ( null , function ( error ) {
3359- if ( $state . transition !== transition ) return TransitionSuperseded ;
3375+ // propagate TransitionSuperseded error without emitting $stateChangeCancel
3376+ // as it was already emitted in the success handler above
3377+ if ( error === TransitionSupersededError ) return TransitionSuperseded ;
3378+
3379+ if ( $state . transition !== transition ) {
3380+ $rootScope . $broadcast ( '$stateChangeCancel' , to . self , toParams , from . self , fromParams ) ;
3381+ return TransitionSuperseded ;
3382+ }
33603383
33613384 $state . transition = null ;
33623385 /**
@@ -3380,7 +3403,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
33803403 evt = $rootScope . $broadcast ( '$stateChangeError' , to . self , toParams , from . self , fromParams , error ) ;
33813404
33823405 if ( ! evt . defaultPrevented ) {
3383- $urlRouter . update ( ) ;
3406+ $urlRouter . update ( ) ;
33843407 }
33853408
33863409 return $q . reject ( error ) ;
@@ -3495,7 +3518,17 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
34953518 var state = findState ( stateOrName , options . relative ) ;
34963519 if ( ! isDefined ( state ) ) { return undefined ; }
34973520 if ( ! isDefined ( $state . $current . includes [ state . name ] ) ) { return false ; }
3498- return params ? equalForKeys ( state . params . $$values ( params ) , $stateParams , objectKeys ( params ) ) : true ;
3521+ if ( ! params ) { return true ; }
3522+
3523+ var keys = objectKeys ( params ) ;
3524+ for ( var i = 0 ; i < keys . length ; i ++ ) {
3525+ var key = keys [ i ] , paramDef = state . params [ key ] ;
3526+ if ( paramDef && ! paramDef . type . equals ( $stateParams [ key ] , params [ key ] ) ) {
3527+ return false ;
3528+ }
3529+ }
3530+
3531+ return true ;
34993532 } ;
35003533
35013534
@@ -4268,9 +4301,9 @@ function $StateRefDirective($state, $timeout) {
42684301
42694302 if ( ! type . clickable ) return ;
42704303 hookFn = clickHook ( element , $state , $timeout , type , function ( ) { return def ; } ) ;
4271- element . bind ( "click" , hookFn ) ;
4304+ element [ element . on ? 'on' : ' bind' ] ( "click" , hookFn ) ;
42724305 scope . $on ( '$destroy' , function ( ) {
4273- element . unbind ( "click" , hookFn ) ;
4306+ element [ element . off ? 'off' : ' unbind' ] ( "click" , hookFn ) ;
42744307 } ) ;
42754308 }
42764309 } ;
@@ -4320,9 +4353,9 @@ function $StateRefDynamicDirective($state, $timeout) {
43204353
43214354 if ( ! type . clickable ) return ;
43224355 hookFn = clickHook ( element , $state , $timeout , type , function ( ) { return def ; } ) ;
4323- element . bind ( "click" , hookFn ) ;
4356+ element [ element . on ? 'on' : ' bind' ] ( "click" , hookFn ) ;
43244357 scope . $on ( '$destroy' , function ( ) {
4325- element . unbind ( "click" , hookFn ) ;
4358+ element [ element . off ? 'off' : ' unbind' ] ( "click" , hookFn ) ;
43264359 } ) ;
43274360 }
43284361 } ;
0 commit comments