refactor(backButton): separate show/enable logic

Previously the showBack property was setting if the back button should
or should not be enabled, and it was also used if the back button
should be hidden or not for the view. Changed it so there are now two
concepts, where showBack is visual only, and enableBack determines if
it should show according to $ionicHistory and navigation info.
This commit is contained in:
Adam Bradley
2014-11-19 11:38:14 -06:00
parent 387b1eef79
commit b4e4055a06
11 changed files with 68 additions and 42 deletions

View File

@@ -21,7 +21,8 @@ function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
var titleLeft = 0;
var titleRight = 0;
var titleCss = '';
var isBackShown;
var isBackEnabled = false;
var isBackShown = false;
var titleTextWidth = 0;
@@ -40,13 +41,25 @@ function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
};
self.enableBack = function(shouldEnable) {
// whether or not the back button show be visible, according
// to the navigation and history
if (arguments.length && shouldEnable !== isBackEnabled) {
var backBtnEle = getEle(BACK_BUTTON);
backBtnEle && backBtnEle.classList[ shouldEnable ? 'remove' : 'add' ](HIDE);
isBackEnabled = shouldEnable;
}
return isBackEnabled;
};
self.showBack = function(shouldShow) {
// different from enableBack() because this will always have the back
// visually hidden if false, even if the history says it should show
if (arguments.length && shouldShow !== isBackShown) {
var backBtnEle = getEle(BACK_BUTTON);
if (backBtnEle) {
backBtnEle.classList[ shouldShow ? 'remove' : 'add' ](HIDE);
isBackShown = shouldShow;
}
if (backBtnEle) backBtnEle.style.display = (shouldShow ? '' : 'none');
isBackShown = shouldShow;
}
return isBackShown;
};
@@ -109,6 +122,7 @@ function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
defaultTitleEle.classList.remove(HIDE);
}
}
self.showBack(true);
};

View File

