delegates: add tabbar, update docs

This commit is contained in:
Andy Joslin
2014-03-24 20:35:55 -06:00
parent 621a355706
commit 5567b08c4b
10 changed files with 117 additions and 110 deletions

View File

@@ -165,6 +165,8 @@ angular.module('ionic.ui.scroll')
* @param {string} handle
* @returns `delegateInstance` A delegate instance that controls only the
* scrollViews with `delegate-handle` matching the given handle.
*
* Example: `$ionicScrollDelegate.getByHandle('my-handle').scrollTop();`
*/
]))

View File

@@ -11,18 +11,11 @@ angular.module('ionic.ui.header', ['ngAnimate', 'ngSanitize'])
* @name ionHeaderBar
* @module ionic
* @restrict E
* @controller ionicBar as $scope.$ionicHeaderBarController
*
* @description
* Adds a fixed header bar above some content.
*
* Is able to have left or right buttons, and additionally its title can be
* aligned through the {@link ionic.controller:ionicBar ionicBar controller}.
*
* @param {string=} controller-bind The scope variable to bind this header bar's
* {@link ionic.controller:ionicBar ionicBar controller} to.
* Default: $scope.$ionicHeaderBarController.
* @param {string=} align-title Where to align the title at the start.
* @param {string=} align-title Where to align the title.
* Avaialble: 'left', 'right', or 'center'. Defaults to 'center'.
*
* @usage
@@ -48,18 +41,11 @@ angular.module('ionic.ui.header', ['ngAnimate', 'ngSanitize'])
* @name ionFooterBar
* @module ionic
* @restrict E
* @controller ionicBar as $scope.$ionicFooterBarController
*
* @description
* Adds a fixed footer bar below some content.
*
* Is able to have left or right buttons, and additionally its title can be
* aligned through the {@link ionic.controller:ionicBar ionicBar controller}.
*
* @param {string=} controller-bind The scope variable to bind this footer bar's
* {@link ionic.controller:ionicBar ionicBar controller} to.
* Default: $scope.$ionicFooterBarController.
* @param {string=} align-title Where to align the title at the start.
* @param {string=} align-title Where to align the title.
* Avaialble: 'left', 'right', or 'center'. Defaults to 'center'.
*
* @usage
@@ -111,11 +97,12 @@ function tapScrollToTopDirective() {
function barDirective(isHeader) {
return ['$parse', function($parse) {
return [function($parse) {
return {
restrict: 'E',
compile: function($element, $attr) {
$element.addClass(isHeader ? 'bar bar-header' : 'bar bar-footer');
return { pre: prelink };
function prelink($scope, $element, $attr) {
var hb = new ionic.views.HeaderBar({
@@ -123,10 +110,6 @@ function barDirective(isHeader) {
alignTitle: $attr.alignTitle || 'center'
});
$parse($attr.controllerBind ||
(isHeader ? '$ionicHeaderBarController' : '$ionicFooterBarController')
).assign($scope, hb);
var el = $element[0];
//just incase header is on rootscope
var parentScope = $scope.$parent || $scope;

View File

@@ -19,15 +19,17 @@ angular.module('ionic.ui.navBar', ['ionic.service.view', 'ngSanitize'])
/**
* @ngdoc method
* @name $ionicNavBarDelegate#align
* @description Calls {@link ionic.controller:ionicBar#align ionicBar#align} for this navBar.
* @param {string=} direction The direction to the align the title text towards.
* @description Aligns the title with the buttons in a given direction.
* @param {string=} direction The direction to the align the title text towards.
* Available: 'left', 'right', 'center'. Default: 'center'.
*/
'align',
/**
* @ngdoc method
* @name $ionicNavBarDelegate#showBackButton
* @description
* Set whether the {@link ionic.directive:ionNavBackButton} should be shown (if it exists).
* Set whether the {@link ionic.directive:ionNavBackButton} should be shown
* (if it exists).
* @param {boolean} show Whether to show the back button.
*/
'showBackButton',

View File

@@ -85,7 +85,15 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.vie
* @name $ionicSideMenuDelegate#isOpenRight
* @returns {boolean} Whether the right menu is currently opened.
*/
'isOpenRight'
'isOpenRight',
/**
* @ngdoc method
* @name $ionicSideMenuDelegate#canDragContent
* @param {boolean=} canDrag Set whether the content can or cannot be dragged to open
* side menus.
* @returns {boolean} Whether the content can be dragged to open side menus.
*/
'canDragContent',
/**
* @ngdoc method
* @name $ionicSideMenuDelegate#getByHandle
@@ -93,6 +101,8 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.vie
* @returns `delegateInstance` A delegate instance that controls only the
* {@link ionic.directive:ionSideMenus} directives with `delegate-handle` matching
* the given handle.
*
* Example: `$ionicSideMenuDelegate.getByHandle('my-handle').toggleLeft();`
*/
]))
@@ -134,9 +144,9 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.vie
* </ion-side-menus>
* ```
* ```js
* function ContentController($scope) {
* function ContentController($scope, $ionicSideMenuDelegate) {
* $scope.toggleLeft = function() {
* $scope.$$ionicSideMenuDelegateController.toggleLeft();
* $ionicSideMenuDelegate.toggleLeft();
* };
* }
* ```
@@ -158,6 +168,13 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.vie
right: { width: 275 }
});
this.canDragContent = function(canDrag) {
if (arguments.length) {
$scope.dragContent = !!canDrag;
}
return $scope.dragContent;
};
$scope.sideMenuContentTranslateX = 0;
var deregisterInstance = $ionicSideMenuDelegate._registerInstance(
@@ -188,7 +205,7 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.vie
* @usage
* ```html
* <div ion-side-menu-content
* drag-content="canDragContent()">
* drag-content="canDrag">
* </div>
* ```
* For a complete side menu example, see the
@@ -210,10 +227,10 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.vie
if (angular.isDefined(attr.dragContent)) {
$scope.$watch(attr.dragContent, function(value) {
$scope.dragContent = value;
sideMenuCtrl.canDragContent(value);
});
} else {
$scope.dragContent = true;
sideMenuCtrl.canDragContent(true);
}
var defaultPrevented = false;

View File

@@ -68,6 +68,8 @@ angular.module('ionic.ui.slideBox', [])
* @returns `delegateInstance` A delegate instance that controls only the
* {@link ionic.directive:ionSlideBox} directives with `delegate-handle` matching
* the given handle.
*
* Example: `$ionicSlideBoxDelegate.getByHandle('my-handle').stop();`
*/
]))

View File

@@ -7,31 +7,57 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
}])
/**
* @ngdoc controller
* @name ionicTabs
* @ngdoc service
* @name $ionicTabsDelegate
* @module ionic
*
* @description
* Controller for the {@link ionic.directive:ionTabs} directive.
* Delegate for controlling the {@link ionic.directive:ionTabs} directive.
*
* Methods called directly on the $ionicTabsDelegate service will control all ionTabs
* directives. Use the {@link ionic.service:$ionicTabsDelegate#getByHandle getByHandle}
* method to control specific ionTabs instances.
*/
.service('$ionicTabsDelegate', delegateService([
/**
* @ngdoc method
* @name $ionicTabsDelegate#select
* @description Select the tab matching the given index.
*
* @param {number} index Index of the tab to select.
* @param {boolean=} shouldChangeHistory Whether this selection should load this tab's
* view history (if it exists) and use it, or just load the default page.
* Default false.
* Hint: you probably want this to be true if you have an
* {@link ionic.directive:ionNavView} inside your tab.
*/
'select',
/**
* @ngdoc method
* @name $ionicTabsDelegate#selectedTabIndex
* @returns `number` The index of the selected tab, or -1.
*/
'selectedIndex'
/**
* @ngdoc method
* @name $ionicTabsDelegate#getByHandle
* @param {string} handle
* @returns `delegateInstance` A delegate instance that controls only the
* {@link ionic.directive:ionTabs} directives with `delegate-handle` matching
* the given handle.
*
* Example: `$ionicTabsDelegate.getByHandle('my-handle').select(0);`
*/
]))
.controller('ionicTabs', ['$scope', '$ionicViewService', '$element', function($scope, $ionicViewService, $element) {
var _selectedTab = null;
var self = this;
self.tabs = [];
/**
* @ngdoc method
* @name ionicTabs#selectedTabIndex
* @returns `number` The index of the selected tab, or -1.
*/
self.selectedTabIndex = function() {
return self.tabs.indexOf(_selectedTab);
};
/**
* @ngdoc method
* @name ionicTabs#selectedTab
* @returns `ionTab` The selected tab or null if none selected.
*/
self.selectedTab = function() {
return _selectedTab;
};
@@ -72,17 +98,6 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
}
};
/**
* @ngdoc method
* @name ionicTabs#select
* @description Select the given tab or tab index.
*
* @param {ionTab|number} tabOrIndex A tab object or index of a tab to select
* @param {boolean=} shouldChangeHistory Whether this selection should load this tab's view history
* (if it exists) and use it, or just loading the default page. Default false.
* Hint: you probably want this to be true if you have an
* {@link ionic.directive:ionNavView} inside your tab.
*/
self.select = function(tab, shouldEmitEvent) {
var tabIndex;
if (angular.isNumber(tab)) {
@@ -132,7 +147,6 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
* @name ionTabs
* @module ionic
* @restrict E
* @controller ionicTabs as $scope.$ionicTabsController
* @codepen KbrzJ
*
* @description
@@ -161,15 +175,15 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
* <ion-tab title="Settings" icon-on="ion-ios7-gear" icon-off="ion-ios7-gear-outline">
* <!-- Tab 3 content -->
* </ion-tab>
*
* </ion-tabs>
* ```
*
* @param {string=} controller-bind The scope variable to bind these tabs'
* {@link ionic.controller:ionicTabs ionicTabs controller} to.
* Default: $scope.$ionicTabsController.
* @param {string=} delegate-handle The handle used to identify these tabs
* with {@link ionic.service:$ionicTabsDelegate}.
*/
.directive('ionTabs', ['$ionicViewService', '$parse', function($ionicViewService, $parse) {
.directive('ionTabs', ['$ionicViewService', '$ionicTabsDelegate', function($ionicViewService, $ionicTabsDelegate) {
return {
restrict: 'E',
scope: true,
@@ -183,7 +197,11 @@ angular.module('ionic.ui.tabs', ['ionic.service.view'])
return { pre: prelink };
function prelink($scope, $element, $attr, tabsCtrl) {
$parse(attr.model || '$ionicTabsController').assign($scope, tabsCtrl);
var deregisterInstance = $ionicTabsDelegate._registerInstance(
tabsCtrl, $attr.delegateHandle
);
$scope.$on('$destroy', deregisterInstance);
tabsCtrl.$scope = $scope;
tabsCtrl.$element = $element;
@@ -242,7 +260,7 @@ function($scope, $ionicViewService, $rootScope, $element) {
* @param {expression=} badge-style The style of badge to put on this tab (eg tabs-positive).
* @param {expression=} on-select Called when this tab is selected.
* @param {expression=} on-deselect Called when this tab is deselected.
* @param {expression=} ng-click By default, the tab will be selected on click. If ngClick is set, it will not. You can explicitly switch tabs using {@link ionic.controller:ionicTabs#select ionicTabBar controller's select method}.
* @param {expression=} ng-click By default, the tab will be selected on click. If ngClick is set, it will not. You can explicitly switch tabs using {@link ionic.service:$ionicTabsDelegate#select $ionicTabsDelegate.select()}.
*/
.directive('ionTab', ['$rootScope', '$animate', '$ionicBind', '$compile', '$ionicViewService',
function($rootScope, $animate, $ionicBind, $compile, $ionicViewService) {

View File

@@ -124,24 +124,6 @@ describe('bar directives', function() {
var el = setup();
expect(el.hasClass(data.className)).toBe(true);
});
it('should assign views.HeaderBar to default controllerBind', function() {
var el = setup();
expect(el.scope()[data.controllerBind] instanceof ionic.views.HeaderBar).toBe(true);
});
it('should assign views.HeaderBar to attr controllerBind', function() {
var el = setup('controller-bind="monkeys"');
expect(el.scope().monkeys instanceof ionic.views.HeaderBar).toBe(true);
});
it('should pass center to views.HeaderBar option by default', function() {
var el = setup();
expect(el.scope()[data.controllerBind].opts.alignTitle).toBe('center');
});
it('should pass attr.alignTitle to views.HeaderBar', function() {
var el = setup('align-title="left"');
expect(el.scope()[data.controllerBind].opts.alignTitle).toBe('left');
});
});
});
});

View File

@@ -5,7 +5,7 @@
describe('Ionic Angular Side Menu', function() {
var el;
beforeEach(module('ionic.ui.sideMenu'));
beforeEach(module('ionic'));
it('should register with $ionicSideMenuDelegate', inject(function($compile, $rootScope, $ionicSideMenuDelegate) {
var deregisterSpy = jasmine.createSpy('deregister');
@@ -23,6 +23,21 @@ describe('Ionic Angular Side Menu', function() {
el.scope().$destroy();
expect(deregisterSpy).toHaveBeenCalled();
}));
it('should canDragContent', inject(function($compile, $rootScope) {
var el = $compile('<ion-side-menus><div ion-side-menu-content></div></ion-side-menus>')($rootScope.$new());
$rootScope.$apply();
expect(el.controller('ionSideMenus').canDragContent()).toBe(true);
expect(el.scope().dragContent).toBe(true);
el.controller('ionSideMenus').canDragContent(false);
expect(el.controller('ionSideMenus').canDragContent()).toBe(false);
expect(el.scope().dragContent).toBe(false);
el.controller('ionSideMenus').canDragContent(true);
expect(el.controller('ionSideMenus').canDragContent()).toBe(true);
expect(el.scope().dragContent).toBe(true);
}));
});
describe('Ionic Side Menu Content Directive', function () {

View File

@@ -224,6 +224,22 @@ describe('tabs', function() {
return element;
}
it('should register with given handle and deregister on destroy', inject(function($ionicTabsDelegate) {
var deregisterSpy = jasmine.createSpy('deregister');
spyOn($ionicTabsDelegate, '_registerInstance').andCallFake(function() {
return deregisterSpy;
});
var el = setup('delegate-handle="banana"');
expect($ionicTabsDelegate._registerInstance)
.toHaveBeenCalledWith(el.controller('ionTabs'), 'banana');
expect(deregisterSpy).not.toHaveBeenCalled();
el.scope().$destroy();
expect(deregisterSpy).toHaveBeenCalled();
}));
it('should $hasTabs and $hasTabsTop', function() {
var el = setup();
var scope = el.scope();
@@ -239,18 +255,6 @@ describe('tabs', function() {
expect(scope.$hasTabsTop).toBe(false);
});
it('should bind controller to scope.$ionicTabsController by default', function() {
var el = setup();
expect(el.controller('ionTabs')).toBeTruthy(); //sanity
expect(el.scope().$ionicTabsController).toBe(el.controller('ionTabs'));
});
it('should bind controller to scope[attr.model]', function() {
var el = setup('model="superman"');
expect(el.controller('ionTabs')).toBeTruthy();
expect(el.scope().superman).toBe(el.controller('ionTabs'));
});
it('should transclude content with same scope', function() {
var el = setup('', '<div class="content"></div>');
expect(el[0].querySelector('.tabs .content')).toBeTruthy();

View File

@@ -1,14 +1,6 @@
(function(ionic) {
'use strict';
/**
* @ngdoc controller
* @name ionicBar
* @module ionic
* @description
* Controller for the {@link ionic.directive:ionHeaderBar} and
* {@link ionic.directive:ionFooterBar} directives.
*/
ionic.views.HeaderBar = ionic.views.View.inherit({
initialize: function(opts) {
this.el = opts.el;
@@ -20,16 +12,6 @@
this.align();
},
/**
* @ngdoc method
* @name ionicBar#align
* @description
* Aligns the title text with the buttons in the bar
* so that the title size is maximized and aligned correctly
* as much as possible.
* @param {string=} direction Which direction to align the title towards.
* Available: 'left', 'right', 'center'. Default: 'center'.
*/
align: function(align) {
align || (align = this.alignTitle);