diff --git a/js/ext/angular/src/directive/ionicBar.js b/js/ext/angular/src/directive/ionicBar.js index c07c67b3be..25bfb2ac9f 100644 --- a/js/ext/angular/src/directive/ionicBar.js +++ b/js/ext/angular/src/directive/ionicBar.js @@ -18,108 +18,98 @@ angular.module('ionic.ui.header', ['ngAnimate', 'ngSanitize']) * @name ionHeaderBar * @module ionic * @restrict E + * @controller ionicBar + * * @description - * While Ionic provides simple Header and Footer bars that can be created through - * HTML and CSS alone, Header bars specifically can be extended in order to - * provide dynamic layout features such as auto-title centering and animation. - * They are also used by the Views and Navigation Controller to animate a title - * on navigation and toggle a back button. + * Adds a fixed header bar above some content. * - * The main header bar feature provided is auto title centering. - * In this situation, the title text will center itself until either the - * left or right button content is too wide for the label to center. - * In that case, it will slide left or right until it can fit. - * You can also align the title left for a more Android-friendly header. + * Is able to have left or right buttons, and additionally its title can be + * aligned through the {@link ionic.controller:ionicBar ionicBar controller}. * - * Using two-way data binding, the header bar will automatically - * readjust the heading title alignment when the title or buttons change. - * - * @param {string} title The title use on the headerBar. - * @param {expression=} leftButtons Point to an array of buttons to put on the left of the bar. - * @param {expression=} rightButtons Point to an array of buttons to put on the right of the bar. - * @param {string=} type The type of the bar, for example 'bar-positive'. - * @param {string=} align Where to align the title. 'left', 'right', or 'center'. Defaults to 'center'. + * @param {string=} model The model to assign this headerBar's + * {@link ionic.controller:ionicBar ionicBar controller} to. + * Defaults to assigning to $scope.headerBarController. + * @param {string=} align-title Where to align the title at the start. + * Avaialble: 'left', 'right', or 'center'. Defaults to 'center'. * * @usage * ```html - * + * + *
+ * + *
+ *

Title!

+ *
+ * + *
*
+ * + * Some content! + * * ``` - * */ -.directive('ionHeaderBar', ['$ionicScrollDelegate', function($ionicScrollDelegate) { - return { - restrict: 'E', - replace: true, - transclude: true, - template: '
\ -
\ - \ -
\ -

\ -
\ - \ -
\ -
', +.directive('ionHeaderBar', barDirective(true)) - scope: { - leftButtons: '=', - rightButtons: '=', - title: '@', - type: '@', - alignTitle: '@' - }, - link: function($scope, $element, $attr) { - var hb = new ionic.views.HeaderBar({ - el: $element[0], - alignTitle: $scope.alignTitle || 'center' - }); +/** + * @ngdoc directive + * @name ionFooterBar + * @module ionic + * @restrict E + * @controller ionicBar + * + * @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=} model The model to assign this footerBar's + * {@link ionic.controller:ionicBar ionicBar controller} to. + * Defaults to assigning to $scope.footerBarController. + * @param {string=} align-title Where to align the title at the start. + * Avaialble: 'left', 'right', or 'center'. Defaults to 'center'. + * + * @usage + * ```html + * + * Some content! + * + * + *
+ * + *
+ *

Title!

