diff --git a/docs/templates/api_menu_version.template.html b/docs/templates/api_menu_version.template.html
index 67175d2622..a75a48191c 100644
--- a/docs/templates/api_menu_version.template.html
+++ b/docs/templates/api_menu_version.template.html
@@ -220,6 +220,29 @@
+
')
+ .append( $element.contents() );
+ $element.append(listEl);
- scope: {
- item: '=',
- itemType: '@',
- canDelete: '@',
- canReorder: '@',
- canSwipe: '@',
- onDelete: '&',
- optionButtons: '&',
- deleteIcon: '@',
- reorderIcon: '@'
- },
+ return function($scope, $element, $attrs, ctrls) {
+ var listCtrl = ctrls[0];
+ var scrollCtrl = ctrls[1];
- template: '
\
-
\
- \
-
\
-
\
-
\
- \
-
\
-
\
- \
-
\
-
',
+ //Wait for child elements to render...
+ $timeout(init);
- link: function($scope, $element, $attr, list) {
- if(!list) return;
-
- var $parentScope = list.scope;
- var $parentAttrs = list.attrs;
-
- $attr.$observe('href', function(value) {
- if(value) $scope.href = value.trim();
- });
-
- if(!$scope.itemType) {
- $scope.itemType = $parentScope.itemType;
- }
-
- // Set this item's class, first from the item directive attr, and then the list attr if item not set
- $element.addClass($scope.itemType || $parentScope.itemType);
-
- $scope.itemClass = $scope.itemType;
-
- // Decide if this item can do stuff, and follow a certain priority
- // depending on where the value comes from
- if(($attr.canDelete ? $scope.canDelete : $parentScope.canDelete) !== "false") {
- if($attr.onDelete || $parentAttrs.onDelete) {
-
- // only assign this method when we need to
- // and use its existence to decide if the delete should show or not
- $scope.deleteClick = function() {
- if($attr.onDelete) {
- // this item has an on-delete attribute
- $scope.onDelete({ item: $scope.item, index: $scope.$parent.$index });
- } else if($parentAttrs.onDelete) {
- // run the parent list's onDelete method
- // if it doesn't exist nothing will happen
- $parentScope.onDelete({ item: $scope.item, index: $scope.$parent.$index });
+ function init() {
+ var listView = listCtrl.listView = new ionic.views.ListView({
+ el: $element[0],
+ listEl: $element.children()[0],
+ scrollEl: scrollCtrl && scrollCtrl.element,
+ scrollView: scrollCtrl && scrollCtrl.scrollView,
+ onReorder: function(el, oldIndex, newIndex) {
+ var itemScope = angular.element(el).scope();
+ if (itemScope && itemScope.$onReorder) {
+ itemScope.$onReorder(oldIndex, newIndex);
+ }
+ },
+ canSwipe: function() {
+ return listCtrl.canSwipeItems();
}
- };
+ });
- // Set which icons to use for deleting
- $scope.deleteIconClass = $scope.deleteIcon || $parentScope.deleteIcon || 'ion-minus-circled';
- $element.addClass('item-left-editable');
+ if (angular.isDefined($attr.canSwipe)) {
+ $scope.$watch('!!(' + $attr.canSwipe + ')', function(value) {
+ listCtrl.canSwipeItems(value);
+ });
+ }
+
+ $scope.$watch('!!(' + $attr.showDelete + ')', function(value, oldValue) {
+ //Don't care about first false value
+ if (!value && !angular.isDefined(oldValue)) return;
+
+ if (value) listCtrl.closeOptionButtons();
+ listCtrl.showDelete(value);
+
+ $element.children().toggleClass('list-left-editing', value);
+ toggleNgHide('.item-delete.item-left-edit', value);
+ });
+ $scope.$watch('!!(' + $attr.showReorder + ')', function(value, oldValue) {
+ //Don't care about first false value
+ if (!value && !angular.isDefined(oldValue)) return;
+
+ if (value) listCtrl.closeOptionButtons();
+ listCtrl.showReorder(value);
+
+ $element.children().toggleClass('list-right-editing', value);
+ toggleNgHide('.item-reorder.item-right-edit', value);
+ });
+
+ function toggleNgHide(selector, shouldShow) {
+ angular.forEach($element[0].querySelectorAll(selector), function(node) {
+ if (shouldShow) $animate.removeClass(angular.element(node), 'ng-hide');
+ else $animate.addClass(angular.element(node), 'ng-hide');
+ });
+ }
}
+
+ };
+ }
+ };
+}])
+
+.controller('$ionicItem', [
+ '$scope',
+ '$element',
+function($scope, $element) {
+ this.$element = $element;
+ this.$scope = $scope;
+}])
+
+/**
+ * @ngdoc directive
+ * @name ionItem
+ * @parent ionic.directive:ionList
+ * @module ionic
+ * @restrict E
+ * Creates a list-item that can easily be swiped,
+ * deleted, reordered, edited, and more.
+ *
+ * See {@link ionic.directive:ionList} for a complete example & explanation.
+ *
+ * Can be assigned any item class name. See the
+ * [list CSS documentation](/docs/components/#list).
+ *
+ * @usage
+ *
+ * ```html
+ *
+ * Hello!
+ *
+ * ```
+ */
+.directive('ionItem', ['$animate', '$compile', function($animate, $compile) {
+ return {
+ restrict: 'E',
+ controller: '$ionicItem',
+ priorty: Number.MAX_VALUE,
+ require: ['ionItem', '^ionList'],
+ scope: true,
+ compile: function($element, $attrs) {
+ var isAnchor = angular.isDefined($attrs.href) || angular.isDefined($attrs.ngHref);
+ var isComplexItem = isAnchor ||
+ //Lame way of testing, but we have to know at compile what to do with the element
+ /ion-(delete|option|reorder)-button/.test($element.html());
+
+ if (isComplexItem) {
+ var innerElement = angular.element(isAnchor ? TPL_CONTENT_ANCHOR : TPL_CONTENT);
+ innerElement.append($element.contents());
+
+ $element.append(innerElement);
+ $element.addClass('item item-complex');
+ } else {
+ $element.addClass('item');
}
- // set the reorder Icon Class only if the item or list set can-reorder="true"
- if(($attr.canReorder ? $scope.canReorder : $parentScope.canReorder) === "true") {
- $scope.reorderIconClass = $scope.reorderIcon || $parentScope.reorderIcon || 'ion-navicon';
- $element.addClass('item-right-editable');
- }
-
- // Set the option buttons which can be revealed by swiping to the left
- // if canSwipe was set to false don't even bother
- if(($attr.canSwipe ? $scope.canSwipe : $parentScope.canSwipe) !== "false") {
- $scope.itemOptionButtons = $scope.optionButtons();
- if(typeof $scope.itemOptionButtons === "undefined") {
- $scope.itemOptionButtons = $parentScope.optionButtons();
- }
- $element.addClass('item-swipeable');
- }
-
+ return function link($scope, $element, $attrs) {
+ $scope.$href = function() {
+ return $attrs.href || $attrs.ngHref;
+ };
+ };
}
};
}])
/**
* @ngdoc directive
- * @name ionList
+ * @name ionDeleteButton
+ * @parent ionic.directive:ionItem
* @module ionic
* @restrict E
- * @codepen jsHjf
+ * Creates a delete button inside a list item, that is visible when the
+ * {@link ionic.directive:ionList ionList parent's} `show-delete` evaluates to true or
+ * `$ionicListDelegate.showDelete(true)` is called.
*
- * @description
- * The List is a widely used interface element in almost any mobile app,
- * and can include content ranging from basic text all the way to buttons,
- * toggles, icons, and thumbnails.
+ * Takes any ionicon as a class.
*
- * Both the list, which contains items, and the list items themselves can be
- * any HTML element. The containing element requires the list class and each
- * list item requires the item class. Ionic also comes with pre-built Angular
- * directives to make it easier to create a complex list.
- *
- * Using the ionList and {@link ionic.directive:ionItem} directives
- * make it easy to support various interaction modes such as swipe to edit,
- * drag to reorder, and removing items.
- *
- * However, if you need just a simple list you won't be required to use the
- * directives, but rather just use the classnames.
- * This demo is a simple list without using the directives.
- *
- * See the {@link ionic.directive:ionItem} documentation for more information on list items.
+ * See {@link ionic.directive:ionList} for a complete example & explanation.
*
* @usage
+ *
* ```html
- *
- *
+ *
+ *
+ *
+ * Hello, list item!
+ *
+ *
+ *
+ * Show Delete?
+ *
+ * ```
+ */
+.directive('ionDeleteButton', [function() {
+ return {
+ restrict: 'E',
+ require: '^ionItem',
+ //Run before anything else, so we can move it before other directives process
+ //its location (eg ngIf relies on the location of the directive in the dom)
+ priority: Number.MAX_VALUE,
+ compile: function($element, $attr) {
+ //Add the classes we need during the compile phase, so that they stay
+ //even if something else like ngIf removes the element and re-addss it
+ $attr.$set('class', ($attr.class || '') + ' button icon button-icon', true);
+ return function($scope, $element, $attr, itemCtrl) {
+ var container = angular.element(TPL_DELETE_BUTTON);
+ container.append($element);
+ itemCtrl.$element.append(container).addClass('item-left-editable');
+ };
+ }
+ };
+}])
+
+/**
+ * @ngdoc directive
+ * @name ionReorderButton
+ * @parent ionic.directive:ionItem
+ * @module ionic
+ * @restrict E
+ * Creates a reorder button inside a list item, that is visible when the
+ * {@link ionic.directive:ionList ionList parent's} `show-reorder` evaluates to true or
+ * `$ionicListDelegate.showReorder(true)` is called.
+ *
+ * Can be dragged to reorder items in the list. Takes any ionicon class.
+ *
+ * When an item reorder is complete, the `on-reorder` callback given in the attribute is called
+ * (see below).
+ *
+ * See {@link ionic.directive:ionList} for a complete example.
+ *
+ * @usage
+ *
+ * ```html
+ *
+ *
+ * Item {{$index}}
+ *
+ *
*
*
* ```
+ * ```js
+ * function MyCtrl($scope) {
+ * $scope.items = [1, 2, 3, 4];
+ * $scope.moveItem = function(item, fromIndex, toIndex) {
+ * //Move the item in the array
+ * $scope.items.splice(fromIndex, 1);
+ * $scope.items.splice(toIndex, 0, item);
+ * };
+ * }
+ * ```
*
- * @param {string=} item-type The type of this item. See [the list CSS page](/docs/components/#list) for available item types.
- * @param {expression=} on-delete Called when a child item is deleted.
- * @param {expression=} on-reorder Called when a child item is reordered.
- * @param {boolean=} show-delete Whether to show each item delete button.
- * @param {boolean=} show-reoder Whether to show each item's reorder button.
- * @param {boolean=} can-delete Whether child items are able to be deleted or not.
- * @param {boolean=} can-reorder Whether child items can be reordered or not.
- * @param {boolean=} can-swipe Whether child items can be swiped to reveal option buttons.
- * @param {string=} delete-icon The class name of the icon to show on child items while deleting. Defaults to `ion-minus-circled`.
- * @param {string=} reorder-icon The class name to show on child items while reordering. Defaults to `ion-navicon`.
- * @param {string=} animation An animation class to apply to the list for animating when child items enter or exit the list. See [the animation CSS page](/docs/components/#animations) for available animation classes.
+ * @param {expression=} on-reorder Expression to call when an item is reordered.
+ * Parameters given: $fromIndex, $toIndex.
*/
-.directive('ionList', ['$timeout', function($timeout) {
+.directive('ionReorderButton', [function() {
return {
restrict: 'E',
- replace: true,
- transclude: true,
- require: '^?$ionicScroll',
- scope: {
- itemType: '@',
- canDelete: '@',
- canReorder: '@',
- canSwipe: '@',
- showDelete: '=',
- showReorder: '=',
- onDelete: '&',
- onReorder: '&',
- optionButtons: '&',
- deleteIcon: '@',
- reorderIcon: '@'
- },
-
- template: '
',
-
- controller: ['$scope', '$attrs', function($scope, $attrs) {
- this.scope = $scope;
- this.attrs = $attrs;
- }],
-
- link: function($scope, $element, $attr, ionicScrollCtrl) {
- $scope.listView = new ionic.views.ListView({
- canSwipe: $scope.canSwipe !== "false" && !!$scope.optionButtons(),
- el: $element[0],
- listEl: $element[0].children[0],
- scrollEl: ionicScrollCtrl && ionicScrollCtrl.element,
- scrollView: ionicScrollCtrl && ionicScrollCtrl.scrollView,
- onReorder: function(el, oldIndex, newIndex) {
- $scope.$apply(function() {
- $scope.onReorder({el: el, start: oldIndex, end: newIndex});
+ require: '^ionItem',
+ priority: Number.MAX_VALUE,
+ compile: function($element, $attr) {
+ $attr.$set('class', ($attr.class || '') + ' button icon button-icon', true);
+ $element[0].setAttribute('data-prevent-scroll', true);
+ return function($scope, $element, $attr, itemCtrl) {
+ $scope.$onReorder = function(oldIndex, newIndex) {
+ $scope.$eval($attr.onReorder, {
+ $fromIndex: oldIndex,
+ $toIndex: newIndex
});
+ };
+
+ var container = angular.element(TPL_REORDER_BUTTON);
+ container.append($element);
+ itemCtrl.$element.append(container).addClass('item-right-editable');
+ };
+ }
+ };
+}])
+
+/**
+ * @ngdoc directive
+ * @name ionOptionButton
+ * @parent ionic.directive:ionItem
+ * @module ionic
+ * @restrict E
+ * Creates an option button inside a list item, that is visible when the item is swiped
+ * to the left by the user. Swiped open option buttons can be hidden with
+ * {@link ionic.directive:$ionicListDelegate#closeOptionButtons $ionicListDelegate#closeOptionButtons}.
+ *
+ * Can be assigned any button class.
+ *
+ * See {@link ionic.directive:ionList} for a complete example & explanation.
+ *
+ * @usage
+ *
+ * ```html
+ *
+ *
+ * I love kittens!
+ * Share
+ * Edit
+ *
+ *
+ * ```
+ */
+.directive('ionOptionButton', ['$compile', function($compile) {
+ return {
+ restrict: 'E',
+ require: '^ionItem',
+ priority: Number.MAX_VALUE,
+ compile: function($element, $attr) {
+ $attr.$set('class', ($attr.class || '') + ' button', true);
+ return function($scope, $element, $attr, itemCtrl) {
+ if (!itemCtrl.optionsContainer) {
+ itemCtrl.optionsContainer = angular.element(TPL_OPTION_BUTTONS);
+ itemCtrl.$element.append(itemCtrl.optionsContainer);
}
- });
-
- if($attr.animation) {
- $element[0].classList.add($attr.animation);
- }
-
- var destroyShowReorderWatch = $scope.$watch('showReorder', function(val) {
- if(val) {
- $element[0].classList.add('item-options-hide');
- $scope.listView && $scope.listView.clearDragEffects();
- } else if(val === false) {
- // false checking is because it could be undefined
- // if its undefined then we don't care to do anything
- $timeout(function(){
- $element[0].classList.remove('item-options-hide');
- }, 250);
- }
- });
-
- $scope.$on('$destroy', function () {
- destroyShowReorderWatch();
- });
-
+ itemCtrl.optionsContainer.append($element);
+ };
}
};
}]);
diff --git a/js/ext/angular/test/anchorScroll.html b/js/ext/angular/test/anchorScroll.html
index ce1823525c..819d0d00eb 100644
--- a/js/ext/angular/test/anchorScroll.html
+++ b/js/ext/angular/test/anchorScroll.html
@@ -24,7 +24,6 @@
Item {{ item.id }}
diff --git a/js/ext/angular/test/directive/ionicList.unit.js b/js/ext/angular/test/directive/ionicList.unit.js
index 7cf22dd159..082457adcd 100644
--- a/js/ext/angular/test/directive/ionicList.unit.js
+++ b/js/ext/angular/test/directive/ionicList.unit.js
@@ -1,389 +1,290 @@
'use strict';
+describe('$ionicList controller', function() {
+ beforeEach(module('ionic'));
+ function setup(attrs) {
+ var ctrl;
+ inject(function($controller, $rootScope) {
+ var scope = $rootScope.$new();
+ ctrl = $controller('$ionicList', {
+ $scope: scope,
+ $attrs: attrs || {},
+ });
+ ctrl.$scope = scope;
+ });
+ return ctrl;
+ }
-describe('Ionic List', function() {
- var compile, scope, listElement, listCtrl;
-
- beforeEach(module('ionic.ui.list'));
-
- beforeEach(inject(function($compile, $rootScope, $controller) {
- compile = $compile;
- scope = $rootScope;
+ it('should register with handle', inject(function($ionicListDelegate) {
+ spyOn($ionicListDelegate, '_registerInstance');
+ var ctrl = setup({delegateHandle: 'foobar'});
+ expect($ionicListDelegate._registerInstance)
+ .toHaveBeenCalledWith(ctrl, 'foobar');
}));
- beforeEach(inject(function (_$compile_, _$rootScope_) {
- compile = _$compile_;
- scope.showDelete = false;
- scope.showReorder = false;
+ it('should register with given handle and deregister on destroy', inject(function($ionicListDelegate) {
+ var deregisterSpy = jasmine.createSpy('deregister');
+ spyOn($ionicListDelegate, '_registerInstance').andCallFake(function() {
+ return deregisterSpy;
+ });
+ var ctrl = setup({
+ delegateHandle: 'something'
+ });
+ expect($ionicListDelegate._registerInstance)
+ .toHaveBeenCalledWith(ctrl, 'something');
- listElement = angular.element('');
- listElement = _$compile_(listElement)(scope);
-
- listCtrl = listElement.controller('list');
-
- scope.$digest();
+ expect(deregisterSpy).not.toHaveBeenCalled();
+ ctrl.$scope.$destroy();
+ expect(deregisterSpy).toHaveBeenCalled();
}));
- it('Should init', function() {
- var element = compile('' +
- ' ' +
- ' ' +
- ' ')(scope);
-
- expect(element.children().length).toBe(2);
+ it('.showReorder sets/gets', function() {
+ var ctrl = setup();
+ expect(ctrl.showReorder()).toBe(false);
+ ctrl.showReorder(true);
+ expect(ctrl.showReorder()).toBe(true);
});
- it('Should add animation class', function() {
- var element = compile('')(scope);
- expect(element.hasClass('my-animation')).toBe(true);
+ it('.showDelete sets/gets', function() {
+ var ctrl = setup();
+ expect(ctrl.showDelete()).toBe(false);
+ ctrl.showDelete(true);
+ expect(ctrl.showDelete()).toBe(true);
});
- it('Should add list-left-editing class because of showDelete', function() {
- expect(listElement.hasClass('list-left-editing')).toBe(false);
- scope.showDelete = true;
- scope.$digest();
- expect(listElement.hasClass('list-left-editing')).toBe(true);
+ it('.canSwipeItems sets/gets', function() {
+ var ctrl = setup();
+ expect(ctrl.canSwipeItems()).toBe(true);
+ ctrl.canSwipeItems(false);
+ expect(ctrl.canSwipeItems()).toBe(false);
});
- it('Should add list-right-editing class because of showReorder', function() {
- expect(listElement.hasClass('list-right-editing')).toBe(false);
- scope.showReorder = true;
- scope.$digest();
- expect(listElement.hasClass('list-right-editing')).toBe(true);
- });
-
- it('Should add item-options-hide class', function() {
- expect(listElement.hasClass('item-options-hide')).toBe(false);
- scope.showReorder = true;
- scope.$digest();
- expect(listElement.hasClass('item-options-hide')).toBe(true);
- });
-
- it('Should reorder', function() {
- scope.onReorder = function(el, start, end) {
- };
-
- listElement = angular.element(' ');
- listElement = compile(listElement)(scope);
-
- var lv = listElement.isolateScope().listView;
-
- spyOn(scope, 'onReorder');
-
- lv.onReorder({}, 0, 1);
-
- expect(scope.onReorder).toHaveBeenCalledWith({}, 0, 1);
+ it('.closeOptionButtons closes calls clearDragEffects', function() {
+ var ctrl = setup();
+ ctrl.listView = { clearDragEffects: jasmine.createSpy('clearDragEffects') };
+ ctrl.closeOptionButtons();
+ expect(ctrl.listView.clearDragEffects).toHaveBeenCalled();
});
});
-describe('Ionic Item Directive', function () {
- var $rootScope, $compile, listCtrl, options, listScope, itemScope, listElement, itemElement;
+describe('ionList directive', function() {
+ beforeEach(module('ionic'));
- beforeEach(module('ionic.ui.list'));
+ function setup(attrs, content) {
+ var el;
+ inject(function($compile, $rootScope) {
+ var scope = $rootScope.$new();
+ el = angular.element(''+(content||'')+' ');
+ el.data('$$ionicScrollController', {
+ scrollView: {},
+ element: angular.element('')
+ });
+ $compile(el)(scope);
+ scope.$apply();
+ });
+ return el;
+ }
+ function flush() {
+ inject(function($timeout) { $timeout.flush(); });
+ }
- beforeEach(inject(function (_$compile_, _$rootScope_) {
- $rootScope = _$rootScope_;
- $compile = _$compile_;
- $rootScope.showDelete = false;
+ it('should put contents in a list wrapper', function() {
+ var el = setup('', '
');
+ expect(el.children().hasClass('list')).toBe(true);
+ expect(el.children().html()).toBe('
');
+ });
- listElement = angular.element('
');
- listElement = _$compile_(listElement)($rootScope);
- listScope = listElement.isolateScope();
+ it('should give options to listView after init', function() {
+ var options;
+ spyOn(ionic.views, 'ListView').andCallFake(function(o) {
+ options = o;
+ });
+ var el = setup();
+ flush();
+ expect(ionic.views.ListView).toHaveBeenCalled();
+ expect(options.el).toBe(el[0]);
+ expect(options.listEl).toBe(el.children()[0]);
+ expect(options.scrollEl).toBe(el.controller('$ionicScroll').element);
+ expect(options.scrollView).toBe(el.controller('$ionicScroll').scrollView);
- listCtrl = listElement.controller('list');
+ spyOn(el.controller('ionList'), 'canSwipeItems').andReturn('swipey');
+ expect(options.canSwipe()).toBe('swipey');
- itemElement = angular.element('').appendTo(listElement);
- itemElement = _$compile_(itemElement)($rootScope);
+ el.scope().$onReorder = jasmine.createSpy('$onReorder');
+ options.onReorder(el, 2, 3);
+ expect(el.scope().$onReorder).toHaveBeenCalledWith(2,3);
+ });
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
+ it('should watch canSwipe if given', function() {
+ var el = setup('can-swipe="shouldSwipe"');
+ flush();
+ expect(el.controller('ionList').canSwipeItems()).toBe(false);
+ el.scope().$apply('shouldSwipe = true');
+ expect(el.controller('ionList').canSwipeItems()).toBe(true);
+ });
+
+ it('should showDelete true', inject(function($animate) {
+ var el = setup('show-delete="shouldDelete"', '
');
+ flush();
+
+ spyOn(el.controller('ionList'), 'closeOptionButtons');
+ spyOn(el.controller('ionList'), 'showDelete');
+ spyOn($animate, 'removeClass');
+
+ el.scope().$apply('shouldDelete = true');
+
+ expect(el.controller('ionList').closeOptionButtons).toHaveBeenCalled();
+ expect(el.controller('ionList').showDelete).toHaveBeenCalledWith(true);
+ expect(el.children().hasClass('list-left-editing')).toBe(true);
+ expect($animate.removeClass).toHaveBeenCalled();
+ expect($animate.removeClass.mostRecentCall.args[0][0])
+ .toBe(el[0].querySelector('.item-delete.item-left-edit'));
+ expect($animate.removeClass.mostRecentCall.args[1]).toBe('ng-hide');
}));
- it('Should set item type from item attribute', inject(function ($timeout) {
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemClass).toBe(undefined);
+ it('should showDelete false', inject(function($animate) {
+ var el = setup('show-delete="shouldDelete"', '
');
+ flush();
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemType).toBe("item-type-test");
- expect(itemElement.hasClass('item-type-test')).toBe(true);
+ el.scope().$apply('shouldDelete = true');
+
+ spyOn(el.controller('ionList'), 'closeOptionButtons');
+ spyOn(el.controller('ionList'), 'showDelete');
+ spyOn($animate, 'addClass');
+
+ el.scope().$apply('shouldDelete = false');
+
+ expect(el.controller('ionList').closeOptionButtons).not.toHaveBeenCalled();
+ expect(el.controller('ionList').showDelete).toHaveBeenCalledWith(false);
+ expect(el.children().hasClass('list-left-editing')).toBe(false);
+ expect($animate.addClass).toHaveBeenCalled();
+ expect($animate.addClass.mostRecentCall.args[0][0])
+ .toBe(el[0].querySelector('.item-delete.item-left-edit'));
+ expect($animate.addClass.mostRecentCall.args[1]).toBe('ng-hide');
}));
- it('Should set item type from list attribute', inject(function ($timeout) {
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemElement.hasClass('list-item-type-test')).toBe(true);
+ it('should showReorder true', inject(function($animate) {
+ var el = setup('show-reorder="shouldReorder"', '
');
+ flush();
+
+ spyOn(el.controller('ionList'), 'closeOptionButtons');
+ spyOn(el.controller('ionList'), 'showReorder');
+ spyOn($animate, 'removeClass');
+
+ el.scope().$apply('shouldReorder = true');
+
+ expect(el.controller('ionList').closeOptionButtons).toHaveBeenCalled();
+ expect(el.controller('ionList').showReorder).toHaveBeenCalledWith(true);
+ expect(el.children().hasClass('list-right-editing')).toBe(true);
+ expect($animate.removeClass).toHaveBeenCalled();
+ expect($animate.removeClass.mostRecentCall.args[0][0])
+ .toBe(el[0].querySelector('.item-reorder.item-right-edit'));
+ expect($animate.removeClass.mostRecentCall.args[1]).toBe('ng-hide');
}));
- it('Should item option buttons from item attribute', inject(function ($timeout) {
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.optionButtons()).toBe(undefined);
- expect(itemScope.itemOptionButtons).toBe(undefined);
- expect(itemElement.find('.item-options').length).toBe(0);
+ it('should showReorder false', inject(function($animate) {
+ var el = setup('show-reorder="shouldReorder"', '
');
+ flush();
- $rootScope.buttons = [
- { text: 'Edit' }, { text: 'Cancel' }
- ];
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.optionButtons().length).toBe(2);
- expect(itemScope.itemOptionButtons.length).toBe(2);
- expect(itemElement.find('.item-options').find('button').length).toBe(2);
+ el.scope().$apply('shouldReorder = true');
+
+ spyOn(el.controller('ionList'), 'closeOptionButtons');
+ spyOn(el.controller('ionList'), 'showReorder');
+ spyOn($animate, 'addClass');
+
+ el.scope().$apply('shouldReorder = false');
+
+ expect(el.controller('ionList').closeOptionButtons).not.toHaveBeenCalled();
+ expect(el.controller('ionList').showReorder).toHaveBeenCalledWith(false);
+ expect(el.children().hasClass('list-right-editing')).toBe(false);
+ expect($animate.addClass).toHaveBeenCalled();
+ expect($animate.addClass.mostRecentCall.args[0][0])
+ .toBe(el[0].querySelector('.item-reorder.item-right-edit'));
+ expect($animate.addClass.mostRecentCall.args[1]).toBe('ng-hide');
}));
-
- it('Should item option buttons from list attribute', inject(function ($timeout) {
- $rootScope.buttons = [
- { text: 'Edit' }, { text: 'Cancel' }
- ];
-
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- expect(listScope.optionButtons().length ).toBe(2);
-
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
-
- expect(itemScope.optionButtons()).toBe(undefined);
- expect(itemScope.itemOptionButtons.length).toBe(2);
- expect(itemElement.find('.item-options').find('button').length).toBe(2);
- }));
-
- it('Should have no option buttons by disabling item canSwipe', inject(function ($timeout) {
- $rootScope.buttons = [
- { text: 'Edit' }, { text: 'Cancel' }
- ];
-
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
-
- expect(itemScope.itemOptionButtons).toBe(undefined);
- }));
-
- it('Should have no option buttons by disabling list canSwipe', inject(function ($timeout) {
- $rootScope.buttons = [
- { text: 'Edit' }, { text: 'Cancel' }
- ];
-
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- expect(listScope.optionButtons().length ).toBe(2);
-
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
-
- expect(itemScope.itemOptionButtons).toBe(undefined);
- }));
-
- it('Should hide delete w/ item can-delete attribute true but no list or item onDelete', inject(function ($timeout) {
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).toBe(undefined);
- expect(itemElement.find('.item-edit').length).toBe(0);
- }));
-
- it('Should hide delete w/ item can-delete attribute false but with item onDelete', inject(function ($timeout) {
- $rootScope.onDelete = function() {};
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).toBe(undefined);
- expect(itemElement.find('.item-edit').length).toBe(0);
- }));
-
- it('Should show delete w/ no item can-delete attribute but with item onDelete', inject(function ($timeout) {
- $rootScope.onDelete = function() {};
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).not.toBe(undefined);
- expect(itemElement.find('.item-left-edit').length).toBe(1);
- expect(itemElement.find('.item-delete').length).toBe(1);
- expect(itemScope.deleteIconClass).toBe("test-icon");
- }));
-
- it('Should hide delete w/ list can-delete attribute true but no list or item onDelete', inject(function ($timeout) {
- $rootScope.onDelete = function() {};
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
-
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).toBe(undefined);
- expect(itemElement.find('.item-edit').length).toBe(0);
- }));
-
- it('Should hide delete w/ list can-delete attribute false but with list onDelete', inject(function ($timeout) {
- $rootScope.onDelete = function() {};
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
-
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).toBe(undefined);
- expect(itemElement.find('.item-edit').length).toBe(0);
- }));
-
- it('Should hide delete w/ list can-delete attribute false but with item onDelete', inject(function ($timeout) {
- $rootScope.onDelete = function() {};
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
-
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).toBe(undefined);
- expect(itemElement.find('.item-edit').length).toBe(0);
- }));
-
- it('Should show delete w/ no can-delete attribute but with list onDelete', inject(function ($timeout) {
- $rootScope.onDelete = function() {};
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.deleteClick).not.toBe(undefined);
- expect(itemElement.find('.item-left-edit').length).toBe(1);
- expect(itemElement.find('.item-delete').length).toBe(1);
-
- expect(itemScope.deleteIconClass).toBe("test-icon");
- }));
-
- it('Should not be able to reorder cuz no item or list can-reorder attribute true', inject(function ($timeout) {
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.reorderIconClass).toBe(undefined);
- expect(itemElement.find('.item-reorder').length).toBe(0);
- expect(itemElement.find('.item-right-edit').length).toBe(0);
- }));
-
- it('Should be able to reorder cuz item can-reorder attribute true', inject(function ($timeout) {
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.reorderIconClass).toBe('test-icon');
- expect(itemElement.find('.item-reorder').length).toBe(1);
- expect(itemElement.find('.item-right-edit').length).toBe(1);
- }));
-
- it('Should be able to reorder cuz list can-reorder attribute true', inject(function ($timeout) {
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.reorderIconClass).toBe('test-icon');
- expect(itemElement.find('.item-reorder').length).toBe(1);
- expect(itemElement.find('.item-right-edit').length).toBe(1);
- }));
-
- it('Should not have options cuz no optionButtons', inject(function ($timeout) {
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemOptionButtons).toBe(undefined);
- expect(itemElement.find('.item-options').length).toBe(0);
- }));
-
- it('Should be able to reorder cuz list can-reorder attribute false and item can-reorder true', inject(function ($timeout) {
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.reorderIconClass).toBe('ion-navicon');
- expect(itemElement.find('.item-reorder').length).toBe(1);
- expect(itemElement.find('.item-right-edit').length).toBe(1);
- }));
-
- it('Should not have options cuz item can-swipe false', inject(function ($timeout) {
- $rootScope.optionButtons = [{text:'BUTTON'}];
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemOptionButtons).toBe(undefined);
- expect(itemElement.find('.item-options').length).toBe(0);
- }));
-
- it('Should not have options cuz list can-swipe false', inject(function ($timeout) {
- $rootScope.optionButtons = [{text:'BUTTON'}];
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemOptionButtons).toBe(undefined);
- expect(itemElement.find('.item-options').length).toBe(0);
- }));
-
- it('Should have options cuz item option-buttons and no can-swipe false', inject(function ($timeout) {
- $rootScope.optionButtons = [{text:'BUTTON'}];
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemOptionButtons.length).toBe(1);
- expect(itemElement.find('.item-options').find('button').length).toBe(1);
- }));
-
- it('Should have options cuz list option-buttons and no can-swipe false', inject(function ($timeout) {
- $rootScope.optionButtons = [{text:'BUTTON'}];
- listElement = angular.element('');
- listElement = $compile(listElement)($rootScope);
- listScope = listElement.isolateScope();
- itemElement = angular.element('').appendTo(listElement);
- itemElement = $compile(itemElement)($rootScope);
- $rootScope.$digest();
- itemScope = itemElement.isolateScope();
- expect(itemScope.itemOptionButtons.length).toBe(1);
- expect(itemElement.find('.item-options').find('button').length).toBe(1);
- }));
-
});
+describe('ionItem directive', function() {
+ beforeEach(module('ionic'));
+ function setup(attrs, content) {
+ var el;
+ inject(function($rootScope, $compile) {
+ el = angular.element('').html(content || '');
+ el.data('$ionListController', {});
+ $compile(el)($rootScope);
+ $rootScope.$apply();
+ });
+ return el;
+ }
+
+ it('should be simple item by default', function() {
+ var el = setup('', '{{1}} 2 ');
+ expect(el.html()).toBe('1 2 ');
+ expect(el.hasClass('item')).toBe(true);
+ expect(el.hasClass('item-complex')).toBe(false);
+ });
+ ['href', 'ng-href'].forEach(function(attr) {
+ it('should be complex anchor if '+attr+' is defined', function() {
+ var el = setup(attr+'="something"');
+ expect(el.hasClass('item item-complex')).toBe(true);
+ expect(el.children()[0].tagName).toBe('A');
+ expect(el.children().hasClass('item-content')).toBe(true);
+ expect(el.children().attr('ng-href')).toBe('something');
+ });
+ });
+ ['ion-option-button','ion-reorder-button','ion-delete-button'].forEach(function(tag) {
+ it('should be complex div if '+tag+' is found', function() {
+ var el = setup('', tag);
+ expect(el.hasClass('item item-complex')).toBe(true);
+ expect(el.children()[0].tagName).toBe('DIV');
+ expect(el.children().hasClass('item-content')).toBe(true);
+ expect(el.children().html()).toBe(tag);
+ });
+ });
+});
+
+describe('ionDeleteButton directive', function() {
+ beforeEach(module('ionic'));
+ it('should have delete button', inject(function($compile, $rootScope) {
+ var setSpy = jasmine.createSpy('setDeleteButton')
+ var el = angular.element(' ');
+ el.data('$ionListController', {});
+ $compile(el)($rootScope.$new());
+ $rootScope.$apply();
+
+ var deleteContainer = angular.element(el[0].querySelector('.item-left-edit.item-delete'));
+ expect(deleteContainer.length).toBe(1);
+ expect(deleteContainer.children().hasClass('button icon button-icon')).toBe(true);
+ }));
+});
+
+describe('ionReorderButton directive', function() {
+ beforeEach(module('ionic'));
+ it('should have reorder button', inject(function($compile, $rootScope) {
+ var setSpy = jasmine.createSpy('setReorderButton')
+ var el = angular.element(' ');
+ el.data('$ionListController', {});
+ $compile(el)($rootScope.$new());
+ $rootScope.$apply();
+
+ var reorderContainer = angular.element(el[0].querySelector('.item-right-edit.item-reorder'));
+ expect(reorderContainer.length).toBe(1);
+ expect(reorderContainer.children().hasClass('button icon button-icon')).toBe(true);
+ expect(reorderContainer.attr('data-prevent-scroll')).toBe('true');
+ expect(reorderContainer.children().attr('data-prevent-scroll')).toBe('true');
+ }));
+});
+
+describe('ionOptionButton directive', function() {
+ beforeEach(module('ionic'));
+ it('should have option button', inject(function($compile, $rootScope) {
+ var setSpy = jasmine.createSpy('setOptionButton')
+ var el = angular.element(' ');
+ el.data('$ionListController', {});
+ $compile(el)($rootScope.$new());
+ $rootScope.$apply();
+
+ var optionContainer = angular.element(el[0].querySelector('.item-options'));
+ expect(optionContainer.length).toBe(1);
+ expect(optionContainer.children().hasClass('button')).toBe(true);
+ }));
+});
diff --git a/js/ext/angular/test/list.html b/js/ext/angular/test/list.html
index ece83d86d5..16742227df 100644
--- a/js/ext/angular/test/list.html
+++ b/js/ext/angular/test/list.html
@@ -47,7 +47,6 @@
{{ editBtnText }}
- Toggle Left Menu
List Tests
@@ -57,91 +56,29 @@
@@ -232,8 +169,11 @@
console.log('onDelete from the "list" on-delete attribute', item, index);
$scope.items.splice(index, 1);
};
- $scope.onReorder = function(el, start, end) {
- console.log('On reorder', el, start, end);
+ $scope.onReorder = function(item, fromIndex, toIndex) {
+ console.log('On reorder', item, fromIndex, toIndex);
+ $scope.items.splice(fromIndex, 1);
+ $scope.items.splice(toIndex, 0, item);
+ console.log($scope.items);
};
$scope.optionButtons1 = [
diff --git a/js/ext/angular/test/sideMenu.html b/js/ext/angular/test/sideMenu.html
index f499b39933..84c5fc8dd1 100644
--- a/js/ext/angular/test/sideMenu.html
+++ b/js/ext/angular/test/sideMenu.html
@@ -22,8 +22,11 @@
Hello
Content
-
- Sup
+
+
+ Sup
+ Hello
+
diff --git a/js/ext/angular/test/tabs.html b/js/ext/angular/test/tabs.html
index 83a90b1e34..b749a68f56 100644
--- a/js/ext/angular/test/tabs.html
+++ b/js/ext/angular/test/tabs.html
@@ -54,27 +54,14 @@