refactor(backButton): separate show/hide logic

This commit is contained in:
Adam Bradley
2014-11-26 12:46:14 -06:00
parent 17d0c5b852
commit 05fb7a09ea
7 changed files with 151 additions and 31 deletions

View File

@@ -23,6 +23,8 @@ function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
var titleCss = '';
var isBackEnabled = false;
var isBackShown = true;
var isNavBackShown = true;
var isBackElementShown = false;
var titleTextWidth = 0;
@@ -41,30 +43,45 @@ function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
};
self.enableBack = function(shouldEnable) {
self.enableBack = function(shouldEnable, disableReset) {
// 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' ]('back-disabled');
if (arguments.length) {
isBackEnabled = shouldEnable;
if (!disableReset) self.updateBackButton();
}
return isBackEnabled;
};
self.showBack = function(shouldShow) {
self.showBack = function(shouldShow, disableReset) {
// 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);
backBtnEle && backBtnEle.classList[ shouldShow ? 'remove' : 'add' ](HIDE);
if (arguments.length) {
isBackShown = shouldShow;
if (!disableReset) self.updateBackButton();
}
return isBackShown;
};
self.showNavBack = function(shouldShow) {
// different from showBack() because this is for the entire nav bar's
// setting for all of it's child headers. For internal use.
isNavBackShown = shouldShow;
self.updateBackButton();
};
self.updateBackButton = function() {
if ( (isBackShown && isNavBackShown && isBackEnabled) !== isBackElementShown) {
isBackElementShown = isBackShown && isNavBackShown && isBackEnabled;
var backBtnEle = getEle(BACK_BUTTON);
backBtnEle && backBtnEle.classList[ isBackElementShown ? 'remove' : 'add' ](HIDE);
}
};
self.titleTextWidth = function() {
if (!titleTextWidth) {
var bounds = ionic.DomUtil.getTextBounds(getEle(TITLE));
@@ -320,7 +337,7 @@ function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) {
var eleCache = {};
function getEle(className) {
if (!eleCache[className]) {
if (!isDefined(eleCache[className])) {
eleCache[className] = $element[0].querySelector('.' + className);
}
return eleCache[className];

View File

@@ -82,12 +82,6 @@ function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $io
var headerBarInstance = {
isActive: isActive,
enableBack: function(shouldEnable) {
headerBarCtrl.enableBack(shouldEnable);
},
showBack: function(shouldShow) {
headerBarCtrl.showBack(shouldShow);
},
title: function(newTitleText) {
headerBarCtrl.title(newTitleText);
},
@@ -215,10 +209,12 @@ function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $io
self.enable(showNavBar);
var enteringHeaderBar = self.isInitialized ? getOffScreenHeaderBar() : getOnScreenHeaderBar();
var leavingHeaderBar = self.isInitialized ? getOnScreenHeaderBar() : null;
var enteringHeaderCtrl = enteringHeaderBar.controller();
// update if the entering header should show the back button or not
self.enableBackButton(viewData.enableBack, enteringHeaderBar);
self.showBackButton(viewData.showBack, enteringHeaderBar);
enteringHeaderCtrl.enableBack(viewData.enableBack, true);
enteringHeaderCtrl.showBack(viewData.showBack, true);
enteringHeaderCtrl.updateBackButton();
// update the entering header bar's title
self.title(viewData.title, enteringHeaderBar);
@@ -335,17 +331,31 @@ function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $io
};
self.enableBackButton = function(shouldEnable, headerBar) {
headerBar = headerBar || getOnScreenHeaderBar();
headerBar && headerBar.enableBack(shouldEnable);
/**
* @ngdoc method
* @name $ionicNavBar#showBackButton
* @description Show/hide the nav bar back button when there is a
* back view. If the back button is not possible, for example, the
* first view in the stack, then this will not force the back button
* to show.
*/
self.showBackButton = function(shouldShow) {
for (var x = 0; x < headerBars.length; x++) {
headerBars[x].controller().showNavBack(!!shouldShow);
}
$scope.$isBackButtonShown = !!shouldShow;
return $scope.$isBackButtonShown;
};
self.showBackButton = function(shouldShow, headerBar) {
headerBar = headerBar || getOnScreenHeaderBar();
headerBar && headerBar.showBack(shouldShow);
$scope.$isBackButtonShown = !!shouldShow;
return !!shouldShow;
/**
* @ngdoc method
* @name $ionicNavBar#showActiveBackButton
* @description Show/hide only the active header bar's back button.
*/
self.showActiveBackButton = function(shouldShow) {
var headerBar = getOnScreenHeaderBar();
headerBar && headerBar.controller().showBack(shouldShow);
};

View File

@@ -202,15 +202,29 @@ function($scope, $element, $attrs, $compile, $controller, $ionicNavBarDelegate,
};
/**
* @ngdoc method
* @name $ionicNavView#enableBackButton
* @description Enable/disable if the back button can be shown or not. For
* example, the very first view in the navigation stack would not have a
* back view, so the back button would be disabled.
*/
self.enableBackButton = function(shouldEnable) {
var associatedNavBarCtrl = getAssociatedNavBarCtrl();
associatedNavBarCtrl && associatedNavBarCtrl.enableBackButton(shouldEnable);
};
/**
* @ngdoc method
* @name $ionicNavView#showBackButton
* @description Show/hide the nav bar active back button. If the back button
* is not possible this will not force the back button to show. The
* `enableBackButton()` method handles if a back button is even possible or not.
*/
self.showBackButton = function(shouldShow) {
var associatedNavBarCtrl = getAssociatedNavBarCtrl();
associatedNavBarCtrl && associatedNavBarCtrl.showBackButton(shouldShow);
associatedNavBarCtrl && associatedNavBarCtrl.showActiveBackButton(shouldShow);
};

View File

@@ -71,7 +71,7 @@ IonicModule
buttonEle.setAttribute('ng-click', '$ionicGoBack($event)');
}
buttonEle.className = 'button back-button back-disabled buttons ' + (tElement.attr('class') || '');
buttonEle.className = 'button back-button hide buttons ' + (tElement.attr('class') || '');
buttonEle.innerHTML = tElement.html() || '';
var childNode;

View File

@@ -361,7 +361,6 @@
z-index: $z-index-bar;
}
.bar .back-button.back-disabled,
.bar .back-button.hide,
.bar .buttons .hide {
display: none;

View File

@@ -1,14 +1,15 @@
describe('$ionicNavBar controller', function() {
beforeEach(module('ionic'));
var scope;
var scope, ele;
function makeNavBarCtrl(css) {
var ctrl;
ele = angular.element('<div>');
inject(function($rootScope, $controller, $ionicHistory, $ionicViewSwitcher) {
scope = $rootScope.$new();
ctrl = $controller('$ionicNavBar', {
$scope: scope,
$element: angular.element('<div>'),
$element: ele,
$attrs: { class: css },
$ionicHistory: $ionicHistory,
$ionicViewSwitcher: $ionicViewSwitcher
@@ -253,4 +254,83 @@ describe('$ionicNavBar controller', function() {
expect(backButtonEle.text()).toBe(scope.buttonText);
});
it('should show the active back button on update() w/ showBack false', function() {
var ctrl = makeNavBarCtrl();
ctrl.navElement('backButton', '<button class="back-button hide"></button>');
ctrl.init();
ctrl.update({
enableBack: true,
showBack: false
});
var backButtonEle1 = ele[0].querySelector('[nav-bar]:first-child .back-button');
var backButtonEle2 = ele[0].querySelector('[nav-bar]:last-child .back-button');
expect(backButtonEle1.classList.contains('hide')).toBe(true);
expect(backButtonEle2.classList.contains('hide')).toBe(true);
ctrl.update({
enableBack: true,
showBack: true
});
expect(backButtonEle1.classList.contains('hide')).toBe(false);
expect(backButtonEle2.classList.contains('hide')).toBe(true);
});
it('should not show the back button on update() w/ enableBack false', function() {
var ctrl = makeNavBarCtrl();
ctrl.navElement('backButton', '<button class="back-button hide"></button>');
ctrl.init();
ctrl.update({
enableBack: false,
showBack: true
});
var backButtonEle1 = ele[0].querySelector('[nav-bar]:first-child .back-button');
var backButtonEle2 = ele[0].querySelector('[nav-bar]:last-child .back-button');
expect(backButtonEle1.classList.contains('hide')).toBe(true);
expect(backButtonEle2.classList.contains('hide')).toBe(true);
ctrl.update({
enableBack: true,
showBack: true
});
expect(backButtonEle1.classList.contains('hide')).toBe(false);
expect(backButtonEle2.classList.contains('hide')).toBe(true);
});
it('should always hide the back buttons on showBackButton(false)', function() {
var ctrl = makeNavBarCtrl();
ctrl.navElement('backButton', '<button class="back-button hide"></button>');
ctrl.init();
ctrl.showBackButton(false);
ctrl.update({
enableBack: true,
showBack: true
});
var backButtonEle1 = ele[0].querySelector('[nav-bar]:first-child .back-button');
var backButtonEle2 = ele[0].querySelector('[nav-bar]:last-child .back-button');
expect(backButtonEle1.classList.contains('hide')).toBe(true);
expect(backButtonEle2.classList.contains('hide')).toBe(true);
ctrl.showBackButton(true);
ctrl.update({
enableBack: true,
showBack: true
});
expect(backButtonEle1.classList.contains('hide')).toBe(false);
expect(backButtonEle2.classList.contains('hide')).toBe(false);
ctrl.update({
enableBack: false,
showBack: true
});
expect(backButtonEle1.classList.contains('hide')).toBe(true);
expect(backButtonEle2.classList.contains('hide')).toBe(false);
});
});

View File

@@ -34,7 +34,7 @@ describe('ionNavBackButton directive', function() {
expect( outputEle[0].tagName ).toBe('BUTTON');
expect( outputEle.hasClass('button') ).toBe(true);
expect( outputEle.hasClass('back-button') ).toBe(true);
expect( outputEle.hasClass('back-disabled') ).toBe(true);
expect( outputEle.hasClass('hide') ).toBe(true);
expect( outputEle.hasClass('buttons') ).toBe(true);
}));