+ *
+ * + *
+ *
+ * ``` + */ +.directive('ionFooterBar', barDirective(false)); - $element.addClass($scope.type); +function barDirective(isHeader) { + var BAR_TEMPLATE = isHeader ? + '
' : + ''; + var BAR_MODEL_DEFAULT = isHeader ? + 'headerBarController' : + 'footerBarController'; + return ['$parse', function($parse) { + return { + restrict: 'E', + replace: true, + transclude: true, + template: BAR_TEMPLATE, + link: function($scope, $element, $attr) { + var hb = new ionic.views.HeaderBar({ + el: $element[0], + alignTitle: $attr.alignTitle || 'center' + }); - $scope.headerBarView = hb; - - $scope.$watchCollection('leftButtons', function(val) { - // Resize the title since the buttons have changed - hb.align(); - }); - - $scope.$watchCollection('rightButtons', function(val) { - // Resize the title since the buttons have changed - hb.align(); - }); - - $scope.$watch('title', function(val) { - // Resize the title since the title has changed - hb.align(); - }); - } - }; -}]) - -.directive('ionFooterBar', function() { - return { - restrict: 'E', - replace: true, - transclude: true, - template: '', - - scope: { - type: '@', - }, - - link: function($scope, $element, $attr) { - $element.addClass($scope.type); - } - }; -}); + $parse($attr.model || BAR_MODEL_DEFAULT).assign($scope.$parent, hb); + } + }; + }]; +} })(ionic); diff --git a/js/ext/angular/src/directive/ionicNavBar.js b/js/ext/angular/src/directive/ionicNavBar.js new file mode 100644 index 0000000000..78c2d0eec9 --- /dev/null +++ b/js/ext/angular/src/directive/ionicNavBar.js @@ -0,0 +1,379 @@ + +angular.module('ionic.ui.navBar', ['ionic.service.view', 'ngSanitize']) + +/** + * @ngdoc controller + * @name ionicNavBar + * @module ionic + * @description + * Controller for the {@link ionic.directive:ionNavBar} directive. + */ +.controller('$ionicNavBar', ['$scope', '$element', '$ionicViewService', '$animate', '$compile', +function($scope, $element, $ionicViewService, $animate, $compile) { + //Let the parent know about our controller too so that children of + //sibling content elements can know about us. + $element.parent().data('$ionNavBarController', this); + + var hb = this._headerBarView = new ionic.views.HeaderBar({ + el: $element[0], + alignTitle: $scope.alignTitle || 'center' + }); + + this.leftButtonsElement = angular.element( + $element[0].querySelector('.buttons.left-buttons') + ); + this.rightButtonsElement = angular.element( + $element[0].querySelector('.buttons.right-buttons') + ); + + /** + * @ngdoc method + * @name ionicNavBar#back + * @description Goes back in the view history. + * @param {DOMEvent=} event The event object (eg from a tap event) + */ + this.back = function(e) { + var backView = $ionicViewService.getBackView(); + backView && backView.go(); + e && (e.alreadyHandled = true); + return false; + }; + + /** + * @ngdoc method + * @name ionicNavBar#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. + */ + this.align = function(direction) { + this._headerBarView.align(direction); + }; + + /** + * @ngdoc method + * @name ionicNavBar#showBackButton + * @description + * Set whether the {@link ionic.directive:ionNavBackButton} should be shown (if it exists). + * @param {boolean} show Whether to show the back button. + */ + this.showBackButton = function(show) { + $scope.backButtonShown = !!show; + }; + /** + * @ngdoc method + * @name ionicNavBar#showBar + * @description + * Set whether the {@link ionic.directive:ionNavBar} should be shown. + * @param {boolean} show Whether to show the bar. + */ + this.showBar = function(show) { + $scope.isInvisible = !show; + }; + /** + * @ngdoc method + * @name ionicNavBar#setTitle + * @description + * Set the title for the {@link ionic.directive:ionNavBar}. + * @param {string} title The new title to show. + */ + this.setTitle = function(title) { + $scope.oldTitle = $scope.title; + $scope.title = title || ''; + }; + /** + * @ngdoc method + * @name ionicNavBar#changeTitle + * @description + * Change the title, transitioning the new title in and the old one out in a given direction. + * @param {string} title The new title to show. + * @param {string} direction The direction to transition the new title in. + * Available: 'forward', 'back'. + */ + this.changeTitle = function(title, direction) { + if ($scope.title === title) { + return false; + } + this.setTitle(title); + $scope.isReverse = direction == 'back'; + $scope.shouldAnimate = !!direction; + + if (!$scope.shouldAnimate) { + //We're done! + this._headerBarView.align(); + } else { + this._animateTitles(); + } + return true; + }; + + /** + * @private + * Exposed for testing + */ + this._animateTitles = function() { + var oldTitleEl, newTitleEl, currentTitles; + + //If we have any title right now + //(or more than one, they could be transitioning on switch), + //replace the first one with an oldTitle element + currentTitles = $element[0].querySelectorAll('.title'); + if (currentTitles.length) { + oldTitleEl = $compile('

')($scope); + angular.element(currentTitles[0]).replaceWith(oldTitleEl); + } + //Compile new title + newTitleEl = $compile('

')($scope); + + //Animate in on next frame + ionic.requestAnimationFrame(function() { + + oldTitleEl && $animate.leave(angular.element(oldTitleEl)); + + var insert = oldTitleEl && angular.element(oldTitleEl) || null; + $animate.enter(newTitleEl, $element, insert, function() { + hb.align(); + }); + + //Cleanup any old titles leftover (besides the one we already did replaceWith on) + angular.forEach(currentTitles, function(el) { + if (el && el.parentNode) { + //Use .remove() to cleanup things like .data() + angular.element(el).remove(); + } + }); + + //$apply so bindings fire + $scope.$digest(); + + //Stop flicker of new title on ios7 + ionic.requestAnimationFrame(function() { + newTitleEl[0].classList.remove('invisible'); + }); + }); + }; +}]) + +/** + * @ngdoc directive + * @name ionNavBar + * @module ionic + * @controller ionicNavBar + * @restrict E + * + * @description + * If we have an {@link ionic.directive:ionNavView} directive, we can also create an + * ``, which will create a topbar that updates as the application state changes. + * + * We can add a back button by putting an {@link ionic.directive:ionNavBackButton} inside. + * + * We can add buttons depending on the currently visible view using + * {@link ionic.directive:ionNavButtons}. + * + * @usage + * + * ```html + * + * + * + * + * + * + * + * ``` + * + * @param model {string=} The model to assign the + * {@link ionic.controller:ionicNavBar ionicNavBar controller} to. + * Default: assigns it to $scope.navBarController. + * @param animation {string=} The animation used to transition between titles. + * @param type {string=} The className for the navbar. For example, 'bar-positive'. + * @param align {string=} Where to align the title of the navbar. + * Available: 'left', 'right', 'center'. Defaults to 'center'. + */ +.directive('ionNavBar', ['$ionicViewService', '$rootScope', '$animate', '$compile', '$parse', +function($ionicViewService, $rootScope, $animate, $compile, $parse) { + + return { + restrict: 'E', + replace: true, + transclude: true, + controller: '$ionicNavBar', + scope: { + animation: '@', + type: '@', + alignTitle: '@' + }, + template: + '', + compile: function(tElement, tAttrs, transclude) { + + return function link($scope, $element, $attr, navBarCtrl) { + $parse($attr.model || 'navBarController') + .assign($scope.$parent, navBarCtrl); + + //Put transcluded content (usually a back button) before the rest + transclude($scope, function(clone) { + $element.prepend(clone); + }); + + //defaults + $scope.backButtonShown = false; + $scope.shouldAnimate = true; + $scope.isReverse = false; + $scope.isInvisible = true; + + $scope.navBarClass = function() { + return ($scope.type ? ' ' + $scope.type : '') + + ($scope.isReverse ? ' reverse' : '') + + ($scope.isInvisible ? ' invisible' : '') + + ($scope.shouldAnimate && $scope.animation ? ' ' + $scope.animation : ''); + }; + }; + } + }; +}]) + +/** + * @ngdoc directive + * @name ionNavBackButton + * @module ionic + * @restrict E + * @parent ionNavBar + * @description + * Creates a back button inside an {@link ionic.directive:ionNavBar}. + * + * Will show up when the user is able to go back in the current navigation stack. + * + * By default, will go back when clicked. If you wish to set a custom action on click, + * simply define an `ng-click` attribute and use + * {@link ionic.controller:ionicNavBar#back ionicNavBar controller's .back method} to go back + * when wished. + * + * @usage + * + * With default click action: + * + * ```html + * + * + * Back! + * + * + * ``` + * + * With custom click action: + * + * ```html + * + * + * Back! + * + * + * ``` + */ +.directive('ionNavBackButton', [function() { + return { + restrict: 'E', + require: '^ionNavBar', + replace: true, + transclude: true, + template: + '', + link: function($scope, $element, $attr, navBarCtrl) { + if (!$attr.ngClick) { + ionic.on('tap', navBarCtrl.back, $element[0]); + } + + //If the current viewstate does not allow a back button, + //always hide it. + var deregisterListener = $scope.$parent.$on( + '$viewHistory.historyChange', + function(e, data) { + $scope.hasBackButton = !!data.showBack; + } + ); + $scope.$on('$destroy', deregisterListener); + + //Make sure both that a backButton is allowed in the first place, + //and that it is shown by the current view. + $scope.$watch('!!(backButtonShown && hasBackButton)', function(val) { + $element.toggleClass('hide', !val); + }); + } + }; +}]) + +/** + * @ngdoc directive + * @name ionNavButtons + * @module ionic + * @restrict E + * @parent ionNavView + * + * @description + * Use ionNavButtons to set the buttons on your {@link ionic.directive:ionNavBar} + * from within an {@link ionic.directive:ionView}. + * + * Any buttons you declare will be placed onto the navbar's corresponding side, + * and then destroyed when the user leaves their parent view. + * + * @usage + * ```html + * + * + * + * + * + * + * + * + * Some super content here! + * + * + * + * ``` + * + * @param {string} side The side to place the buttons on in the parent + * {@link ionic.directive:ionNavBar}. Available: 'left' or 'right'. + */ +.directive('ionNavButtons', ['$compile', '$animate', function($compile, $animate) { + return { + require: '^ionNavBar', + transclude: true, + restrict: 'E', + compile: function($element, $attrs, transclude) { + return function($scope, $element, $attrs, navBarCtrl) { + var navElement = $attrs.side === 'right' ? + navBarCtrl.rightButtonsElement : + navBarCtrl.leftButtonsElement; + + //Put all of our inside buttons into their own div, + //so we can remove them all when this element dies - + //even if the buttons have changed through an ng-repeat or the like, + //we just remove their div parent and they are gone. + var clone = angular.element('
').append(transclude($scope)); + $animate.enter(clone, navElement); + + //When our ion-nav-buttons container is destroyed, + //destroy everything in the navbar + $element.on('$destroy', function() { + $animate.leave(clone); + }); + + //The original element is just a completely empty - make it invisible + $element.css('display', 'none'); + }; + } + }; +}]); diff --git a/js/ext/angular/src/directive/ionicTabBar.js b/js/ext/angular/src/directive/ionicTabBar.js index 10ea896d18..d73e4d153b 100644 --- a/js/ext/angular/src/directive/ionicTabBar.js +++ b/js/ext/angular/src/directive/ionicTabBar.js @@ -239,8 +239,6 @@ function($scope, $ionicViewService, $rootScope, $element) { * @param {string=} icon-off The icon of the tab while it is not selected. * @param {expression=} badge The badge to put on this tab (usually a number). * @param {expression=} badge-style The style of badge to put on this tab (eg tabs-positive). - * @param {expression=} left-buttons The left buttons to use on a parent {@link ionic.directive:ionNavBar} while this tab is selected. - * @param {expression=} right-buttons The right buttons to use on a parent {@link ionic.directive:ionNavBar} while this tab is selected. * @param {expression=} on-select Called when this tab is selected. * @param {expression=} on-deselect Called when this tab is deselected. */ @@ -273,8 +271,6 @@ function($rootScope, $animate, $ionicBind, $compile, $ionicViewService) { $ionicBind($scope, $attr, { animate: '=', - leftButtons: '=', - rightButtons: '=', onSelect: '&', onDeselect: '&', title: '@', diff --git a/js/ext/angular/src/directive/ionicViewState.js b/js/ext/angular/src/directive/ionicViewState.js index 5f70acb814..69fb24f104 100644 --- a/js/ext/angular/src/directive/ionicViewState.js +++ b/js/ext/angular/src/directive/ionicViewState.js @@ -3,197 +3,6 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gesture', 'ngSanitize']) -/** - * @ngdoc directive - * @name ionNavBar - * @module ionic - * @restrict E - * - * @usage - * If have an {@link ionic.directive:ionNavView} directive, we can also create an - * , which will create a topbar that updates as the application state changes. - * We can also add some styles and set up animations: - * - * ```html - * - * - * - * - * - * - * - * ``` - * - * @param {string=} back-button-type The type of the back button's icon. Available: 'button-icon' or just 'button'. - * @param {string=} back-button-icon The icon to use for the back button. For example, 'ion-arrow-left-c'. - * @param {string=} back-button-label The label to use for the back button. For example, 'Back'. - * @param animation {string=} The animation used to transition between titles. - * @param type {string=} The className for the navbar. For example, 'bar-positive'. - * @param align {string=} Where to align the title of the navbar. Available: 'left', 'right', 'center'. Defaults to 'center'. - */ -.directive('ionNavBar', ['$ionicViewService', '$rootScope', '$animate', '$compile', - function( $ionicViewService, $rootScope, $animate, $compile) { - - return { - restrict: 'E', - replace: true, - scope: { - animation: '@', - type: '@', - backType: '@backButtonType', - backLabel: '@backButtonLabel', - backIcon: '@backButtonIcon', - alignTitle: '@' - }, - controller: function() {}, - template: - '', - compile: function(tElement, tAttrs) { - - return function link($scope, $element, $attr) { - //defaults - $scope.backButtonEnabled = false; - $scope.animateEnabled = true; - $scope.isReverse = false; - $scope.isInvisible = true; - - $scope.navBarClass = function() { - return ($scope.type ? ' ' + $scope.type : '') + - ($scope.isReverse ? ' reverse' : '') + - ($scope.isInvisible ? ' invisible' : '') + - (!$scope.animationDisabled && $scope.animation ? ' ' + $scope.animation : ''); - }; - - // Initialize our header bar view which will handle - // resizing and aligning our title labels - var hb = new ionic.views.HeaderBar({ - el: $element[0], - alignTitle: $scope.alignTitle || 'center' - }); - $scope.headerBarView = hb; - - //Navbar events - $scope.$on('viewState.viewEnter', function(e, data) { - updateHeaderData(data); - }); - $scope.$on('viewState.showNavBar', function(e, showNavBar) { - $scope.isInvisible = !showNavBar; - }); - - // All of these these are emitted from children of a sibling scope, - // so we listen on parent so we can catch them as they bubble up - var unregisterEventListeners = [ - $scope.$parent.$on('$viewHistory.historyChange', function(e, data) { - $scope.backButtonEnabled = !!data.showBack; - }), - $scope.$parent.$on('viewState.leftButtonsChanged', function(e, data) { - $scope.leftButtons = data; - }), - $scope.$parent.$on('viewState.rightButtonsChanged', function(e, data) { - $scope.rightButtons = data; - }), - $scope.$parent.$on('viewState.showBackButton', function(e, data) { - $scope.backButtonEnabled = !!data; - }), - $scope.$parent.$on('viewState.titleUpdated', function(e, data) { - $scope.title = data && data.title || ''; - }) - ]; - $scope.$on('$destroy', function() { - for (var i=0; i')($scope); - angular.element(currentTitles[0]).replaceWith(oldTitleEl); - } - //Compile new title - newTitleEl = $compile('

')($scope); - - //Animate in one frame - ionic.requestAnimationFrame(function() { - - oldTitleEl && $animate.leave(angular.element(oldTitleEl)); - - var insert = oldTitleEl && angular.element(oldTitleEl) || null; - $animate.enter(newTitleEl, $element, insert, function() { - hb.align(); - }); - - //Cleanup any old titles leftover (besides the one we already did replaceWith on) - angular.forEach(currentTitles, function(el) { - if (el && el.parentNode) { - //Use .remove() to cleanup things like .data() - angular.element(el).remove(); - } - }); - - //$apply so bindings fire - $scope.$digest(); - - //Stop flicker of new title on ios7 - ionic.requestAnimationFrame(function() { - newTitleEl[0].classList.remove('invisible'); - }); - }); - } - }; - } - }; -}]) - /** * @ngdoc directive * @name ionView @@ -219,10 +28,9 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu * * ``` * - * @param {expression=} left-buttons The leftButtons to display on the parent {@link ionic.directive:ionNavBar}. - * @param {expression=} right-buttons The rightButtons to display on the parent {@link ionic.directive:ionNavBar}. * @param {string=} title The title to display on the parent {@link ionic.directive:ionNavBar}. - * @param {boolean=} hideBackButton Whether to hide the back button on the parent {@link ionic.directive:ionNavBar}. + * @param {boolean=} hideBackButton Whether to hide the back button on the parent + * {@link ionic.directive:ionNavBar}. * @param {boolean=} hideNavBar Whether to hide the parent {@link ionic.directive:ionNavBar}. */ .directive('ionView', ['$ionicViewService', '$rootScope', '$animate', @@ -230,46 +38,34 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu return { restrict: 'EA', priority: 1000, + require: '^?ionNavBar', scope: { - leftButtons: '=', - rightButtons: '=', title: '@', - hideBackButton: '@', - hideNavBar: '@', + hideBackButton: '&', + hideNavBar: '&', }, - compile: function(tElement, tAttrs, transclude) { tElement.addClass('pane'); tElement[0].removeAttribute('title'); - return function link($scope, $element, $attr) { - - $rootScope.$broadcast('viewState.viewEnter', { - title: $scope.title, - navDirection: $scope.$navDirection || $scope.$parent.$navDirection - }); + return function link($scope, $element, $attr, navBarCtrl) { + if (!navBarCtrl) { + return; + } + navBarCtrl.changeTitle($scope.title, $scope.$parent.$navDirection); // Should we hide a back button when this tab is shown - $scope.hideBackButton = $scope.$eval($scope.hideBackButton); - if($scope.hideBackButton) { - $rootScope.$broadcast('viewState.showBackButton', false); - } + navBarCtrl.showBackButton(!$scope.hideBackButton()); // Should the nav bar be hidden for this view or not? - $rootScope.$broadcast('viewState.showNavBar', ($scope.hideNavBar !== 'true') ); - - // watch for changes in the left buttons - $scope.$watch('leftButtons', function(value) { - $scope.$emit('viewState.leftButtonsChanged', $scope.leftButtons); - }); - - $scope.$watch('rightButtons', function(val) { - $scope.$emit('viewState.rightButtonsChanged', $scope.rightButtons); - }); + navBarCtrl.showBar(!$scope.hideNavBar()); // watch for changes in the title - $scope.$watch('title', function(val) { - $scope.$emit('viewState.titleUpdated', $scope); + $scope.$watch('title', function(val, oldVal) { + //Don't send in initial value, changeTitle does that + if (val !== oldVal) { + navBarCtrl.setTitle(val); + } }); }; } @@ -277,39 +73,6 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu }]) -/** -* @private -*/ -.directive('ionNavBackButton', ['$ionicViewService', '$rootScope', - function($ionicViewService, $rootScope) { - - function goBack(e) { - var backView = $ionicViewService.getBackView(); - backView && backView.go(); - e.alreadyHandled = true; - return false; - } - - return { - restrict: 'E', - scope: { - type: '=', - label: '=', - icon: '=' - }, - replace: true, - template: - '', - link: function($scope) { - $scope.goBack = goBack; - } - }; -}]) - /** * @ngdoc directive * @name ionNavView diff --git a/js/ext/angular/src/ionicAngular.js b/js/ext/angular/src/ionicAngular.js index 556d48f9f1..618852b83e 100644 --- a/js/ext/angular/src/ionicAngular.js +++ b/js/ext/angular/src/ionicAngular.js @@ -26,26 +26,25 @@ angular.module('ionic.service', [ // UI specific services and delegates angular.module('ionic.ui.service', [ 'ionic.ui.service.scrollDelegate', - 'ionic.ui.service.slideBoxDelegate', - 'ionic.ui.service.sideMenuDelegate', + 'ionic.ui.service.slideBoxDelegate' ]); angular.module('ionic.ui', [ - 'ionic.ui.content', - 'ionic.ui.scroll', - 'ionic.ui.tabs', - 'ionic.ui.viewState', - 'ionic.ui.header', - 'ionic.ui.sideMenu', - 'ionic.ui.slideBox', - 'ionic.ui.list', - 'ionic.ui.checkbox', - 'ionic.ui.toggle', - 'ionic.ui.radio', - 'ionic.ui.touch', - 'ionic.ui.popup' - ]); - + 'ionic.ui.checkbox', + 'ionic.ui.content', + 'ionic.ui.header', + 'ionic.ui.list', + 'ionic.ui.navBar', + 'ionic.ui.popup', + 'ionic.ui.radio', + 'ionic.ui.scroll', + 'ionic.ui.sideMenu', + 'ionic.ui.slideBox', + 'ionic.ui.tabs', + 'ionic.ui.toggle', + 'ionic.ui.touch', + 'ionic.ui.viewState' +]); angular.module('ionic', [ 'ionic.service', diff --git a/js/ext/angular/src/service/delegates/ionicSideMenuDelegate.js b/js/ext/angular/src/service/delegates/ionicSideMenuDelegate.js deleted file mode 100644 index 7218fae523..0000000000 --- a/js/ext/angular/src/service/delegates/ionicSideMenuDelegate.js +++ /dev/null @@ -1,39 +0,0 @@ -(function() { -'use strict'; - -angular.module('ionic.ui.service.sideMenuDelegate', []) - -.factory('$ionicSideMenuDelegate', ['$rootScope', '$timeout', '$q', function($rootScope, $timeout, $q) { - return { - getSideMenuController: function($scope) { - return $scope.sideMenuController; - }, - close: function($scope) { - if($scope.sideMenuController) { - $scope.sideMenuController.close(); - } - }, - toggleLeft: function($scope) { - if($scope.sideMenuController) { - $scope.sideMenuController.toggleLeft(); - } - }, - toggleRight: function($scope) { - if($scope.sideMenuController) { - $scope.sideMenuController.toggleRight(); - } - }, - openLeft: function($scope) { - if($scope.sideMenuController) { - $scope.sideMenuController.openPercentage(100); - } - }, - openRight: function($scope) { - if($scope.sideMenuController) { - $scope.sideMenuController.openPercentage(-100); - } - } - }; -}]); - -})(); diff --git a/js/ext/angular/test/directive/ionicBar.unit.js b/js/ext/angular/test/directive/ionicBar.unit.js index ea6d8e01ef..076e13a8e5 100644 --- a/js/ext/angular/test/directive/ionicBar.unit.js +++ b/js/ext/angular/test/directive/ionicBar.unit.js @@ -1,74 +1,53 @@ -describe('Ionic Header Bar', function() { - var el, rootScope, compile; - +describe('bar directives', function() { beforeEach(module('ionic')); - beforeEach(inject(function($animate, $compile, $rootScope) { - compile = $compile; - rootScope = $rootScope; - ionic.requestAnimationFrame = function(cb) { cb(); }; - $animate.enabled(false); - el = null; - })); + angular.forEach([{ + tag: 'ion-header-bar', + element: 'header', + model: 'headerBarController' + }, { + tag: 'ion-footer-bar', + element: 'footer', + model: 'footerBarController' + }], function(data) { + describe(data.tag, function() { - it('Should not add title-left or title-right classes when align-title=center', function() { - el = compile('')(rootScope); - var headerView = el.isolateScope().headerBarView; - var title = angular.element(headerView.el.querySelector('.title')); - expect(title.hasClass('title-left')).not.toEqual(true); - expect(title.hasClass('title-right')).not.toEqual(true); + function setup(attrs) { + var el; + ionic.views.HeaderBar = function(opts) { + this.opts = opts; + this.align = jasmine.createSpy('align'); + }; + inject(function($compile, $rootScope) { + el = angular.element('<'+data.tag+' '+(attrs||'')+'>'); + el = $compile(el)($rootScope.$new()); + $rootScope.$apply(); + }); + return el; + } + + it('should compile to ' + data.element, function() { + var el = setup(); + expect(el[0].tagName.toLowerCase()).toBe(data.element); + }); + + it('should assign views.HeaderBar to default model', function() { + var el = setup(); + expect(el.scope()[data.model] instanceof ionic.views.HeaderBar).toBe(true); + }); + it('should assign views.HeaderBar to attr model', function() { + var el = setup('model="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.model].opts.alignTitle).toBe('center'); + }); + it('should pass attr.alignTitle to views.HeaderBar', function() { + var el = setup('align-title="left"'); + expect(el.scope()[data.model].opts.alignTitle).toBe('left'); + }); + }); }); - - it('Should add title-left class when align-title=left', inject(function($animate) { - el = compile('')(rootScope); - rootScope.$apply(); - var headerView = el.isolateScope().headerBarView; - var title = angular.element(headerView.el.querySelector('.title')); - expect(title.hasClass('title-left')).toEqual(true); - })); - - it('Should add title-right class when align-title=right', function() { - el = compile('')(rootScope); - rootScope.$apply(); - var headerView = el.isolateScope().headerBarView; - var title = angular.element(headerView.el.querySelector('.title')); - expect(title.hasClass('title-right')).toEqual(true); - }); - - it('Should re-align the title when leftButtons change', function() { - rootScope.leftButtons = []; - el = compile('')(rootScope); - var headerView = el.isolateScope().headerBarView; - - //trigger initial align() - rootScope.$apply(); - - spyOn(headerView, 'align'); - - var button = { content: '' }; - rootScope.leftButtons.push(button); - rootScope.$apply(); - - expect(headerView.align).toHaveBeenCalled(); - }); - - it('Should re-align the title when rightButtons change', function() { - rootScope.rightButtons = []; - el = compile('')(rootScope); - var headerView = el.isolateScope().headerBarView; - - //trigger initial align() - rootScope.$apply(); - - spyOn(headerView, 'align'); - - var button = { content: '' }; - rootScope.rightButtons.push(button); - rootScope.$apply(); - - expect(headerView.align).toHaveBeenCalled(); - }); - - - }); diff --git a/js/ext/angular/test/directive/ionicNavBackButton.unit.js b/js/ext/angular/test/directive/ionicNavBackButton.unit.js new file mode 100644 index 0000000000..0e77e7f59a --- /dev/null +++ b/js/ext/angular/test/directive/ionicNavBackButton.unit.js @@ -0,0 +1,71 @@ +describe('ionNavBackButton directive', function() { + beforeEach(module('ionic.ui.navBar')); + + function setup(attr, content) { + var el; + inject(function($compile, $rootScope) { + el = angular.element(''+(content||'')+''); + el.data('$ionNavBarController', { + back: jasmine.createSpy('back'), + }); + el = $compile(el)($rootScope.$new()); + $rootScope.$apply(); + }); + return el; + } + + it('should error without a parent ionNavBar', inject(function($compile, $rootScope) { + expect(function() { + $compile('')($rootScope); + }).toThrow(); + })); + + it('should should have class', function() { + var el = setup(); + expect(el.hasClass('button back-button')).toBe(true); + }); + + it('should set hasBackButton through historyChange event', function() { + var el = setup(); + expect(el.scope().hasBackButton).toBeFalsy(); + el.scope().$parent.$broadcast('$viewHistory.historyChange', {showBack: true}); + expect(el.scope().hasBackButton).toBe(true); + el.scope().$parent.$broadcast('$viewHistory.historyChange', {showBack: false}); + expect(el.scope().hasBackButton).toBe(false); + }); + + it('should hide based on backButtonShown && hasBackButton', function() { + var el = setup(); + expect(el.hasClass('hide')).toBe(true); + el.scope().$apply('backButtonShown = true; hasBackButton = true'); + expect(el.hasClass('hide')).toBe(false); + el.scope().$apply('backButtonShown = false; hasBackButton = true'); + expect(el.hasClass('hide')).toBe(true); + el.scope().$apply('backButtonShown = true; hasBackButton = false'); + expect(el.hasClass('hide')).toBe(true); + el.scope().$apply('backButtonShown = true; hasBackButton = true'); + expect(el.hasClass('hide')).toBe(false); + }); + + it('should transclude content', function() { + var el = setup('', 'content {{1+2}}'); + expect(el.text().trim()).toBe('content 3'); + expect(el.children().eq(0)[0].tagName.toLowerCase()).toBe('b'); + }); + + it('should add onTap if ngClick isnt defined', function() { + spyOn(ionic, 'on'); + var el = setup(); + expect(ionic.on).toHaveBeenCalledWith( + 'tap', + el.controller('ionNavBar').back, + el[0] + ); + }); + + it('should not add onTap if ngClick is defined', function() { + spyOn(ionic, 'on'); + var el = setup('ng-click="doSomething()"'); + expect(ionic.on).not.toHaveBeenCalled(); + }); +}); diff --git a/js/ext/angular/test/directive/ionicNavBar.unit.js b/js/ext/angular/test/directive/ionicNavBar.unit.js new file mode 100644 index 0000000000..f0cce79f1b --- /dev/null +++ b/js/ext/angular/test/directive/ionicNavBar.unit.js @@ -0,0 +1,254 @@ +describe('ionNavBar', function() { + describe('$ionicNavBar controller', function() { + + var backView = { go: jasmine.createSpy('backViewGo') }; + beforeEach(module('ionic.ui.navBar', function($provide) { + $provide.value('$ionicViewService', { + getBackView: jasmine.createSpy('getBackView').andCallFake(function() { + return backView; + }) + }); + })); + + var parent, el, $scope; + function setup(locals) { + parent = angular.element('
'); + var ctrl; + inject(function($controller, $rootScope) { + el = angular.element('
' + + '
' + + '

' + + '
' + + '
'); + parent.append(el); + $scope = $rootScope.$new(); + + ctrl = $controller('$ionicNavBar', { + $element: el, + $scope: $scope + }); + ctrl._headerBarView = { align: jasmine.createSpy('align') }; + }); + return ctrl; + } + + it('should set controller-data on parent as well for easier access', function() { + var ctrl = setup(); + expect(parent.data('$ionNavBarController')).toBe(ctrl); + }); + + it('should expose leftButtonsElement', function() { + var ctrl = setup(); + expect(ctrl.leftButtonsElement.hasClass('left-buttons')).toBe(true); + }); + it('should expose rightButtonsElement', function() { + var ctrl = setup(); + expect(ctrl.rightButtonsElement.hasClass('right-buttons')).toBe(true); + }); + + it('should go back', inject(function($ionicViewService) { + var ctrl = setup(); + var e = { alreadyHandled: false }; + ctrl.back(e); + expect($ionicViewService.getBackView).toHaveBeenCalled(); + expect(backView.go).toHaveBeenCalled(); + expect(e.alreadyHandled).toBe(true); + })); + + it('should align', function() { + var ctrl = setup(); + expect($scope.backButtonShown).toBeUndefined(); + ctrl.showBackButton(true); + expect($scope.backButtonShown).toBe(true); + ctrl.showBackButton(false); + expect($scope.backButtonShown).toBe(false); + }); + + it('should showBackButton', function() { + var ctrl = setup(); + expect($scope.backButtonShown).toBeUndefined(); + ctrl.showBackButton(true); + expect($scope.backButtonShown).toBe(true); + ctrl.showBackButton(false); + expect($scope.backButtonShown).toBe(false); + }); + + it('should showBar', function() { + var ctrl = setup(); + expect($scope.isInvisible).toBeUndefined(); + ctrl.showBar(true); + expect($scope.isInvisible).toBe(false); + ctrl.showBar(false); + expect($scope.isInvisible).toBe(true); + }); + + it('should setTitle', function() { + var ctrl = setup(); + expect($scope.title).toBeUndefined(); + ctrl.setTitle('foo'); + expect($scope.title).toBe('foo'); + ctrl.setTitle(null); + expect($scope.title).toBe(''); + }) + + describe('changeTitle', function() { + var ctrl; + beforeEach(function() { + ctrl = setup(); + ctrl._animateTitles = jasmine.createSpy('animateTitles'); + }); + + it('should do nothing if title is same', function() { + ctrl.setTitle('123'); + expect($scope.title).toBe('123'); + expect(ctrl.changeTitle('123')).toBe(false); + }); + + it('should set isReverse', function() { + expect($scope.isReverse).toBeFalsy(); + ctrl.changeTitle('foo', 'back'); + expect($scope.isReverse).toBe(true); + ctrl.changeTitle('bar', 'this is not back'); + expect($scope.isReverse).toBe(false); + }); + + it('should set shouldAnimate', function() { + expect($scope.shouldAnimate).toBeFalsy(); + ctrl.changeTitle('foo', 'someDirection'); + expect($scope.shouldAnimate).toBe(true); + ctrl.changeTitle('bar', ''); + expect($scope.shouldAnimate).toBe(false); + }); + + it('should set title & oldTitle', function() { + expect($scope.oldTitle).toBeFalsy(); + ctrl.setTitle('title1'); + ctrl.changeTitle('title2'); + expect($scope.oldTitle).toBe('title1'); + expect($scope.title).toBe('title2'); + ctrl.changeTitle('title3'); + expect($scope.oldTitle).toBe('title2'); + expect($scope.title).toBe('title3'); + }); + + it('should only align if no navDirection', function() { + expect(ctrl._headerBarView.align).not.toHaveBeenCalled(); + ctrl.changeTitle('title1', null); + expect(ctrl._headerBarView.align).toHaveBeenCalled(); + expect(ctrl._animateTitles).not.toHaveBeenCalled(); + }); + + it('should animateTitles if a navDirection given', function() { + expect(ctrl._animateTitles).not.toHaveBeenCalled(); + ctrl.changeTitle('title1', 'back'); + expect(ctrl._headerBarView.align).not.toHaveBeenCalled(); + expect(ctrl._animateTitles).toHaveBeenCalled(); + }); + }); + + describe('animateTitles', function() { + var ctrl; + beforeEach(function() { + ctrl = setup(); + //Add an extra h1 just so we can test that it gets removed + el.append('

'); + ionic.requestAnimationFrame = function(cb) { cb(); }; + }); + + it('before raf should replace title with oldTitle', function() { + //Make raf do nothing so we can test what happens before it + ionic.requestAnimationFrame = function(){}; + + $scope.oldTitle = 'someTitle'; + ctrl._animateTitles(); + var titles = el[0].querySelectorAll('.title'); + expect(titles.length).toBe(2); + expect(titles[0].getAttribute('ng-bind-html')).toEqual('oldTitle'); + expect(titles[1].classList.contains('filler-element')).toBe(true); + }); + + it('after raf should have changed titles & cleaned up', inject(function($animate) { + var enterCallback; + $animate.leave = jasmine.createSpy('leave'); + $animate.enter = jasmine.createSpy('enter').andCallFake(function(child,parent,_,cb) { + parent.append(child); + enterCallback = cb; + }); + spyOn($scope, '$digest'); + ctrl._animateTitles(); + var oldTitle = el[0].querySelector('[ng-bind-html="oldTitle"]'); + var title = el[0].querySelector('[ng-bind-html="title"]'); + expect($animate.leave.mostRecentCall.args[0][0]).toBe(oldTitle); + expect($animate.enter.mostRecentCall.args[0][0]).toBe(title); + expect(el[0].querySelector('h1.filler-element')).toBe(null); + + expect($scope.$digest).toHaveBeenCalled(); + expect(title.classList.contains('invisible')).toBe(false); + })); + + }); + }); + + describe('ionNavBar directive', function() { + beforeEach(module('ionic.ui.navBar')); + function setup(attrs, content) { + var el; + inject(function($compile, $rootScope) { + el = $compile(''+(content||'')+'')($rootScope.$new()); + $rootScope.$apply(); + }); + return el; + } + + it('should prepend-transclude content', function() { + var el = setup('', 'super content {{4}}'); + expect(el.children().eq(0).html()).toBe('super content 4'); + }); + + it('should assign $scope.navBarController by default', function() { + var el = setup(); + expect(el.controller('ionNavBar')).toBeTruthy(); //sanity + expect(el.scope().navBarController).toBe(el.controller('ionNavBar')); + }); + + it('should assign $scope.navBarController to attr.model if set', function() { + var el = setup('model="theNavBarCtrl"'); + expect(el.controller('ionNavBar')).toBeTruthy(); + expect(el.scope().theNavBarCtrl).toBe(el.controller('ionNavBar')); + }); + + it('should have isInvisible class (default true)', function() { + var el = setup(); + expect(el.hasClass('invisible')).toBe(true); + el.isolateScope().$apply('isInvisible = false'); + expect(el.hasClass('invisible')).toBe(false); + el.isolateScope().$apply('isInvisible = true'); + expect(el.hasClass('invisible')).toBe(true); + }); + + it('should have animation class', function() { + var el = setup('animation="my-anim"'); + expect(el.hasClass('my-anim')).toBe(true); + el.isolateScope().$apply('shouldAnimate = false'); + expect(el.hasClass('my-anim')).toBe(false); + el.isolateScope().$apply('shouldAnimate = true'); + expect(el.hasClass('my-anim')).toBe(true); + }); + + it('should have reverse class', function() { + var el = setup(); + expect(el.hasClass('reverse')).toBe(false); + el.isolateScope().$apply('isReverse = true'); + expect(el.hasClass('reverse')).toBe(true); + el.isolateScope().$apply('isReverse = false'); + expect(el.hasClass('reverse')).toBe(false); + }); + + it('should have type class', function() { + var el = setup(); + expect(el.hasClass('superbar')).toBe(false); + el.isolateScope().$apply('type = "superbar"'); + expect(el.hasClass('superbar')).toBe(true); + }); + }); +}); diff --git a/js/ext/angular/test/directive/ionicNavButtons.js b/js/ext/angular/test/directive/ionicNavButtons.js new file mode 100644 index 0000000000..89c1fe62bf --- /dev/null +++ b/js/ext/angular/test/directive/ionicNavButtons.js @@ -0,0 +1,67 @@ +describe('ionNavButtons directive', function() { + + beforeEach(module('ionic.ui.navBar')); + function setup(attrs, contents) { + var el; + inject(function($compile, $rootScope) { + el = angular.element(''+(contents||'')+''); + el.data('$ionNavBarController', { + leftButtonsElement: angular.element('
'), + rightButtonsElement: angular.element('
') + }); + el = $compile(el)($rootScope.$new()); + $rootScope.$apply(); + }); + return el; + } + + it('should error without parent navBar', inject(function($compile, $rootScope) { + expect(function() { + $compile('')($rootScope.$new()); + }).toThrow(); + })); + + it('should make the container element end up display:none', function() { + var el = setup(); + expect(el.css('display')).toBe('none'); + }); + + it('should transclude contents into left', function() { + var el = setup('side="left" ng-init="items=[1,2]"', ''); + var leftButtons = el.controller('ionNavBar').leftButtonsElement.children(); + expect(leftButtons.text().trim()).toEqual('12'); + el.scope().$apply('items=[1,3,5]'); + expect(leftButtons.text().trim()).toEqual('135'); + }); + + it('should transclude contents into right', function() { + var el = setup('side="right" ng-init="items=[1,2]"', ''); + var rightButtons = el.controller('ionNavBar').rightButtonsElement.children(); + expect(rightButtons.text().trim()).toEqual('12'); + el.scope().$apply('items=[1,3,5]'); + expect(rightButtons.text().trim()).toEqual('135'); + }); + + it('left should destroy contents on element destroy', inject(function($animate) { + spyOn($animate, 'leave'); + + var el = setup('side="left" ng-init="items=[1,2]"', ''); + var leftButtons = el.controller('ionNavBar').leftButtonsElement.children(); + expect(leftButtons.text().trim()).toEqual('12'); + el.remove(); + expect($animate.leave).toHaveBeenCalled(); + expect($animate.leave.mostRecentCall.args[0][0]).toBe(leftButtons[0]); + })); + + it('right should destroy contents on element destroy', inject(function($animate) { + spyOn($animate, 'leave'); + + var el = setup('side="right" ng-init="items=[1,2]"', ''); + var rightButtons = el.controller('ionNavBar').rightButtonsElement.children(); + expect(rightButtons.text().trim()).toEqual('12'); + el.remove(); + expect($animate.leave).toHaveBeenCalled(); + expect($animate.leave.mostRecentCall.args[0][0]).toBe(rightButtons[0]); + })); + +}); diff --git a/js/ext/angular/test/directive/ionicView.unit.js b/js/ext/angular/test/directive/ionicView.unit.js index 1bbd060934..b65d749985 100644 --- a/js/ext/angular/test/directive/ionicView.unit.js +++ b/js/ext/angular/test/directive/ionicView.unit.js @@ -1,263 +1,63 @@ 'use strict'; -describe('Ionic View', function() { - var compile, scope, listElement, listCtrl; - +describe('ionView directive', function() { beforeEach(module('ionic.ui.viewState')); - beforeEach(inject(function($compile, $rootScope, $controller) { - compile = $compile; - scope = $rootScope; + function setup(attrs, scopeProps, content) { + var el; + inject(function($compile, $rootScope) { + var scope = angular.extend($rootScope.$new(), scopeProps || {}); + + el = angular.element(''); + el.data('$ionNavBarController', { + changeTitle: jasmine.createSpy('changeTitle'), + setTitle: jasmine.createSpy('setTitle'), + showBackButton: jasmine.createSpy('showBackButton'), + showBar: jasmine.createSpy('showBar') + }); + content && el.html(content); + + el = $compile(el)(scope); + $rootScope.$apply(); + }); + return el; + } + + it('should remove title & add pane, even with no navbar', inject(function($compile, $rootScope) { + var el = $compile('')($rootScope.$new()); + $rootScope.$apply(); + expect(el.hasClass('pane')).toBe(true); + expect(el[0].getAttribute('title')).toBe(null); })); - it('should init a view', function() { - var element = compile('me view')(scope); - expect(element.html()).toEqual('me view'); + it('should have content inside', function() { + var el = setup(null, null, 'some html'); + expect(el.html()).toBe('some html'); }); - it('should add pane classname and remove title from view', function() { - var element = compile('')(scope); - expect(element.attr('title')).toBeUndefined(); - expect(element.hasClass('pane')).toEqual(true); + it('should changeTitle with a navDirection', function() { + var el = setup('title="Hi, {{1}}!"', {$navDirection: 'foo'}); + expect(el.controller('ionNavBar').changeTitle).toHaveBeenCalledWith('Hi, 1!', 'foo'); }); - it('should broacast view enter on link', function() { - spyOn(scope, '$broadcast'); - var element = compile('')(scope); - expect(scope.$broadcast).toHaveBeenCalledWith('viewState.viewEnter', { title: 'Me Title', navDirection: undefined }); - - scope.$navDirection = 'forward'; - element = compile('')(scope); - expect(scope.$broadcast).toHaveBeenCalledWith('viewState.viewEnter', { title: 'Me Title', navDirection: 'forward' }); + it('should showBackButten depending on what is given', function() { + var el = setup(); + expect(el.controller('ionNavBar').showBackButton).toHaveBeenCalledWith(true); + el = setup('hide-back-button="true"'); + expect(el.controller('ionNavBar').showBackButton).toHaveBeenCalledWith(false); }); - it('should set hide back button', function() { - spyOn(scope, '$broadcast'); - - var element = compile('')(scope); - var viewScope = element.isolateScope(); - expect(viewScope.hideBackButton).toBeUndefined(); - expect(scope.$broadcast).not.toHaveBeenCalledWith('viewState.showBackButton', false); - - element = compile('')(scope); - viewScope = element.isolateScope(); - expect(viewScope.hideBackButton).toEqual(true); - expect(scope.$broadcast).toHaveBeenCalledWith('viewState.showBackButton', false); + it('should showBar depending on what is given', function() { + var el = setup(); + expect(el.controller('ionNavBar').showBar).toHaveBeenCalledWith(true); + var el = setup('hide-nav-bar="true"'); + expect(el.controller('ionNavBar').showBar).toHaveBeenCalledWith(false); }); - it('should add/remove back button based on events', function() { - var element = compile('')(scope); - scope.$apply(); - function backButton() { - return angular.element(element[0].querySelector('.back-button')); - }; - expect(backButton().hasClass('hide')).toEqual(true); - - scope.$broadcast('viewState.showBackButton', false); - scope.$apply(); - expect(backButton().hasClass('hide')).toEqual(true); - - scope.$broadcast('viewState.showBackButton', true); - scope.$apply(); - expect(backButton().hasClass('hide')).toEqual(false); - - scope.$broadcast('$viewHistory.historyChange', { showBack: false }); - scope.$apply(); - expect(backButton().hasClass('hide')).toEqual(true); - - scope.$broadcast('$viewHistory.historyChange', { showBack: true }); - scope.$apply(); - expect(backButton().hasClass('hide')).toEqual(false); + it('should setTitle on change', function() { + var el = setup('', {title: 'foo'}); + expect(el.controller('ionNavBar').setTitle).not.toHaveBeenCalled(); + el.isolateScope().$apply('title = "bar"'); + expect(el.controller('ionNavBar').setTitle).toHaveBeenCalledWith('bar'); }); - - it('should show/hide navBar', function() { - var element = compile('')(scope); - scope.$digest(); - expect(element.hasClass('invisible')).toEqual(true); - scope.$broadcast('viewState.showNavBar', true); - scope.$digest(); - expect(element.hasClass('invisible')).toEqual(false); - scope.$broadcast('viewState.showNavBar', false); - scope.$digest(); - expect(element.hasClass('invisible')).toEqual(true); - }); - - it('should have have animateEnabled=true if there is a navDirection and animate isnt false', function() { - var element = compile('')(scope); - scope.$digest(); - scope = element.isolateScope(); - - scope.$broadcast('viewState.viewEnter', {}); - expect(scope.animateEnabled).toBe(false); - - scope.$broadcast('viewState.viewEnter', { navDirection: 'forward' }); - expect(scope.animateEnabled).toBe(true); - - scope.$broadcast('viewState.viewEnter', { navDirection: 'forward', animate: false }); - expect(scope.animateEnabled).toBe(false); - - scope.$broadcast('viewState.viewEnter', { navDirection: 'back', animate: true }); - expect(scope.animateEnabled).toBe(true); - }); - - it('should hide navBar when using view attr', function() { - var element = compile('
')(scope); - scope.$digest(); - var navBar = element.find('header') - expect(navBar.hasClass('invisible')).toEqual(true); - }); - - it('should show and update navBar title when using view attr or events', function() { - scope.viewTitle = 'Title'; - var element = compile('
')(scope); - scope.$digest(); - var navBar = element.find('header'); - var title = navBar.find('h1'); - expect(element.find('header').find('h1').text().trim()).toEqual('Title'); - - scope.viewTitle = 'New Title'; - scope.$digest(); - title = navBar.find('h1'); - expect(title.text().trim()).toEqual('New Title'); - - scope.$broadcast('viewState.titleUpdated', { title: 'Event Title' }); - scope.$digest(); - title = navBar.find('h1'); - expect(title.text().trim()).toEqual('Event Title'); - }); - - it('should show / update navBar left and right buttons when using view attr or events', function() { - scope.leftButtons = [{ - type: 'button', - content: 'Left Button' - }]; - scope.rightButtons = [{ - type: 'button', - content: 'Right Button' - }]; - var element = compile('
')(scope); - scope.$digest(); - - var leftButton = angular.element(element[0].querySelector('.left-buttons')).find('button'); - expect(leftButton.text().trim()).toBe('Left Button'); - var rightButton = angular.element(element[0].querySelector('.right-buttons')).find('button'); - expect(rightButton.text().trim()).toBe('Right Button'); - - scope.leftButtons = [{ - type: 'button', - content: 'New Left Button' - }]; - scope.rightButtons = [{ - type: 'button', - content: 'New Right Button' - }]; - - scope.$digest(); - - leftButton = angular.element(element[0].querySelector('.left-buttons')).find('button'); - expect(leftButton.text().trim()).toBe('New Left Button'); - rightButton = angular.element(element[0].querySelector('.right-buttons')).find('button'); - expect(rightButton.text().trim()).toBe('New Right Button'); - - scope.$broadcast('viewState.leftButtonsChanged', [{ - type: 'button', - content: 'Event Left Button' - }]); - scope.$broadcast('viewState.rightButtonsChanged', [{ - type: 'button', - content: 'Event Right Button' - }]); - - scope.$digest(); - - leftButton = angular.element(element[0].querySelector('.left-buttons')).find('button'); - expect(leftButton.text().trim()).toBe('Event Left Button'); - rightButton = angular.element(element[0].querySelector('.right-buttons')).find('button'); - expect(rightButton.text().trim()).toBe('Event Right Button'); - }); - - it('should show navbar when not using view attr', function() { - var element = compile('
')(scope); - scope.$digest(); - var navBar = element.find('header') - expect(navBar.hasClass('invisible')).toEqual(false); - }); - - it('should set the navBar type', function() { - var element = compile('')(scope); - scope.$digest(); - expect(element.hasClass('bar-positive')).toEqual(true); - }); - - it('should not have the back button if no back button attributes set', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.length).toEqual(0); - }); - - it('should have the back button if back-button-type attributes set', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.length).toEqual(1); - }); - - it('should have the back button if back-button-icon attributes set', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.length).toEqual(1); - }); - - it('should have the back button if back-button-label attributes set', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.length).toEqual(1); - }); - - it('should have the back button if all back button attributes set', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.length).toEqual(1); - }); - - it('should set just a back button icon, no text', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.hasClass('button')).toEqual(true); - expect(backButton.hasClass('button-icon')).toEqual(true); - expect(backButton.hasClass('icon')).toEqual(true); - expect(backButton.hasClass('ion-back')).toEqual(true); - expect(backButton.children().length).toEqual(0); - expect(backButton.text().trim()).toEqual(''); - }); - - it('should set just a back button with only text, button-clear', function() { - var element = compile('')(scope); - scope.$apply(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.hasClass('button')).toEqual(true); - expect(backButton.hasClass('button-clear')).toEqual(true); - expect(backButton.hasClass('icon')).toEqual(false); - expect(backButton.text().trim()).toEqual('Back'); - }); - - it('should set a back button with an icon and text, button-icon', function() { - var element = compile('')(scope); - scope.$digest(); - var backButton = angular.element(element[0].querySelector('.back-button')); - expect(backButton.hasClass('button')).toEqual(true); - expect(backButton.hasClass('button-icon')).toEqual(true); - var icon = backButton.find('i'); - expect(icon.hasClass('icon')).toEqual(true); - expect(backButton.children()[0].tagName.toLowerCase()).toBe('i'); - expect(backButton.children()[0].className).toBe('icon ion-back'); - expect(backButton.text().trim()).toBe('Back'); - }); - }); - diff --git a/js/ext/angular/test/service/delegates/sideMenuDelegate.unit.js b/js/ext/angular/test/service/delegates/sideMenuDelegate.unit.js deleted file mode 100644 index b7411cd6ca..0000000000 --- a/js/ext/angular/test/service/delegates/sideMenuDelegate.unit.js +++ /dev/null @@ -1,22 +0,0 @@ -describe('Ionic SideMenuDelegate Service', function() { - var del, rootScope, compile, timeout, document; - - beforeEach(module('ionic')); - - beforeEach(inject(function($ionicSideMenuDelegate, $rootScope, $timeout, $compile, $document) { - del = $ionicSideMenuDelegate; - document = $document; - rootScope = $rootScope; - timeout = $timeout; - compile = $compile; - })); - - it('Should get from scope', function() { - var scope = rootScope.$new(); - var el = compile('')(scope); - var sc = del.getSideMenuController(scope); - - expect(sc).not.toBe(undefined); - }); - -}); diff --git a/js/ext/angular/test/viewState.html b/js/ext/angular/test/viewState.html index 66d200f6bc..6951b6f026 100644 --- a/js/ext/angular/test/viewState.html +++ b/js/ext/angular/test/viewState.html @@ -13,26 +13,28 @@
+ type="bar-positive"> + + Back + +
@@ -158,7 +161,12 @@