Browse files

bugfix for #14 including refactoring of the create/delete event liste…

…ning and fireing
  • Loading branch information...
1 parent 1633d5c commit c0b0247a59fde33b6f691c2891913661a9926fc8 Tobias Bosch committed Feb 1, 2012
View
2 Changelog.md
@@ -5,7 +5,7 @@ Changelog
------------
- Allow an object to be passed to `$navigate` service as first argument to leverage the full power
of jqm `changePage` function.
-
+- ng:switch now works correctly.
1.0.4
View
1 src/main/webapp/jqm-angular.js
@@ -12,6 +12,7 @@ define([
'jqmng/sharedController',
'jqmng/widgets/pageCompile',
'jqmng/widgets/angularRepeat',
+ 'jqmng/widgets/angularSwitch',
'jqmng/widgets/angularInput',
'jqmng/widgets/angularSelect',
'jqmng/widgets/disabledHandling',
View
13 src/main/webapp/jqmng/widgets/angularRepeat.js
@@ -3,13 +3,11 @@ define(['jqmng/widgets/widgetProxyUtil'], function(proxyUtil) {
* Modify original ng:repeat so that all created items directly have a parent
* (old style repeat). This is slower, however simplifies the integration with jquery mobile a lot!
* <p>
- * This will furthermore create the events "elementsAdded" and "elementsRemoved" if
- * elements were added or deleted (only once per eval).
- * <p>
* This also takes care for jquery widgets wrapping themselves into other elements
* (e.g. setting a div as new parent).
*/
angular.widget('@ng:repeat', function(expression, element) {
+ element.attr('ngm:createwidgets', 'true');
element.removeAttr('ng:repeat');
element.replaceWith(angular.element('<!-- ng:repeat: ' + expression + ' -->'));
var linker = this.compile(element);
@@ -39,8 +37,6 @@ define(['jqmng/widgets/widgetProxyUtil'], function(proxyUtil) {
collectionLength = angular.Array.size(collection, true),
childScope,
key;
- var addedElements = [];
- var removedElements = [];
for (key in collection) {
if (collection.hasOwnProperty(key)) {
@@ -78,7 +74,6 @@ define(['jqmng/widgets/widgetProxyUtil'], function(proxyUtil) {
appendPosition.after(clone);
lastIterElement = clone;
});
- addedElements.push(lastIterElement);
}
index ++;
}
@@ -89,15 +84,9 @@ define(['jqmng/widgets/widgetProxyUtil'], function(proxyUtil) {
// Sencha Integration: Destroy widgets
var child = children.pop();
var childElement = child.$element;
- removedElements.push(childElement);
childElement.remove();
}
- if (addedElements.length>0) {
- parent.trigger('elementsAdded', addedElements);
- } else if (removedElements.length>0) {
- parent.trigger('elementsRemoved', removedElements);
- }
}, iterStartElement);
};
});
View
12 src/main/webapp/jqmng/widgets/angularSwitch.js
@@ -0,0 +1,12 @@
+define(['jqmng/widgets/widgetProxyUtil'], function(proxyUtil) {
+ /**
+ * Modify the original ng:switch so that it adds the ngm:createwidgets attribute to all cases that will
+ * fire the jqm create event whenever a new scope is created.
+ */
+ proxyUtil.createAngularWidgetProxy('ng:switch', function(element) {
+ element.children().attr('ngm:createwidgets', 'true');
+ return function(element, origBinder) {
+ return origBinder();
+ }
+ });
+});
View
18 src/main/webapp/jqmng/widgets/jqmListView.js
@@ -25,10 +25,22 @@ define([
fn._create = function() {
var self = this;
var res = oldCreate.apply(this, arguments);
- // refresh the list when the children change
- this.element.bind('elementsAdded elementsRemoved', function(event) {
- event.stopPropagation();
+ // refresh the list when the children change.
+ this.element.bind('create', function(event) {
self.refresh();
+ // register listeners when the children are destroyed.
+ // Do this only once per child.
+ var children = self.element.children('li');
+ var child, i;
+ for (i=0; i<children.length; i++) {
+ child = children.eq(i);
+ if (!child.data('listlistener')) {
+ child.data('listlistener', true);
+ child.bind("remove", function() {
+ self.refresh();
+ });
+ }
+ }
});
};
});
View
3 src/main/webapp/jqmng/widgets/jqmSelectMenu.js
@@ -1,7 +1,6 @@
define(['jquery'], function($) {
- // selectmenu may create:
- // - parent element
+ // selectmenu may create parent element and extra pages
var fn = $.mobile.selectmenu.prototype;
var oldDestroy = fn.destroy;
fn.destroy = function() {
View
2 src/main/webapp/jqmng/widgets/jqmSlider.js
@@ -1,5 +1,5 @@
define(['jquery'], function($) {
- // Button wraps the actual button into another div that is stored in the
+ // Slider wraps the actual input into another div that is stored in the
// "slider" property.
var fn = $.mobile.slider.prototype;
var oldDestroy = fn.destroy;
View
12 src/main/webapp/jqmng/widgets/pageCompile.js
@@ -47,8 +47,6 @@ define(['jquery', 'angular', 'jqmng/globalScope'], function($, angular, globalSc
degradeInputs(page);
angular.compile(page)(childScope);
parentScope.$eval();
- // The second pagecreate does only initialize
- // the widgets that we did not already create by angular.
page.trigger("pagecreate");
});
@@ -78,10 +76,14 @@ define(['jquery', 'angular', 'jqmng/globalScope'], function($, angular, globalSc
});
/**
- * Create jquery elements when elements were added to the dom.
+ * When scopes are created by angular, the elements within the scope need to be enhanced by jquery mobile.
+ * We do this by using a special directive that triggers the corresponding event.
+ * In a later release of angular there will be angular events that we can hook to.
*/
- $(document).bind('elementsAdded', function(event) {
- $(event.target).trigger('create');
+ angular.directive("ngm:createwidgets", function(expression) {
+ return function(element) {
+ element.parent().trigger('create');
+ };
});
var currScope = null;
View
10 src/test/webapp/devSnippetPage.html
@@ -23,7 +23,15 @@
<div data-role="page" id="start">
<div data-role="content">
- <a href="" ngm:click="$navigate({target: 'page2', transition:'pop'})">Test</a>
+ <input type="submit" ng:click="flag = true">
+ <a href="" ngm:click="list = [1,2]" data-role="button">Fill</a>
+ <a href="" ngm:click="list = []" data-role="button">Clear</a>
+ <ul data-role="listview" data-inset="true">
+ <li ng:repeat="l in list">
+ Test
+ <button>Test</button>
+ </li>
+ </ul>
</div>
</div>
View
27 src/test/webapp/ui/selectmenuSpec.js
@@ -5,10 +5,9 @@ define(function() {
var scope, dialog, dialogOpen;
loadHtml('/jqmng/ui/test-fixture.html', function(frame) {
var page = frame.$('#start');
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
page.append(
'<div data-role="content">' +
- '<select ng:repeat="item in [1]" name="mysel" id="mysel" data-native-menu="false"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
+ '<select name="mysel" id="mysel" data-native-menu="false"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
'</div>');
});
runs(function() {
@@ -48,10 +47,9 @@ define(function() {
it('should save the ui value into the model when using non native menus', function() {
loadHtml('/jqmng/ui/test-fixture.html', function(frame) {
var page = frame.$('#start');
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
page.append(
'<div data-role="content">' +
- '<select ng:repeat="item in [1]" name="mysel" id="mysel" data-native-menu="false"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
+ '<select name="mysel" id="mysel" data-native-menu="false"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
'</div>');
});
runs(function() {
@@ -72,13 +70,12 @@ define(function() {
});
});
- it('should save the model value into the ui', function() {
+ it('should save the model value into the ui when using non native menus', function() {
loadHtml('/jqmng/ui/test-fixture.html', function(frame) {
var page = frame.$('#start');
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
page.append(
'<div data-role="content">' +
- '<select ng:repeat="item in [1]" name="mysel" id="mysel" data-native-menu="false"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
+ '<select name="mysel" id="mysel" data-native-menu="false"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
'</div>');
});
runs(function() {
@@ -101,10 +98,9 @@ define(function() {
it('should use the disabled attribute', function() {
loadHtml('/jqmng/ui/test-fixture.html', function(frame) {
var page = frame.$('#start');
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
page.append(
'<div data-role="content">' +
- '<select ng:repeat="item in [1]" name="mysel" id="mysel" data-native-menu="false" ng:bind-attr="{disabled: \'{{disabled}}\'}"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
+ '<select name="mysel" id="mysel" data-native-menu="false" ng:bind-attr="{disabled: \'{{disabled}}\'}"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
'</div>');
});
runs(function() {
@@ -122,24 +118,23 @@ define(function() {
});
});
- it('should be removable when ng:repeat shrinks', function() {
+ it('should be removable', function() {
loadHtml('/jqmng/ui/test-fixture.html', function(frame) {
var page = frame.$('#start');
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
page.append(
- '<div data-role="content" ng:init="mylist = [1,2]">' +
- '<select ng:repeat="item in mylist" name="mysel" id="mysel" data-native-menu="false" ng:bind-attr="{disabled: \'{{disabled}}\'}"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
+ '<div data-role="content">' +
+ '<select name="mysel" id="mysel" data-native-menu="false" ng:bind-attr="{disabled: \'{{disabled}}\'}"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
'</div>');
});
runs(function() {
var page = testframe().$("#start");
var scope = page.scope();
// ui select creates a new parent for itself
var content = page.find(":jqmData(role='content')");
- expect(content.children('div').length).toEqual(2);
- scope.mylist = [1];
- scope.$root.$eval();
expect(content.children('div').length).toEqual(1);
+ // select creates a parent div. This should be removed when the select is removed.
+ content.find('select').eq(0).remove();
+ expect(content.children('div').length).toEqual(0);
});
});
View
3 src/test/webapp/unit-tests.js
@@ -18,5 +18,6 @@ define([
'unit/radioSpec',
'unit/selectSliderSpec',
'unit/textInputSpec',
- 'unit/listViewSpec'
+ 'unit/listViewSpec',
+ 'unit/switchSpec'
]);
View
14 src/test/webapp/unit/buttonSpec.js
@@ -2,8 +2,7 @@ define(["unit/testUtils"], function(utils) {
describe("button", function() {
it('should allow clicks via ng:click', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<button ng:repeat="item in [1]" id="mysel" ng:click="flag = true">Test</button>');
+ var d = utils.compileInPage('<button id="mysel" ng:click="flag = true">Test</button>');
var page = d.page;
var input = d.element;
var scope = input.scope();
@@ -13,7 +12,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- var d = utils.compileInPage('<button ng:repeat="item in [1]" id="mysel" ng:click="flag = true" ng:bind-attr="{disabled: \'{{disabled}}\'}">Test</button>');
+ var d = utils.compileInPage('<button id="mysel" ng:click="flag = true" ng:bind-attr="{disabled: \'{{disabled}}\'}">Test</button>');
var page = d.page;
var input = d.element;
var scope = input.scope();
@@ -26,15 +25,14 @@ define(["unit/testUtils"], function(utils) {
expect(parentDiv.hasClass('ui-disabled')).toBeTruthy();
});
- it('should be removable when ng:repeat shrinks', function() {
- var d = utils.compileInPage('<div ng:init="mylist=[1,2]"><button ng:repeat="item in mylist" id="mysel" ng:click="flag = true">Test</button></div>');
+ it('should be removable', function() {
+ var d = utils.compileInPage('<div><button>1</button><button>2</button></div>');
var page = d.page;
- // ui select creates a new parent for itself
var container = d.element;
var scope = container.scope();
expect(container.children('div').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
+ // removal of the button should also remove the parent div
+ container.find('button').eq(0).remove();
expect(container.children('div').length).toEqual(1);
});
});
View
22 src/test/webapp/unit/checkBoxSpec.js
@@ -2,8 +2,7 @@ define(["unit/testUtils"], function(utils) {
describe("checkbox", function() {
it('should save the ui value into the model', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<div ng:repeat="item in [1]">' +
+ var d = utils.compileInPage('<div>' +
'<input name="mysel" id="mysel" type="checkbox">{{mysel}}<label for="mysel" id="mylab">Entry</label>' +
'</div>');
var page = d.page;
@@ -19,9 +18,8 @@ define(["unit/testUtils"], function(utils) {
});
it('should save the model value into the ui', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<div ng:repeat="item in [1]">' +
+ '<div>' +
'<input name="mysel" id="mysel" type="checkbox"><label for="mysel" id="mylab">Entry</label>' +
'</div>');
var page = d.page;
@@ -39,9 +37,8 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<div ng:repeat="item in [1]">' +
+ '<div>' +
'<input name="mysel" id="mysel" type="checkbox" value="false" ng:bind-attr="{disabled: \'{{disabled}}\'}"><label for="mysel" id="mylab">Entry</label>' +
'</div>');
var page = d.page;
@@ -55,19 +52,6 @@ define(["unit/testUtils"], function(utils) {
scope.$eval();
expect(parentDiv.hasClass('ui-disabled')).toBeTruthy();
});
-
- it('should enhance checkboxes when ng:repeat is used (not only during page compile)', function() {
- var d = utils.compileInPage(
- '<div><div ng:repeat="item in items" id="mydiv">' +
- '<input name="mysel" id="mysel{{$index}}" type="checkbox" value="false"><label for="mysel{{$index}}" id="mylab{{$index}}">Entry</label>' +
- '</div></div>');
- var page = d.page;
- var parentDiv = d.element;
- expect(parentDiv.find('.ui-checkbox').length).toBe(0);
- page.scope().$set('items', [1,2]);
- page.scope().$eval();
- expect(parentDiv.find('.ui-checkbox').length).toBe(2);
- });
});
});
View
20 src/test/webapp/unit/collapsibleSpec.js
@@ -3,8 +3,7 @@ define(["unit/testUtils"], function(utils) {
describe("collapsible", function() {
it('should collapse the content by a click', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<div id="el" data-role="collapsible" ng:repeat="item in [1]">' +
+ var d = utils.compileInPage('<div id="el" data-role="collapsible">' +
'<h3>header</h3>' +
'<p>content</p>' +
'</div>');
@@ -15,23 +14,6 @@ define(["unit/testUtils"], function(utils) {
header.trigger('click');
expect(content.hasClass('ui-collapsible-content-collapsed')).toBeFalsy();
});
-
- it('should be removable when ng:repeat shrinks', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<div ng:init="mylist = [1,2]">' +
- '<div id="el" data-role="collapsible" ng:repeat="item in mylist">' +
- '<h3>header</h3>' +
- '<p>content</p>' +
- '</div>' +
- '</div>');
- var container = d.element;
- var scope = container.scope();
- expect(container.children('div').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
- expect(container.children('div').length).toEqual(1);
- });
-
});
});
View
17 src/test/webapp/unit/inputButtonSpec.js
@@ -3,9 +3,8 @@ define(["unit/testUtils"], function(utils) {
describe("input button", function() {
it('should allow clicks via ng:click', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<input type="submit" ng:repeat="item in [1]" id="mysel" ng:click="flag = true">'
+ '<input type="submit" ng:click="flag = true">'
);
var input = d.element;
var scope = input.scope();
@@ -15,9 +14,8 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<input type="submit" ng:repeat="item in [1]" id="mysel" ng:click="flag = true" ng:bind-attr="{disabled: \'{{disabled}}\'}">');
+ '<input type="submit" ng:click="flag = true" ng:bind-attr="{disabled: \'{{disabled}}\'}">');
var input = d.element;
var scope = input.scope();
var parentDiv = input.parent();
@@ -29,16 +27,15 @@ define(["unit/testUtils"], function(utils) {
expect(parentDiv.hasClass('ui-disabled')).toBeTruthy();
});
- it('should be removable when ng:repeat shrinks', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<div ng:init="mylist=[1,2]">' +
- '<input type="submit" ng:repeat="item in mylist" id="mysel" ng:click="flag = true">' +
+ it('should be removable', function() {
+ var d = utils.compileInPage('<div>' +
+ '<input type="submit" value="1"><input type="submit" value="2"></input>' +
'</div>');
var container = d.element;
var scope = container.scope();
expect(container.children('div').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
+ // removal of the button should also remove the parent div
+ container.find('input').eq(0).remove();
expect(container.children('div').length).toEqual(1);
});
});
View
24 src/test/webapp/unit/inputSliderSpec.js
@@ -2,8 +2,7 @@ define(["unit/testUtils"], function(utils) {
describe("inputSlider", function() {
it('should save the ui value into the model', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<input ng:repeat="l in [0] " type="number" data-type="range" name="mysel" id="mysel" value="150" min="0" max="300">');
+ var d = utils.compileInPage('<input type="number" data-type="range" name="mysel" value="150" min="0" max="300">');
var input = d.element;
var scope = input.scope();
expect(scope.$get('mysel')).toEqual("150");
@@ -13,8 +12,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should save the model value into the ui', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<input ng:repeat="l in [0] " type="number" data-type="range" name="mysel" id="mysel" value="150" min="0" max="300">');
+ var d = utils.compileInPage('<input type="number" data-type="range" name="mysel" value="150" min="0" max="300">');
var input = d.element;
var scope = input.scope();
expect(input[0].value).toEqual("150");
@@ -24,8 +22,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<input ng:repeat="l in [0] " type="number" data-type="range" name="mysel" id="mysel" value="150" min="0" max="300" ng:bind-attr="{disabled: \'{{disabled}}\'}">');
+ var d = utils.compileInPage('<input type="number" data-type="range" name="mysel" value="150" min="0" max="300" ng:bind-attr="{disabled: \'{{disabled}}\'}">');
var input = d.element;
var scope = input.scope();
scope.$set('disabled', false);
@@ -38,16 +35,17 @@ define(["unit/testUtils"], function(utils) {
expect(disabled).toEqual(true);
});
- it('should be removable when ng:repeat shrinks', function() {
- var d = utils.compileInPage('<div ng:init="mylist = [1,2]">' +
- '<input ng:repeat="l in mylist " type="number" data-type="range" name="mysel" id="mysel" value="150" min="0" max="300">' +
+ it('should be removable', function() {
+ var d = utils.compileInPage('<div>' +
+ '<input type="number" data-type="range" value="150" min="0" max="300">' +
+ '<input type="number" data-type="range" value="150" min="0" max="300">' +
'</div>');
var container = d.element;
var scope = container.scope();
- expect(container.children('.ui-slider').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
- expect(container.children('.ui-slider').length).toEqual(1);
+ expect(container.children('div').length).toEqual(2);
+ // removal of the slider should also remove the parent div
+ container.find('input').eq(0).remove();
+ expect(container.children('div').length).toEqual(1);
});
});
View
77 src/test/webapp/unit/listViewSpec.js
@@ -1,9 +1,9 @@
define(["unit/testUtils"], function(utils) {
describe("listview", function() {
- it('should be usable without ng:repeat', function() {
+ it('should be working without ng:repeat', function() {
var d = utils.compileInPage(
- '<ul data-role="listview" ng:repeat="item in [1]">' +
+ '<ul data-role="listview">' +
'<li id="entry">Test</li>' +
'</ul>');
var list = d.element;
@@ -13,61 +13,62 @@ define(["unit/testUtils"], function(utils) {
it('should be usable with ng:repeat', function() {
var d = utils.compileInPage(
- '<ul data-role="listview" ng:repeat="i in [1]">' +
+ '<ul data-role="listview">' +
'<li ng:repeat="item in [1]">{{item}} Test</li>' +
'</ul');
var page = d.page;
var li = page.find("li");
expect(li.hasClass('ui-li')).toBeTruthy();
});
- it('should refresh entries if used with ng:repeat', function() {
+ it('should refresh entries when they are added and enhanced by the create event', function() {
var d = utils.compileInPage(
- '<ul data-role="listview" ng:repeat="item in [1]">' +
- '<li ng:repeat="item in list">Test</li>' +
- '</ul>');
+ '<ul data-role="listview" data-inset="true"><li>1</li></ul>');
var list = d.element;
- var li = list.find("li");
- var scope = list.scope();
- expect(li.length).toEqual(0);
- scope.$set('list', [1,2]);
- scope.$eval();
- li = list.find("li");
- expect(li.length).toEqual(2);
- for (var i = 0; i < li.length; i++) {
- expect($(li[i]).hasClass('ui-li')).toBeTruthy();
- }
+ var lis = list.find("li");
+ expect(lis.eq(0).hasClass('ui-corner-top'));
+ expect(lis.eq(0).text()).toBe('1');
+ expect(lis.eq(0).hasClass('ui-corner-bottom'));
+ list.append('<li>2</li>');
+ list.trigger('create');
+ lis = list.find("li");
+ expect(lis.length).toEqual(2);
+ expect(lis.eq(0).hasClass('ui-corner-top'));
+ expect(lis.eq(0).text()).toBe('1');
+ expect(lis.eq(1).hasClass('ui-corner-bottom'));
+ expect(lis.eq(1).text()).toBe('2');
});
- it('should be removable when ng:repeat shrinks', function() {
- var d = utils.compileInPage('<div ng:init="mylist = [1,2]">' +
- '<ul data-role="listview" ng:repeat="item in mylist">' +
- '<li>Test</li>' +
- '</ul>' +
- '</div>');
+ it('should refresh when entries are removed', function() {
+ var d = utils.compileInPage(
+ '<ul data-role="listview" data-inset="true"><li>1</li><li>2</li></ul>');
var container = d.element;
- var scope = container.scope();
- expect(container.children('ul').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
- expect(container.children('ul').length).toEqual(1);
+ var lis = container.children('li');
+ expect(lis.length).toEqual(2);
+ expect(lis.eq(0).hasClass('ui-corner-top'));
+ expect(lis.eq(0).text()).toBe('1');
+ expect(lis.eq(1).hasClass('ui-corner-bottom'));
+ expect(lis.eq(1).text()).toBe('2');
+ container.children('li').eq(0).remove();
+ var lis = container.children('li');
+ expect(lis.eq(0).hasClass('ui-corner-top'));
+ expect(lis.eq(0).text()).toBe('2');
+ expect(lis.eq(0).hasClass('ui-corner-bottom'));
});
- it('should be removable when ng:repeat shrinks and subpages are used', function() {
- var d = utils.compileInPage('<div ng:init="mylist = [1,2]">' +
- '<ul data-role="listview" ng:repeat="item in mylist" id="list{{$index}}">' +
+ it('should be removable when subpages are used', function() {
+ var d = utils.compileInPage('<div>' +
+ '<ul data-role="listview" id="list1">' +
'<li>Test' +
'<ul><li>Item 2.1</li><li>Item 2.2</li></ul>' +
'</li></ul>' +
'</div>');
var container = d.element;
- var scope = container.scope();
- expect(container.children('ul').length).toEqual(2);
- // ui select creates sub pages.
- expect($(":jqmData(role='page')").length).toEqual(3);
- scope.mylist = [1];
- scope.$eval();
- expect($(":jqmData(role='page')").length).toEqual(3);
+ var list = container.children('ul');
+ // ui select creates sub pages for nested uls.
+ expect($(":jqmData(role='page')").length).toEqual(2);
+ list.remove();
+ expect($(":jqmData(role='page')").length).toEqual(1);
});
});
View
9 src/test/webapp/unit/radioSpec.js
@@ -3,8 +3,7 @@ define(["unit/testUtils"], function(utils) {
describe("radio", function() {
it('should save the ui value into the model', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<div ng:repeat="item in [1]">' +
+ var d = utils.compileInPage('<div>' +
'<input name="mysel" id="mysel" type="radio" value="v1"><label for="mysel" id="mylab">Entry</label>' +
'</div>');
var input = d.element.find("input");
@@ -18,8 +17,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should save the model value into the ui', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<div ng:repeat="item in [1]">' +
+ var d = utils.compileInPage('<div>' +
'<input name="mysel" id="mysel" type="radio" value="v1"><label for="mysel" id="mylab">Entry</label>' +
'</div>');
var input = d.element.find("input");
@@ -36,9 +34,8 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<div ng:repeat="item in [1]">' +
+ '<div>' +
'<input name="mysel" id="mysel" type="radio" value="v1" ng:bind-attr="{disabled: \'{{disabled}}\'}"><label for="mysel" id="mylab">Entry</label>' +
'</div>');
var input = d.element.find("input");
View
29 src/test/webapp/unit/repeatSpec.js
@@ -1,24 +1,29 @@
define(['angular'], function(angular) {
describe('ng:repeat', function() {
- it('should fire elemensAdded and elementsRemoved when new elements are created / deleted', function() {
+ it("should fire the create event for every entry when the list grows", function() {
var element = angular.element('<div><div ng:repeat="l in list"></div></div>');
var scope = angular.compile(element)();
- var added = 0;
- var removed = 0;
- element.bind('elementsAdded', function() {
- added++;
- });
- element.bind('elementsRemoved', function() {
- removed++;
+ var createCount = 0;
+ element.bind('create', function() {
+ createCount++;
});
scope.list = [0,1];
scope.$eval();
- expect(added).toEqual(1);
- expect(removed).toEqual(0);
+ expect(createCount).toEqual(2);
+ });
+
+ it("should fire the remove event for every entry when the list shrinks", function() {
+ var element = angular.element('<div><div ng:repeat="l in list"></div></div>');
+ var scope = angular.compile(element)();
+ scope.list = [0,1];
+ scope.$eval();
+ var removeCount = 0;
+ element.children('div').bind('remove', function() {
+ removeCount++;
+ });
scope.list = [];
scope.$eval();
- expect(added).toEqual(1);
- expect(removed).toEqual(1);
+ expect(removeCount).toEqual(2);
});
it('should append new elements at the same level even when they wrap themselves in new parents', function() {
View
24 src/test/webapp/unit/selectSliderSpec.js
@@ -2,9 +2,8 @@ define(["unit/testUtils"], function(utils) {
describe("selectSlider", function() {
it('should save the ui value into the model', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<select ng:repeat="item in [1]" name="mysel" id="mysel" data-role="slider"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>'
+ '<select name="mysel" data-role="slider"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>'
);
var select = d.element;
var scope = select.scope();
@@ -18,8 +17,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should save the model value into the ui', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<select ng:repeat="item in [1]" name="mysel" id="mysel" data-role="slider"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>');
+ var d = utils.compileInPage('<select name="mysel" data-role="slider"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>');
var select = d.element;
var scope = select.scope();
expect(select[0].value).toEqual("v1");
@@ -35,9 +33,8 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
var d = utils.compileInPage(
- '<select ng:repeat="item in [1]" name="mysel" id="mysel" data-role="slider" ng:bind-attr="{disabled: \'{{disabled}}\'}"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>');
+ '<select name="mysel" data-role="slider" ng:bind-attr="{disabled: \'{{disabled}}\'}"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>');
var select = d.element;
var scope = select.scope();
scope.$set('disabled', false);
@@ -50,16 +47,17 @@ define(["unit/testUtils"], function(utils) {
expect(disabled).toEqual(true);
});
- it('should be removable when ng:repeat shrinks', function() {
- var d = utils.compileInPage('<div ng:init="mylist = [1,2]">' +
- '<select ng:repeat="item in mylist" name="mysel" id="mysel" data-role="slider"><option value="v1" default="true">v1</option><option value="v2">v2</option></select>' +
+ it('should be removable', function() {
+ var d = utils.compileInPage('<div>' +
+ '<select name="mysel" data-role="slider"><option value="v1" default="true">v1</option></select>' +
+ '<select name="mysel2" data-role="slider"><option value="v1" default="true">v1</option></select>' +
'</div>');
var container = d.element;
var scope = container.scope();
- expect(container.children('.ui-slider').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
- expect(container.children('.ui-slider').length).toEqual(1);
+ expect(container.children('div').length).toEqual(2);
+ // removal of the slider should also remove the parent div
+ container.find("select").eq(0).remove();
+ expect(container.children('div').length).toEqual(1);
});
});
View
40 src/test/webapp/unit/switchSpec.js
@@ -0,0 +1,40 @@
+define(['angular'], function(angular) {
+ describe('ng:switch', function() {
+ it("should fire the create event for every entry that is created", function() {
+ var element = angular.element('<ng:switch on="value">' +
+ '<div ng:switch-when="case1"><a href="" data-role="button">b1</a></div>'+
+ '<div ng:switch-when="case2"><a href="" data-role="button">b2</a></div>'+
+ '</ng:switch>');
+ var scope = angular.compile(element)();
+ var createCount = 0;
+ element.bind('create', function() {
+ createCount++;
+ });
+ scope.$eval();
+ expect(createCount).toEqual(0);
+ scope.value = 'case1';
+ scope.$eval();
+ expect(createCount).toEqual(1);
+ });
+
+ it("should fire the remove event for every entry that is removed", function() {
+ var element = angular.element('<ng:switch on="value">' +
+ '<div ng:switch-when="case1"><a href="" data-role="button">b1</a></div>'+
+ '<div ng:switch-when="case2"><a href="" data-role="button">b2</a></div>'+
+ '</ng:switch>');
+ var scope = angular.compile(element)();
+ scope.value = 'case1';
+ scope.$eval();
+ var removeCount = 0;
+ element.find('a').bind('remove', function() {
+ removeCount++;
+ });
+ scope.$eval();
+ expect(removeCount).toEqual(0);
+ scope.value = '';
+ scope.$eval();
+ expect(removeCount).toEqual(1);
+ });
+ });
+});
+
View
2 src/test/webapp/unit/testUtils.js
@@ -23,7 +23,7 @@ define(["jquery", "angular"], function($, angular) {
function compileInPage(html) {
var elements = test$("<div>"+html+"</div>").children().addClass("result", "true");
- var page = test$('<div id="start" data-role="page"><div data-role="content"></div></div>');
+ var page = test$('<div id="start" data-role="page" data-url="start"><div data-role="content"></div></div>');
test$("body").append(page);
page.find(":jqmData(role='content')").append(elements);
page.page();
View
25 src/test/webapp/unit/textInputSpec.js
@@ -3,8 +3,7 @@ define(["unit/testUtils"], function(utils) {
describe("textInput", function() {
it('should save the ui value into the model', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<input ng:repeat="item in [1]" name="mysel" id="mysel" type="text">');
+ var d = utils.compileInPage('<input name="mysel" type="text">');
var input = d.element;
var scope = input.scope();
expect(scope.$get('mysel')).toBeFalsy();
@@ -14,8 +13,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should save the model value into the ui', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<input ng:repeat="item in [1]" name="mysel" id="mysel" type="text">');
+ var d = utils.compileInPage('<input name="mysel" type="text">');
var input = d.element;
var scope = input.scope();
expect(input[0].value).toEqual('');
@@ -25,8 +23,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should use the disabled attribute', function() {
- // Note: Be sure to use ng:repeat, as this is the most problematic case!
- var d = utils.compileInPage('<input ng:repeat="item in [1]" name="mysel" id="mysel" type="text" ng:bind-attr="{disabled: \'{{disabled}}\'}">');
+ var d = utils.compileInPage('<input name="mysel" type="text" ng:bind-attr="{disabled: \'{{disabled}}\'}">');
var input = d.element;
var scope = input.scope();
scope.$set('disabled', false);
@@ -37,20 +34,8 @@ define(["unit/testUtils"], function(utils) {
expect(input.hasClass('ui-disabled')).toBeTruthy();
});
- it('should be removable when ng:repeat shrinks', function() {
- var d = utils.compileInPage('<div ng:init="mylist = [1,2]">' +
- '<input ng:repeat="item in mylist" name="mysel" id="mysel" type="text">' +
- '</div>');
- var container = d.element;
- var scope = container.scope();
- expect(container.children('input').length).toEqual(2);
- scope.mylist = [1];
- scope.$eval();
- expect(container.children('input').length).toEqual(1);
- });
-
it('should work with type="tel"', function() {
- var d = utils.compileInPage('<input ng:repeat="item in [1]" name="mysel" id="mysel" type="tel">');
+ var d = utils.compileInPage('<input name="mysel" type="tel">');
var input = d.element;
expect(input.prop('type')).toEqual('tel');
var scope = input.scope();
@@ -61,7 +46,7 @@ define(["unit/testUtils"], function(utils) {
});
it('should work with type="number"', function() {
- var d = utils.compileInPage('<input ng:repeat="item in [1]" name="mysel" id="mysel" type="number">');
+ var d = utils.compileInPage('<input name="mysel" type="number">');
var input = d.element;
expect(input.prop('type')).toEqual('number');
var scope = input.scope();

0 comments on commit c0b0247

Please sign in to comment.