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(){    }); | 
