diff options
| -rw-r--r-- | example/widgets.html | 17 | ||||
| -rw-r--r-- | src/Angular.js | 15 | ||||
| -rw-r--r-- | src/Compiler.js | 13 | ||||
| -rw-r--r-- | src/markup.js | 48 | ||||
| -rw-r--r-- | src/widgets2.js | 26 | ||||
| -rw-r--r-- | test/markupSpec.js | 11 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 21 |
7 files changed, 93 insertions, 58 deletions
diff --git a/example/widgets.html b/example/widgets.html index d3e980a1..6a8214e7 100644 --- a/example/widgets.html +++ b/example/widgets.html @@ -2,7 +2,7 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <script type="text/javascript" src="../lib/underscore/underscore.js"></script> - <script type="text/javascript" src="../lib/jquery/jquery-1.3.2.js"></script> + <script type="text/javascript" src="../lib/jquery/jquery-1.4.2.js"></script> <script type="text/javascript" src="../src/angular-bootstrap.js"></script> <script type="text/javascript"> $(document).ready(function(){ @@ -18,15 +18,20 @@ </head> <body> <input type="checkbox" name="form.checked" ng-format="boolean" value="true" checked="checked" /> - <input ng-show="form.checked" name="form.required" ng-required/> + <input ng-show="form.checked" name="form.required" ng-required/> + <hr/> + <input name="form.list" ng-format="list" ng-required/> + <input name="form.list" ng-format="list" /> <hr/> - <input name="form.list" ng-format="list" ng-required/> - <input name="form.list" ng-format="list" /> - <hr/> <input type="checkbox" name="form.boolean" ng-format="boolean" value="true" checked="checked" /> <input type="checkbox" name="form.boolean" ng-format="boolean" value="true" /> - <hr/> + <hr/> <input type="text" name="form.async" ng-validate="asynchronous:$window.asyncValidate" /> + <hr/> + <select name="select"> + <option>A</option> + <option selected>B</option> + </select> <pre> form={{form}} $invalidWidgets.length={{$invalidWidgets.length}} diff --git a/src/Angular.js b/src/Angular.js index dc530921..0c6d081e 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -32,24 +32,13 @@ function extensionMap(angular, name) { }); } -function extensionList(angular, name) { - var extPoint, length = 0; - return angular[name] || (extPoint = angular[name] = function (fn, prop){ - if (isDefined(fn)) { - extPoint[length] = extend(fn, prop || {}); - length++; - } - return extPoint; - }); -} - var consoleNode, msie, NOOP = 'noop', jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy slice = Array.prototype.slice, angular = window['angular'] || (window['angular'] = {}), - angularTextMarkup = extensionList(angular, 'textMarkup'), - angularAttrMarkup = extensionList(angular, 'attrMarkup'), + angularTextMarkup = extensionMap(angular, 'textMarkup'), + angularAttrMarkup = extensionMap(angular, 'attrMarkup'), angularDirective = extensionMap(angular, 'directive'), angularWidget = extensionMap(angular, 'widget'), angularValidator = extensionMap(angular, 'validator'), diff --git a/src/Compiler.js b/src/Compiler.js index 4423fcef..47ab0c14 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -120,6 +120,7 @@ Compiler.prototype = { }; if (widget) { + descend = false; template.addInit(widget.call(selfApi, element)); } else { // process markup for text nodes only @@ -152,12 +153,12 @@ Compiler.prototype = { template.addInit(directive()); }); - // Process non text child nodes - if (descend) { - eachNode(element, function(child, i){ - template.addChild(i, self.templatize(child)); - }); - } + } + // Process non text child nodes + if (descend) { + eachNode(element, function(child, i){ + template.addChild(i, self.templatize(child)); + }); } return template.empty() ? null : template; } diff --git a/src/markup.js b/src/markup.js index add7ce03..5fb10779 100644 --- a/src/markup.js +++ b/src/markup.js @@ -27,30 +27,42 @@ function hasBindings(bindings) { return bindings.length > 1 || Binder.binding(bindings[0]) !== null; }; -angularTextMarkup(function(text, textNode, parentElement) { +angularTextMarkup('{{}}', function(text, textNode, parentElement) { var bindings = parseBindings(text), self = this; - if (isLeafNode(parentElement[0])) { - parentElement.attr('ng-bind-template', text); - } else { - var cursor = textNode, newElement; - foreach(parseBindings(text), function(text){ - var exp = binding(text); - if (exp) { - newElement = self.element('span'); - newElement.attr('ng-bind', exp); - } else { - newElement = self.text(text); - } - cursor.after(newElement); - cursor = newElement; - }); + if (hasBindings(bindings)) { + if (isLeafNode(parentElement[0])) { + parentElement.attr('ng-bind-template', text); + } else { + var cursor = textNode, newElement; + foreach(parseBindings(text), function(text){ + var exp = binding(text); + if (exp) { + newElement = self.element('span'); + newElement.attr('ng-bind', exp); + } else { + newElement = self.text(text); + } + cursor.after(newElement); + cursor = newElement; + }); + } + textNode.remove(); + } +}); + +angularTextMarkup('OPTION', function(text, textNode, parentElement){ + if (parentElement[0].nodeName == "OPTION") { + var select = document.createElement('select'); + select.insertBefore(parentElement[0].cloneNode(true), null); + if (!select.innerHTML.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) { + parentElement.attr('value', text); + } } - textNode.remove(); }); var NG_BIND_ATTR = 'ng-bind-attr'; -angularAttrMarkup(function(value, name, element){ +angularAttrMarkup('{{}}', function(value, name, element){ if (name.substr(0, 3) != 'ng-') { var bindings = parseBindings(value), bindAttr; diff --git a/src/widgets2.js b/src/widgets2.js index b67694b1..a8d17105 100644 --- a/src/widgets2.js +++ b/src/widgets2.js @@ -73,8 +73,8 @@ var NG_ERROR = 'ng-error', 'reset': buttonWidget, 'image': buttonWidget, 'checkbox': inputWidget('click', modelAccessor, checkedAccessor, false), - 'radio': inputWidget('click', modelAccessor, radioAccessor, undefined) -// 'select-one': [null, 'change'], + 'radio': inputWidget('click', modelAccessor, radioAccessor, undefined), + 'select-one': inputWidget('click', modelAccessor, valueAccessor, null) // 'select-multiple': [[], 'change'], // 'file': [{}, 'click'] }; @@ -84,9 +84,10 @@ function inputWidget(events, modelAccessor, viewAccessor, initValue) { var scope = this, model = modelAccessor(scope, element), view = viewAccessor(element), - action = element.attr('ng-action') || ''; - var value = view.get() || initValue; + action = element.attr('ng-action') || '', + value = view.get() || initValue; if (isDefined(value)) model.set(value); + this.$eval(element.attr('ng-init')||''); element.bind(events, function(){ model.set(view.get()); scope.$eval(action); @@ -95,13 +96,14 @@ function inputWidget(events, modelAccessor, viewAccessor, initValue) { }; } -angularWidget('INPUT', function input(element){ - return function(element) { - this.$eval(element.attr('ng-init')||''); - (INPUT_TYPE[lowercase(element[0].type)] || noop).call(this, element); - }; -}); +function inputWidgetSelector(element){ + return INPUT_TYPE[lowercase(element[0].type)] || noop; +} -angularWidget('TEXTAREA', function(){ - return textWidget; +angularWidget('INPUT', inputWidgetSelector); +angularWidget('TEXTAREA', inputWidgetSelector); +angularWidget('BUTTON', inputWidgetSelector); +angularWidget('SELECT', function(element){ + this.descend(true); + return inputWidgetSelector.call(this, element); }); diff --git a/test/markupSpec.js b/test/markupSpec.js index 9e89af7b..8ea88f08 100644 --- a/test/markupSpec.js +++ b/test/markupSpec.js @@ -30,11 +30,11 @@ describe("markups", function(){ }); it('should translate {{}} in terminal nodes', function(){ - compile('<select><option>Greet {{name}}!</option></select>'); - expect(element.html()).toEqual('<option ng-bind-template="Greet {{name}}!"></option>'); + compile('<select name="x"><option value="">Greet {{name}}!</option></select>'); + expect(element.html()).toEqual('<option ng-bind-template="Greet {{name}}!" value=""></option>'); scope.set('name', 'Misko'); scope.updateView(); - expect(element.html()).toEqual('<option ng-bind-template="Greet {{name}}!">Greet Misko!</option>'); + expect(element.html()).toEqual('<option ng-bind-template="Greet {{name}}!" value="">Greet Misko!</option>'); }); it('should translate {{}} in attributes', function(){ @@ -46,4 +46,9 @@ describe("markups", function(){ expect(element.attr('src')).toEqual("http://server/a/b.png"); }); + it('should populate value attribute on OPTION', function(){ + compile('<select name="x"><option>A</option></select>'); + expect(element.html()).toEqual('<option value="A">A</option>'); + }); + }); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index 44a3d225..9471a718 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -108,6 +108,12 @@ describe("input widget", function(){ expect(scope.get('clicked')).toEqual(true); }); + it('should support button alias', function(){ + compile('<button ng-action="clicked = true">Click Me</button>'); + element.click(); + expect(scope.get('clicked')).toEqual(true); + }); + it('should type="checkbox"', function(){ compile('<input type="checkbox" name="checkbox" checked ng-action="action = true"/>'); expect(scope.get('checkbox')).toEqual(true); @@ -142,6 +148,21 @@ describe("input widget", function(){ expect(model.clicked).toEqual(1); }); + it('should type="radio"', function(){ + compile( + '<select name="selection">' + + '<option>A</option>' + + '<option selected>B</option>' + + '</select>'); + expect(element[0].selectedIndex).toEqual(1); + expect(element[0].value).toEqual('B'); + expect(model.selection).toEqual('B'); + model.selection = 'A'; + model.$updateView(); + expect(model.selection).toEqual('A'); + expect(element[0].childNodes[0].selected).toEqual(true); + }); + it('should report error on missing field', function(){ }); |