@@ -77,6 +77,9 @@ function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $io
var headerBarInstance = {
isActive: isActive,
enableBack: function(shouldEnable) {
headerBarCtrl.enableBack(shouldEnable);
},
showBack: function(shouldShow) {
headerBarCtrl.showBack(shouldShow);
},
@@ -209,6 +212,7 @@ function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $io
var leavingHeaderBar = self.isInitialized ? getOnScreenHeaderBar() : null;
// update if the entering header should show the back button or not
self.enableBackButton(viewData.enableBack, enteringHeaderBar);
self.showBackButton(viewData.showBack, enteringHeaderBar);
// update the entering header bar's title
@@ -326,11 +330,17 @@ function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $io
};
self.showBackButton = function(show, headerBar) {
self.enableBackButton = function(shouldEnable, headerBar) {
headerBar = headerBar || getOnScreenHeaderBar();
headerBar && headerBar.showBack(show);
$scope.$isBackButtonShown = !!show;
return !!show;
headerBar && headerBar.enableBack(shouldEnable);
};
self.showBackButton = function(shouldShow, headerBar) {
headerBar = headerBar || getOnScreenHeaderBar();
headerBar && headerBar.showBack(shouldShow);
$scope.$isBackButtonShown = !!shouldShow;
return !!shouldShow;
};

View File

@@ -89,7 +89,7 @@ function($scope, $element, $attrs, $ionicNavBarDelegate, $ionicHistory, $ionicVi
// the view is now compiled, in the dom and linked, now lets transition the views.
// this uses a callback incase THIS nav-view has a nested nav-view, and after the NESTED
// nav-view links, the NESTED nav-view would update which direction THIS nav-view should use
switcher.transition(self.direction(), registerData.showBack);
switcher.transition(self.direction(), registerData.enableBack);
});
};
@@ -111,9 +111,15 @@ function($scope, $element, $attrs, $ionicNavBarDelegate, $ionicHistory, $ionicVi
};
self.showBackButton = function(val) {
self.enableBackButton = function(shouldEnable) {
var associatedNavBarCtrl = getAssociatedNavBarCtrl();
associatedNavBarCtrl && associatedNavBarCtrl.showBackButton(val);
associatedNavBarCtrl && associatedNavBarCtrl.enableBackButton(shouldEnable);
};
self.showBackButton = function(shouldShow) {
var associatedNavBarCtrl = getAssociatedNavBarCtrl();
associatedNavBarCtrl && associatedNavBarCtrl.showBackButton(shouldShow);
};

View File

@@ -54,7 +54,8 @@ function($scope, $element, $attrs, $compile, $ionicViewSwitcher) {
transition: transData.transition,
transitionId: transData.transitionId,
shouldAnimate: transData.shouldAnimate,
showBack: transData.showBack && !attrTrue('hideBackButton'),
enableBack: transData.enableBack,
showBack: !attrTrue('hideBackButton'),
buttons: buttons,
navBarDelegate: navBarDelegateHandle || null,
showNavBar: !attrTrue('hideNavBar'),
@@ -111,7 +112,7 @@ function($scope, $element, $attrs, $compile, $ionicViewSwitcher) {
function attrTrue(key) {
return $attrs[key] == 'true' || $attrs[key] === '';
return !!$scope.$eval($attrs[key]);
}

View File

@@ -26,7 +26,7 @@ IonicModule
restrict: 'AC',
link: function($scope, $element, $attr) {
$scope.$on('$ionicView.beforeEnter', function(ev, viewData) {
if (viewData.showBack) {
if (viewData.enableBack) {
var sideMenuCtrl = $element.inheritedData('$ionSideMenusController');
if (!sideMenuCtrl.enableMenuWithBackViews()) {
$element.addClass('hide');

View File

@@ -406,7 +406,7 @@ function($rootScope, $state, $location, $window, $ionicViewSwitcher) {
action: action,
direction: direction,
historyId: historyId,
showBack: !!(viewHistory.backView && viewHistory.backView.historyId === viewHistory.currentView.historyId),
enableBack: !!(viewHistory.backView && viewHistory.backView.historyId === viewHistory.currentView.historyId),
isHistoryRoot: (viewHistory.currentView.index === 0),
ele: ele
};

View File

@@ -40,7 +40,7 @@ IonicModule
* @name $ionicNavBarDelegate#showBackButton
* @description
* Set/get whether the {@link ionic.directive:ionNavBackButton} is shown
* (if it exists).
* (if it exists and there is a previous view that can be navigated to).
* @param {boolean=} show Whether to show the back button.
* @returns {boolean} Whether the back button is shown.
*/

View File

@@ -46,7 +46,7 @@ function($timeout, $compile, $controller, $document, $ionicClickBlock, $ionicCon
return locals && locals.$$state && locals.$$state.self || {};
}
function getTransitionData(viewLocals, enteringEle, direction, showBack, view) {
function getTransitionData(viewLocals, enteringEle, direction, enableBack, view) {
// Priority
// 1) attribute directive on the button/link to this view
// 2) entering element's attribute
@@ -63,7 +63,7 @@ function($timeout, $compile, $controller, $document, $ionicClickBlock, $ionicCon
transition: transition,
direction: direction,
shouldAnimate: (transition !== 'none' && direction !== 'none'),
showBack: !!showBack
enableBack: !!enableBack
});
}
@@ -207,8 +207,8 @@ function($timeout, $compile, $controller, $document, $ionicClickBlock, $ionicCon
$timeout(callback, 16);
},
transition: function(direction, showBack) {
var enteringData = getTransitionData(viewLocals, enteringEle, direction, showBack, enteringView);
transition: function(direction, enableBack) {
var enteringData = getTransitionData(viewLocals, enteringEle, direction, enableBack, enteringView);
var leavingData = extend(extend({}, enteringData), getViewData(leavingView));
enteringData.transitionId = leavingData.transitionId = transitionId;
enteringData.fromCache = !!alreadyInDom;

View File

@@ -13,6 +13,7 @@ describe('ionView directive', function() {
beforeEnter: function(d) { beforeEnterData = d; },
title: jasmine.createSpy('title'),
showBar: jasmine.createSpy('showBar'),
enableBackButton: jasmine.createSpy('enableBackButton'),
showBackButton: jasmine.createSpy('showBackButton')
});
content && el.html(content);
@@ -47,19 +48,13 @@ describe('ionView directive', function() {
expect(el.html()).toBe('<b>some</b> html');
});
it('should call ionNavViewController.beforeEnter with showNavBar=false and hide-nav-bar=true attr', inject(function($rootScope) {
it('should call ionNavViewController.beforeEnter with showNavBar=false w/ hide-nav-bar="true" attr', inject(function($rootScope) {
var el = setup('hide-nav-bar="true"');
$rootScope.$broadcast('$ionicView.beforeEnter', {});
expect( beforeEnterData.showNavBar ).toBe(false);
}));
it('should call ionNavViewController.beforeEnter with showNavBar=false and hide-nav-bar="" attr', inject(function($rootScope) {
var el = setup('hide-nav-bar');
$rootScope.$broadcast('$ionicView.beforeEnter', {});
expect( beforeEnterData.showNavBar ).toBe(false);
}));
it('should call ionNavViewController.beforeEnter with showNavBar=true and hide-nav-bar=false attr', inject(function($rootScope) {
it('should call ionNavViewController.beforeEnter with showNavBar=true and hide-nav-bar="false" attr', inject(function($rootScope) {
var el = setup('hide-nav-bar="false"');
$rootScope.$broadcast('$ionicView.beforeEnter', {});
expect( beforeEnterData.showNavBar ).toBe(true);
@@ -83,27 +78,27 @@ describe('ionView directive', function() {
expect( beforeEnterData.title ).toBe('my title');
}));
it('should not showBack with hide-back-button attr', inject(function($rootScope) {
it('should not enableBack with hide-back-button attr', inject(function($rootScope) {
var el = setup('hide-back-button="true"');
$rootScope.$broadcast('$ionicView.beforeEnter', {
showBack: true
enableBack: true
});
expect( beforeEnterData.showBack ).toBe(false);
$rootScope.shouldShowBack = false;
var el = setup('hide-back-button="shouldShowBack"');
$rootScope.$broadcast('$ionicView.beforeEnter', {
showBack: true
enableBack: true
});
expect( beforeEnterData.showBack ).toBe(false);
}));
it('should showBack without hide-back-button but no showBack from transition', inject(function($rootScope) {
it('should enableBack without hide-back-button but no enableBack from transition', inject(function($rootScope) {
var el = setup();
$rootScope.$broadcast('$ionicView.beforeEnter', {
showBack: false
enableBack: false
});
expect( beforeEnterData.showBack ).toBe(false);
expect( beforeEnterData.enableBack ).toBe(false);
}));
it('should be receive delegateHandle from child ionNavBar', inject(function($rootScope) {

View File

@@ -1005,7 +1005,7 @@ describe('Ionic History', function() {
rootScope.$apply();
var infoReg = ionicHistory.register({}, false);
expect(infoReg.direction).toEqual('none');
expect(infoReg.showBack).toEqual(true);
expect(infoReg.enableBack).toEqual(true);
expect(ionicHistory.viewHistory().histories[infoReg.historyId].stack.length).toEqual(2);
expect(ionicHistory.viewHistory().backView.viewId).toBe(homeReg.viewId);
}));
@@ -1021,7 +1021,7 @@ describe('Ionic History', function() {
$state.go('info');
rootScope.$apply();
var infoReg = ionicHistory.register({}, false);
expect(infoReg.showBack).toEqual(false);
expect(infoReg.enableBack).toEqual(false);
expect(infoReg.direction).toEqual('forward');
expect(ionicHistory.viewHistory().histories[infoReg.historyId].stack.length).toEqual(2);
expect(ionicHistory.viewHistory().backView).toBe(null);
@@ -1038,7 +1038,7 @@ describe('Ionic History', function() {
$state.go('info');
rootScope.$apply();
var infoReg = ionicHistory.register({}, false);
expect(infoReg.showBack).toEqual(false);
expect(infoReg.enableBack).toEqual(false);
expect(infoReg.direction).toEqual('forward');
expect(ionicHistory.viewHistory().histories[infoReg.historyId].stack.length).toEqual(1);
expect(ionicHistory.viewHistory().backView).toBe(null);

View File

@@ -79,15 +79,15 @@ describe('Ionic View Switcher', function() {
expect(d.direction).toEqual('forward');
}));
it('should set showBack when the view data sets it', inject(function($ionicViewSwitcher) {
it('should set enableBack when the view data sets it', inject(function($ionicViewSwitcher) {
var d = $ionicViewSwitcher.getTransitionData(null, null, null, true);
expect(d.showBack).toEqual(true);
expect(d.enableBack).toEqual(true);
d = $ionicViewSwitcher.getTransitionData(null, null, null, false);
expect(d.showBack).toEqual(false);
expect(d.enableBack).toEqual(false);
d = $ionicViewSwitcher.getTransitionData(null, null, null, null);
expect(d.showBack).toEqual(false);
expect(d.enableBack).toEqual(false);
}));
it('should get an empty entering element with an empty navViewElement', inject(function($ionicViewSwitcher) {