@@ -298,32 +298,67 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
298
298
299
299
} ,
300
300
301
- emit : function ( step , enteringData , leavingData ) {
302
- var enteringScope = enteringEle . scope ( ) ,
303
- leavingScope = leavingEle && leavingEle . scope ( ) ;
301
+ emit : function ( step , enteringData , leavingData ) {
302
+ var enteringScope = getScopeForElement ( enteringEle , enteringData ) ;
303
+ var leavingScope = getScopeForElement ( leavingEle , leavingData ) ;
304
304
305
- if ( step == 'after' ) {
306
- if ( enteringScope ) {
307
- enteringScope . $emit ( '$ionicView.enter' , enteringData ) ;
308
- }
305
+ var prefixesAreEqual ;
309
306
310
- if ( leavingScope ) {
311
- leavingScope . $emit ( '$ionicView.leave' , leavingData ) ;
307
+ if ( ! enteringData . viewId || enteringData . abstractView ) {
308
+ // it's an abstract view, so treat it accordingly
312
309
313
- } else if ( enteringScope && leavingData && leavingData . viewId ) {
314
- enteringScope . $emit ( '$ionicNavView.leave' , leavingData ) ;
310
+ // we only get access to the leaving scope once in the transition,
311
+ // so dispatch all events right away if it exists
312
+ if ( leavingScope ) {
313
+ leavingScope . $emit ( '$ionicView.beforeLeave' , leavingData ) ;
314
+ leavingScope . $emit ( '$ionicView.leave' , leavingData ) ;
315
+ leavingScope . $emit ( '$ionicView.afterLeave' , leavingData ) ;
316
+ leavingScope . $broadcast ( '$ionicParentView.beforeLeave' , leavingData ) ;
317
+ leavingScope . $broadcast ( '$ionicParentView.leave' , leavingData ) ;
318
+ leavingScope . $broadcast ( '$ionicParentView.afterLeave' , leavingData ) ;
315
319
}
316
320
}
321
+ else {
322
+ // it's a regular view, so do the normal process
323
+ if ( step == 'after' ) {
324
+ if ( enteringScope ) {
325
+ enteringScope . $emit ( '$ionicView.enter' , enteringData ) ;
326
+ enteringScope . $broadcast ( '$ionicParentView.enter' , enteringData ) ;
327
+ }
317
328
318
- if ( enteringScope ) {
319
- enteringScope . $emit ( '$ionicView.' + step + 'Enter' , enteringData ) ;
320
- }
329
+ if ( leavingScope ) {
330
+ leavingScope . $emit ( '$ionicView.leave' , leavingData ) ;
331
+ leavingScope . $broadcast ( '$ionicParentView.leave' , leavingData ) ;
332
+ }
333
+ else if ( enteringScope && leavingData && leavingData . viewId && enteringData . stateName !== leavingData . stateName ) {
334
+ // we only want to dispatch this when we are doing a single-tier
335
+ // state change such as changing a tab, so compare the state
336
+ // for the same state-prefix but different suffix
337
+ prefixesAreEqual = compareStatePrefixes ( enteringData . stateName , leavingData . stateName ) ;
338
+ if ( prefixesAreEqual ) {
339
+ enteringScope . $emit ( '$ionicNavView.leave' , leavingData ) ;
340
+ }
341
+ }
342
+ }
321
343
322
- if ( leavingScope ) {
323
- leavingScope . $emit ( '$ionicView.' + step + 'Leave' , leavingData ) ;
344
+ if ( enteringScope ) {
345
+ enteringScope . $emit ( '$ionicView.' + step + 'Enter' , enteringData ) ;
346
+ enteringScope . $broadcast ( '$ionicParentView.' + step + 'Enter' , enteringData ) ;
347
+ }
324
348
325
- } else if ( enteringScope && leavingData && leavingData . viewId ) {
326
- enteringScope . $emit ( '$ionicNavView.' + step + 'Leave' , leavingData ) ;
349
+ if ( leavingScope ) {
350
+ leavingScope . $emit ( '$ionicView.' + step + 'Leave' , leavingData ) ;
351
+ leavingScope . $broadcast ( '$ionicParentView.' + step + 'Leave' , leavingData ) ;
352
+
353
+ } else if ( enteringScope && leavingData && leavingData . viewId && enteringData . stateName !== leavingData . stateName ) {
354
+ // we only want to dispatch this when we are doing a single-tier
355
+ // state change such as changing a tab, so compare the state
356
+ // for the same state-prefix but different suffix
357
+ prefixesAreEqual = compareStatePrefixes ( enteringData . stateName , leavingData . stateName ) ;
358
+ if ( prefixesAreEqual ) {
359
+ enteringScope . $emit ( '$ionicNavView.' + step + 'Leave' , leavingData ) ;
360
+ }
361
+ }
327
362
}
328
363
} ,
329
364
@@ -407,6 +442,15 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
407
442
containerEle . innerHTML = viewLocals . $template ;
408
443
if ( containerEle . children . length === 1 ) {
409
444
containerEle . children [ 0 ] . classList . add ( 'pane' ) ;
445
+ if ( viewLocals . $$state && viewLocals . $$state . self && viewLocals . $$state . self [ 'abstract' ] ) {
446
+ angular . element ( containerEle . children [ 0 ] ) . attr ( "abstract" , "true" ) ;
447
+ }
448
+ else {
449
+ if ( viewLocals . $$state && viewLocals . $$state . self ) {
450
+ angular . element ( containerEle . children [ 0 ] ) . attr ( "state" , viewLocals . $$state . self . name ) ;
451
+ }
452
+
453
+ }
410
454
return jqLite ( containerEle . children [ 0 ] ) ;
411
455
}
412
456
}
@@ -491,4 +535,67 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
491
535
}
492
536
}
493
537
538
+ function compareStatePrefixes ( enteringStateName , exitingStateName ) {
539
+ var enteringStateSuffixIndex = enteringStateName . lastIndexOf ( '.' ) ;
540
+ var exitingStateSuffixIndex = exitingStateName . lastIndexOf ( '.' ) ;
541
+
542
+ // if either of the prefixes are empty, just return false
543
+ if ( enteringStateSuffixIndex < 0 || exitingStateSuffixIndex < 0 ) {
544
+ return false ;
545
+ }
546
+
547
+ var enteringPrefix = enteringStateName . substring ( 0 , enteringStateSuffixIndex ) ;
548
+ var exitingPrefix = exitingStateName . substring ( 0 , exitingStateSuffixIndex ) ;
549
+
550
+ return enteringPrefix === exitingPrefix ;
551
+ }
552
+
553
+ function getScopeForElement ( element , stateData ) {
554
+ if ( ! element ) {
555
+ return null ;
556
+ }
557
+ // check if it's abstract
558
+ var attributeValue = angular . element ( element ) . attr ( "abstract" ) ;
559
+ var stateValue = angular . element ( element ) . attr ( "state" ) ;
560
+
561
+ if ( attributeValue !== "true" ) {
562
+ // it's not an abstract view, so make sure the element
563
+ // matches the state. Due to abstract view weirdness,
564
+ // sometimes it doesn't. If it doesn't, don't dispatch events
565
+ // so leave the scope undefined
566
+ if ( stateValue === stateData . stateName ) {
567
+ return angular . element ( element ) . scope ( ) ;
568
+ }
569
+ return null ;
570
+ }
571
+ else {
572
+ // it is an abstract element, so look for element with the "state" attributeValue
573
+ // set to the name of the stateData state
574
+ var elements = aggregateNavViewChildren ( element ) ;
575
+ for ( var i = 0 ; i < elements . length ; i ++ ) {
576
+ var state = angular . element ( elements [ i ] ) . attr ( "state" ) ;
577
+ if ( state === stateData . stateName ) {
578
+ stateData . abstractView = true ;
579
+ return angular . element ( elements [ i ] ) . scope ( ) ;
580
+ }
581
+ }
582
+ // we didn't find a match, so return null
583
+ return null ;
584
+ }
585
+ }
586
+
587
+ function aggregateNavViewChildren ( element ) {
588
+ var aggregate = [ ] ;
589
+ var navViews = angular . element ( element ) . find ( "ion-nav-view" ) ;
590
+ for ( var i = 0 ; i < navViews . length ; i ++ ) {
591
+ var children = angular . element ( navViews [ i ] ) . children ( ) ;
592
+ var childrenAggregated = [ ] ;
593
+ for ( var j = 0 ; j < children . length ; j ++ ) {
594
+ childrenAggregated = childrenAggregated . concat ( children [ j ] ) ;
595
+ }
596
+ aggregate = aggregate . concat ( childrenAggregated ) ;
597
+ }
598
+ return aggregate ;
599
+ }
600
+
494
601
} ] ) ;
0 commit comments