diff options
| author | Misko Hevery | 2010-03-18 14:43:49 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2010-03-18 14:43:49 -0700 | 
| commit | df607da0d1b9726bce6584238fe3ad7e9b65a966 (patch) | |
| tree | 472a81182226bde4c3541592f940983c9486eea2 | |
| parent | 7634a3ed5227f8bc2a2ba83752d0e2c78adb6051 (diff) | |
| download | angular.js-df607da0d1b9726bce6584238fe3ad7e9b65a966.tar.bz2 | |
support for templates
| -rw-r--r-- | lib/jstestdriver/JsTestDriver.jar | bin | 3090800 -> 3092033 bytes | |||
| -rw-r--r-- | src/Scope.js | 15 | ||||
| -rw-r--r-- | src/directives.js | 8 | ||||
| -rw-r--r-- | test/CompilerSpec.js | 95 | 
4 files changed, 82 insertions, 36 deletions
| diff --git a/lib/jstestdriver/JsTestDriver.jar b/lib/jstestdriver/JsTestDriver.jarBinary files differ index 1a37d230..2c7a5154 100644 --- a/lib/jstestdriver/JsTestDriver.jar +++ b/lib/jstestdriver/JsTestDriver.jar diff --git a/src/Scope.js b/src/Scope.js index 442477b4..3633f960 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,5 +1,6 @@  function Scope(initialState, name) {    this.widgets = []; +  this.evals = [];    this.watchListeners = {};    this.name = name;    initialState = initialState || {}; @@ -11,6 +12,7 @@ function Scope(initialState, name) {      this.state['$root'] = this.state;    }    this.set('$watch', bind(this, this.addWatchListener)); +  this.set('$eval', bind(this, this.addEval));  };  Scope.expressionCache = {}; @@ -48,17 +50,23 @@ Scope.prototype = {    updateView: function() {      var self = this;      this.fireWatchers(); -    _.each(this.widgets, function(widget){ +    foreach(this.widgets, function(widget){        self.evalWidget(widget, "", {}, function(){          this.updateView(self);        });      }); +    foreach(this.evals, bind(this, this.apply));    },    addWidget: function(controller) {      if (controller) this.widgets.push(controller);    }, +  addEval: function(fn, listener) { +    // todo: this should take a function/string and a listener +    this.evals.push(fn); +  }, +    isProperty: function(exp) {      for ( var i = 0; i < exp.length; i++) {        var ch = exp.charAt(i); @@ -190,8 +198,7 @@ Scope.prototype = {    },    fireWatchers: function() { -    var self = this; -    var fired = false; +    var self = this, fired = false;      foreach(this.watchListeners, function(watcher) {        var value = self.eval(watcher.expression);        if (value !== watcher.lastValue) { @@ -206,6 +213,6 @@ Scope.prototype = {    },    apply: function(fn) { -    fn.apply(this.state, slice(arguments, 0, arguments.length)); +    fn.apply(this.state, slice.call(arguments, 1, arguments.length));    }  }; diff --git a/src/directives.js b/src/directives.js index 7c5cc257..26cbfe2c 100644 --- a/src/directives.js +++ b/src/directives.js @@ -58,12 +58,12 @@ angular.directive("bind-attr", function(expression, element){  angular.directive("repeat", function(expression, element){    var anchor = document.createComment(expression);    jQuery(element).replace(anchor); -  var template = this.templetize(element); +  var template = this.compile(element);    var lhs = "item";    var rhs = "items"; -  var children = [];    return function(){ -    this.$watch(rhs, function(items){ +    var children = []; +    this.$eval(rhs, function(items){        foreach(children, function(child){          child.element.remove();        }); @@ -102,7 +102,7 @@ angular.directive("action", function(expression, element){  //ng-eval  angular.directive("eval", function(expression, element){    return function(){ -    this.$onUpdate( expression); +    this.$eval(expression);    };  });  //ng-watch diff --git a/test/CompilerSpec.js b/test/CompilerSpec.js index 35e0e605..4ffdf7f5 100644 --- a/test/CompilerSpec.js +++ b/test/CompilerSpec.js @@ -1,3 +1,9 @@ +/** + * Template provides directions an how to bind to a given element. + * It contains a list of init functions which need to be called to + * bind to a new instance of elements. It also provides a list + * of child paths which contain child templates + */  function Template() {    this.paths = [];    this.children = []; @@ -26,6 +32,11 @@ Template.prototype = {      }    }, +  setExclusiveInit: function(init) { +    this.inits = [init]; +    this.addInit = noop; +  }, +    addChild: function(index, template) {      this.paths.push(index); @@ -33,39 +44,22 @@ Template.prototype = {    }  }; +/////////////////////////////////// +// Compiler +////////////////////////////////// +  function Compiler(directives){    this.directives = directives;  }  DIRECTIVE = /^ng-(.*)$/; -/** - * return { - *   element: - *   init: function(element){...} - * } - * - * internal data structure: { - *  paths: [4, 5, 6], - *  directive: name, - *  init: function(expression, element){} - * } - * - * template : { - *   inits: [fn(), fn()} - *   paths: [1, 5], - *   templates: [ - *     inits: [] - *     paths: [] - *     templates: - *   ] - * } - */  Compiler.prototype = {    compile: function(element) { -    var template = this.templetize(element); -    return function(){ +    var template = this.templetize(element) || new Template(); +    return function(element){        var scope = new Scope(); +      scope.element = element;        return {          scope: scope,          element:element, @@ -79,17 +73,24 @@ Compiler.prototype = {          childTemplate, recurse = true;      // Process attributes/directives -    for (i = 0, items = element.attributes, length = items.length; +    for (i = 0, items = element.attributes || [], length = items.length;           i < length; i++) {        item = items[i];        var match = item.name.match(DIRECTIVE);        if (match) {          directive = this.directives[match[1]];          if (directive) { -          init = directive.call({}, item.value, element); +          init = directive.call(this, item.value, element);            template = template || new Template(); -          template.addInit(init); +          if (directive.exclusive) { +            template.setExclusiveInit(init); +            i = length; // quit iterations +          } else { +            template.addInit(init); +          }            recurse = recurse && init; +        } else { +          error("Directive '" + match[0] + "' is not recognized.");          }        }      } @@ -136,7 +137,7 @@ describe('compiler', function(){      };      compiler = new Compiler(directives);      compile = function(html){ -      var e = element(html); +      var e = element("<div>" + html + "</div>");        var view = compiler.compile(e)(e);        view.init();        return view.scope; @@ -183,4 +184,42 @@ describe('compiler', function(){      var scope = compile('<span ng-hello="misko" ng-stop="true"><span ng-hello="adam"/></span>');      expect(log).toEqual("hello misko");    }); + +  it('should allow creation of templates', function(){ +    directives.duplicate = function(expr, element){ +      var template, +          marker = document.createComment("marker"), +          parentNode = element.parentNode; +      parentNode.insertBefore(marker, element); +      parentNode.removeChild(element); +      element.removeAttribute("ng-duplicate"); +      template = this.compile(element); +      return function(marker) { +        var parentNode = marker.parentNode; +        this.$eval(function() { +          parentNode.insertBefore( +              template(element.cloneNode(true)).element, +              marker.nextSibling); +        }); +      }; +    }; +    var scope = compile('before<span ng-duplicate="expr">x</span>after'); +    expect($(scope.element).html()).toEqual('before<!--marker-->after'); +    scope.updateView(); +    expect($(scope.element).html()).toEqual('before<!--marker--><span>x</span>after'); +    scope.updateView(); +    expect($(scope.element).html()).toEqual('before<!--marker--><span>x</span><span>x</span>after'); +  }); + +  it('should allow for exculsive tags which suppress others', function(){ +    directives.exclusive = function(){ +      return function() { +        log += ('exclusive'); +      }; +    }; +    directives.exclusive.exclusive = true; + +    compile('<span ng-hello="misko", ng-exclusive/>'); +    expect(log).toEqual('exclusive'); +  });  }); | 
