mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
62
js/ext/angular/src/directive/ionicTabBar.js
vendored
62
js/ext/angular/src/directive/ionicTabBar.js
vendored
@@ -214,7 +214,8 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
|
||||
controller: 'ionicTabs',
|
||||
compile: function(element, attr) {
|
||||
element.addClass('view');
|
||||
//We cannot transclude here because it breaks element.data() inheritance on compile
|
||||
//We cannot use regular transclude here because it breaks element.data()
|
||||
//inheritance on compile
|
||||
var innerElement = angular.element('<div class="tabs"></div>');
|
||||
innerElement.append(element.contents());
|
||||
element.append(innerElement);
|
||||
@@ -246,9 +247,26 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('ionicTab', ['$scope', '$ionicViewService', '$rootScope', '$element',
|
||||
function($scope, $ionicViewService, $rootScope, $element) {
|
||||
.controller('ionicTab', ['$scope', '$ionicViewService', '$attrs', '$location', '$state',
|
||||
function($scope, $ionicViewService, $attrs, $location, $state) {
|
||||
this.$scope = $scope;
|
||||
|
||||
//All of these exposed for testing
|
||||
this.hrefMatchesState = function() {
|
||||
return $attrs.href && $location.path().indexOf(
|
||||
$attrs.href.replace(/^#/, '').replace(/\/$/, '')
|
||||
) === 0;
|
||||
};
|
||||
this.srefMatchesState = function() {
|
||||
return $attrs.uiSref && $state.includes( $attrs.uiSref.split('(')[0] );
|
||||
};
|
||||
this.navNameMatchesState = function() {
|
||||
return this.navViewName && $ionicViewService.isCurrentStateNavView(this.navViewName);
|
||||
};
|
||||
|
||||
this.tabMatchesState = function() {
|
||||
return this.hrefMatchesState() || this.srefMatchesState() || this.navNameMatchesState();
|
||||
};
|
||||
}])
|
||||
|
||||
/**
|
||||
@@ -300,27 +318,20 @@ function($rootScope, $animate, $ionicBind, $compile, $ionicViewService, $state,
|
||||
controller: 'ionicTab',
|
||||
scope: true,
|
||||
compile: function(element, attr) {
|
||||
//Do we have a navView?
|
||||
var navView = element[0].querySelector('ion-nav-view') ||
|
||||
var navView = element[0].querySelector('ion-nav-view') ||
|
||||
element[0].querySelector('data-ion-nav-view');
|
||||
var navViewName = navView && navView.getAttribute('name');
|
||||
|
||||
var tabNavItem = angular.element(
|
||||
element[0].querySelector('ion-tab-nav') ||
|
||||
element[0].querySelector('data-ion-tab-nav')
|
||||
).remove();
|
||||
|
||||
//Remove the contents of the element so we can compile them later, if tab is selected
|
||||
//We don't use regular transclusion because it breaks element inheritance
|
||||
var tabContent = angular.element('<div class="pane">')
|
||||
.append( element.contents().remove() );
|
||||
|
||||
return function link($scope, $element, $attr, ctrls) {
|
||||
var childScope, childElement, tabNavElement;
|
||||
tabsCtrl = ctrls[0],
|
||||
tabCtrl = ctrls[1];
|
||||
|
||||
//Remove title attribute so browser-tooltip does not apear
|
||||
$element[0].removeAttribute('title');
|
||||
|
||||
$ionicBind($scope, $attr, {
|
||||
animate: '=',
|
||||
onSelect: '&',
|
||||
@@ -337,10 +348,18 @@ function($rootScope, $animate, $ionicBind, $compile, $ionicViewService, $state,
|
||||
tabNavElement.remove();
|
||||
});
|
||||
|
||||
//Remove title attribute so browser-tooltip does not apear
|
||||
$element[0].removeAttribute('title');
|
||||
|
||||
if (navViewName) {
|
||||
$scope.navViewName = navViewName;
|
||||
$scope.$on('$stateChangeSuccess', selectTabIfMatchesState);
|
||||
selectTabIfMatchesState();
|
||||
tabCtrl.navViewName = navViewName;
|
||||
}
|
||||
$scope.$on('$stateChangeSuccess', selectIfMatchesState);
|
||||
selectIfMatchesState();
|
||||
function selectIfMatchesState() {
|
||||
if (tabCtrl.tabMatchesState()) {
|
||||
tabsCtrl.select($scope);
|
||||
}
|
||||
}
|
||||
|
||||
tabNavElement = angular.element(
|
||||
@@ -371,17 +390,6 @@ function($rootScope, $animate, $ionicBind, $compile, $ionicViewService, $state,
|
||||
}
|
||||
});
|
||||
|
||||
function selectTabIfMatchesState() {
|
||||
var href = $attr.href.replace(/^#/, '');
|
||||
var stateName = $attr.uiSref.split('(')[0];
|
||||
|
||||
if ($location.path().indexOf(href) === 0 || $state.includes(stateName)) {
|
||||
// this tab's ui-view is the current one, go to it!
|
||||
if ($ionicViewService.isCurrentStateNavView($scope.navViewName)) {
|
||||
tabsCtrl.select($scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
describe('tabs', function() {
|
||||
ddescribe('tabs', function() {
|
||||
|
||||
describe('miscellaneous', function() {
|
||||
beforeEach(module('ionic', function($provide) {
|
||||
@@ -261,12 +261,103 @@ describe('tabs', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ionTab directive', function() {
|
||||
describe('ionicTab controller', function() {
|
||||
beforeEach(module('ionic'));
|
||||
var tabsCtrl, tabsEl, scope;
|
||||
function setup(attrs) {
|
||||
var ctrl;
|
||||
inject(function($controller, $rootScope) {
|
||||
ctrl = $controller('ionicTab', {
|
||||
$scope: $rootScope.$new(),
|
||||
$attrs: attrs || {}
|
||||
});
|
||||
});
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
it('.hrefMatchesState', inject(function($location) {
|
||||
spyOn($location, 'path').andReturn('/a/b/c');
|
||||
var attr = {};
|
||||
var ctrl = setup(attr);
|
||||
|
||||
expect(ctrl.hrefMatchesState()).toBeFalsy();
|
||||
|
||||
attr.href = 'a';
|
||||
expect(ctrl.hrefMatchesState()).toBe(false);
|
||||
|
||||
attr.href = '/a';
|
||||
expect(ctrl.hrefMatchesState()).toBe(true);
|
||||
|
||||
attr.href = '#/a';
|
||||
expect(ctrl.hrefMatchesState()).toBe(true);
|
||||
|
||||
attr.href = '#/a/b/c';
|
||||
expect(ctrl.hrefMatchesState()).toBe(true);
|
||||
|
||||
attr.href = '#/a/b/c/';
|
||||
expect(ctrl.hrefMatchesState()).toBe(true);
|
||||
|
||||
attr.href = '/a/b/c/';
|
||||
expect(ctrl.hrefMatchesState()).toBe(true);
|
||||
|
||||
attr.href = '/a/b/c/d';
|
||||
expect(ctrl.hrefMatchesState()).toBe(false);
|
||||
|
||||
attr.href = 'something';
|
||||
expect(ctrl.hrefMatchesState()).toBe(false);
|
||||
}));
|
||||
|
||||
it('.srefMatchesState', inject(function($state) {
|
||||
spyOn($state, 'includes').andReturn(111);
|
||||
var attr = {};
|
||||
var ctrl = setup(attr);
|
||||
|
||||
expect(ctrl.srefMatchesState()).toBeFalsy();
|
||||
expect($state.includes).not.toHaveBeenCalled();
|
||||
|
||||
//We won't unit test $state.includes, only that it was called
|
||||
attr.uiSref = 'abc';
|
||||
expect(ctrl.srefMatchesState()).toBe(111);
|
||||
expect($state.includes).toHaveBeenCalledWith('abc');
|
||||
|
||||
$state.includes.reset();
|
||||
attr.uiSref = 'def({ param: "value" })';
|
||||
ctrl.srefMatchesState();
|
||||
expect($state.includes).toHaveBeenCalledWith('def');
|
||||
}));
|
||||
|
||||
it('.navNameMatchesState', inject(function($ionicViewService) {
|
||||
spyOn($ionicViewService, 'isCurrentStateNavView').andReturn(123);
|
||||
|
||||
var ctrl = setup();
|
||||
expect(ctrl.navNameMatchesState()).toBeFalsy();
|
||||
|
||||
ctrl.navViewName = 'foo';
|
||||
expect(ctrl.navNameMatchesState()).toBe(123);
|
||||
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('foo');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('ionTab directive', function() {
|
||||
var tabDoesMatch;
|
||||
beforeEach(module('ionic', function($controllerProvider) {
|
||||
$controllerProvider.register('ionicTab', function($scope) {
|
||||
this.$scope = $scope;
|
||||
this.tabMatchesState = jasmine.createSpy('tabMatchesState')
|
||||
.andCallFake(function() {
|
||||
return tabDoesMatch;
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
var tabsCtrl, tabsEl, scope, tabEl;
|
||||
function setup(attrs, content) {
|
||||
inject(function($compile, $rootScope) {
|
||||
tabsEl = angular.element('<ion-tabs><ion-tab '+(attrs||'')+'>'+(content||'')+'</ion-tab></ion-tabs>');
|
||||
tabsEl = angular.element(
|
||||
'<ion-tabs>' +
|
||||
'<ion-tab '+(attrs||'')+'>'+(content||'')+'</ion-tab>' +
|
||||
'</ion-tabs>'
|
||||
);
|
||||
tabEl = tabsEl.find('ion-tab');
|
||||
|
||||
$compile(tabsEl)($rootScope.$new());
|
||||
$rootScope.$apply();
|
||||
@@ -323,34 +414,50 @@ describe('tabs', function() {
|
||||
expect(navItem.parent().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not set navViewName if no child nav-view', function() {
|
||||
it('should not set navViewName by default', function() {
|
||||
setup();
|
||||
expect(tabsCtrl.tabs[0].navViewName).toBeUndefined();
|
||||
expect(tabEl.controller('ionTab').navViewName).toBeUndefined();
|
||||
});
|
||||
|
||||
angular.forEach(['ion-nav-view', 'data-ion-nav-view'], function(directive) {
|
||||
it('should set navViewName and select when necessary if a child '+directive, inject(function($ionicViewService, $rootScope) {
|
||||
var isCurrent = false;
|
||||
spyOn($ionicViewService, 'isCurrentStateNavView').andCallFake(function(name) {
|
||||
return isCurrent;
|
||||
});
|
||||
|
||||
it('should set navViewName if a child '+directive, inject(function($ionicViewService, $rootScope) {
|
||||
setup('', '<' + directive + ' name="banana"></' + directive + '>');
|
||||
spyOn(tabsCtrl, 'select');
|
||||
var tab = tabsCtrl.tabs[0];
|
||||
|
||||
expect(tab.navViewName).toBe('banana');
|
||||
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('banana');
|
||||
|
||||
$ionicViewService.isCurrentStateNavView.reset();
|
||||
isCurrent = true;
|
||||
$rootScope.$broadcast('$stateChangeSuccess');
|
||||
|
||||
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('banana');
|
||||
expect(tabsCtrl.select).toHaveBeenCalledWith(tab);
|
||||
expect(tabEl.controller('ionTab').navViewName).toBe('banana');
|
||||
}));
|
||||
});
|
||||
|
||||
it('should call tabMatchesState on compile and if match select', function() {
|
||||
setup();
|
||||
expect(tabEl.controller('ionTab').tabMatchesState).toHaveBeenCalled();
|
||||
|
||||
tabDoesMatch = true;
|
||||
setup();
|
||||
expect(tabEl.controller('ionTab').tabMatchesState).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call selectIfMatchesState on $stateChangeSuccess', function() {
|
||||
setup();
|
||||
var tabMatchesState = tabEl.controller('ionTab').tabMatchesState;
|
||||
|
||||
tabMatchesState.reset();
|
||||
spyOn(tabsCtrl, 'select');
|
||||
tabDoesMatch = false;
|
||||
|
||||
tabEl.scope().$broadcast('$stateChangeSuccess');
|
||||
expect(tabMatchesState).toHaveBeenCalled();
|
||||
expect(tabsCtrl.select).not.toHaveBeenCalled();
|
||||
|
||||
tabMatchesState.reset();
|
||||
tabDoesMatch = true;
|
||||
|
||||
tabEl.scope().$broadcast('$stateChangeSuccess');
|
||||
expect(tabMatchesState).toHaveBeenCalled();
|
||||
expect(tabsCtrl.select).toHaveBeenCalledWith(tabEl.scope());
|
||||
});
|
||||
|
||||
it('should transclude on $tabSelected=true', function() {
|
||||
setup('', '<div class="inside-content"></div>');
|
||||
var tab = tabsCtrl.tabs[0];
|
||||
|
||||
Reference in New Issue
Block a user