aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--example/widgets.html17
-rw-r--r--src/Angular.js15
-rw-r--r--src/Compiler.js13
-rw-r--r--src/markup.js48
-rw-r--r--src/widgets2.js26
-rw-r--r--test/markupSpec.js11
-rw-r--r--test/widgetsSpec.js21
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(){
});