Skip to content

Commit

Permalink
fix(viewSwitcher): do not finish transition from bubbled transitionen…
Browse files Browse the repository at this point in the history
…d events

Closes #3006. Closes #3063.
  • Loading branch information
ajoslin committed Feb 9, 2015
1 parent 83cc181 commit 6fa75b7
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 5 deletions.
3 changes: 2 additions & 1 deletion js/angular/controller/navViewController.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function($scope, $element, $attrs, $compile, $controller, $ionicNavBarDelegate,
var transitionDuration, transitionTiming;

self.scope = $scope;
self.element = $element;

self.init = function() {
var navViewName = $attrs.name || '';
Expand Down Expand Up @@ -399,7 +400,7 @@ function($scope, $element, $attrs, $compile, $controller, $ionicNavBarDelegate,
ionic.offGesture(deregDragStart, 'dragstart', onDragStart);
ionic.offGesture(deregDrag, 'drag', onDrag);
ionic.offGesture(deregRelease, 'release', onRelease);
viewTransition = associatedNavBarCtrl = null;
self.element = viewTransition = associatedNavBarCtrl = null;
});
};

Expand Down
20 changes: 16 additions & 4 deletions js/angular/service/viewSwitcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe

if (viewTransition.shouldAnimate) {
// attach transitionend events (and fallback timer)
enteringEle.on(TRANSITIONEND_EVENT, transitionComplete);
enteringEle.on(TRANSITIONEND_EVENT, completeOnTransitionEnd);
enteringEle.data(DATA_FALLBACK_TIMER, $timeout(transitionComplete, defaultTimeout));
$ionicClickBlock.show(defaultTimeout);
}
Expand Down Expand Up @@ -209,7 +209,7 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
run: viewTransition.run,
cancel: function(shouldAnimate) {
if (shouldAnimate) {
enteringEle.on(TRANSITIONEND_EVENT, cancelTransition);
enteringEle.on(TRANSITIONEND_EVENT, cancelOnTransitionEnd);
enteringEle.data(DATA_FALLBACK_TIMER, $timeout(cancelTransition, defaultTimeout));
$ionicClickBlock.show(defaultTimeout);
} else {
Expand Down Expand Up @@ -248,11 +248,17 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
}
}

// Make sure that transitionend events bubbling up from children won't fire
// transitionComplete. Will only go forward if ev.target == the element listening.
function completeOnTransitionEnd(ev) {
if (ev.target !== this) return;
transitionComplete();
}
function transitionComplete() {
if (transitionComplete.x) return;
transitionComplete.x = true;

enteringEle.off(TRANSITIONEND_EVENT, transitionComplete);
enteringEle.off(TRANSITIONEND_EVENT, completeOnTransitionEnd);
$timeout.cancel(enteringEle.data(DATA_FALLBACK_TIMER));
leavingEle && $timeout.cancel(leavingEle.data(DATA_FALLBACK_TIMER));

Expand All @@ -279,10 +285,16 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
nextTransition = nextDirection = enteringView = leavingView = enteringEle = leavingEle = null;
}

// Make sure that transitionend events bubbling up from children won't fire
// transitionComplete. Will only go forward if ev.target == the element listening.
function cancelOnTransitionEnd(ev) {
if (ev.target !== this) return;
cancelTransition();
}
function cancelTransition() {
navViewAttr(enteringEle, VIEW_STATUS_CACHED);
navViewAttr(leavingEle, VIEW_STATUS_ACTIVE);
enteringEle.off(TRANSITIONEND_EVENT, cancelTransition);
enteringEle.off(TRANSITIONEND_EVENT, cancelOnTransitionEnd);
$timeout.cancel(enteringEle.data(DATA_FALLBACK_TIMER));
ionicViewSwitcher.transitionEnd([navViewCtrl]);
}
Expand Down
1 change: 1 addition & 0 deletions js/utils/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@
}
}
}

};

//Shortcuts
Expand Down
54 changes: 54 additions & 0 deletions test/unit/angular/service/viewSwitcher.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,58 @@ describe('Ionic View Switcher', function() {
expect(switcher.enteringEle().data('$accessed')).toBeDefined();
}));

it('should end the transition on transitionend', inject(function($ionicViewSwitcher, $rootScope, $ionicConfig, $compile) {
$ionicConfig.views.transition('test');
$ionicConfig.transitions.views.test = function() {
return { run: angular.noop, shouldAnimate: true };
};
var afterEnterSpy = jasmine.createSpy('afterEnter');
var navViewCtrl = setup();
var enteringEle = $compile('<enter>')($rootScope);
navViewCtrl.element.append(enteringEle);

enteringEle.data('$eleId', 'foo');
var switcher = $ionicViewSwitcher.create(navViewCtrl, {}, {
viewId: 'foo'
});

switcher.loadViewElements({});
$rootScope.$on('$ionicView.afterEnter', afterEnterSpy);
switcher.transition('forward');

expect(afterEnterSpy).not.toHaveBeenCalled();
enteringEle.triggerHandler('transitionend');
expect(afterEnterSpy).toHaveBeenCalled();
}));

it('should not end the transition on bubbled transitionend', inject(function($ionicViewSwitcher, $rootScope, $ionicConfig, $compile) {
$ionicConfig.views.transition('test');
$ionicConfig.transitions.views.test = function() {
return { run: angular.noop, shouldAnimate: true };
};
var afterEnterSpy = jasmine.createSpy('afterEnter');
var navViewCtrl = setup();
var enteringEle = $compile('<enter>')($rootScope);
navViewCtrl.element.append(enteringEle);

var enteringEleChild = angular.element('<child>');
enteringEle.append(enteringEleChild);

enteringEle.data('$eleId', 'foo');
var switcher = $ionicViewSwitcher.create(navViewCtrl, {}, {
viewId: 'foo'
});

switcher.loadViewElements({});
$rootScope.$on('$ionicView.afterEnter', afterEnterSpy);
switcher.transition('forward');

expect(afterEnterSpy).not.toHaveBeenCalled();
enteringEle.triggerHandler({
type: 'transitionend',
target: enteringEleChild[0]
});
expect(afterEnterSpy).not.toHaveBeenCalled();
}));

});

0 comments on commit 6fa75b7

Please sign in to comment.