diff options
| author | Misko Hevery | 2010-03-22 20:20:05 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2010-03-22 20:20:05 -0700 | 
| commit | a8227086748e37c31c1bb71dec50c96d63c45eef (patch) | |
| tree | 80979da4e4124b57fa4962baf58bb326964b658e | |
| parent | 7c87c17d08dbba318af1a149c0bbedb696b03458 (diff) | |
| download | angular.js-a8227086748e37c31c1bb71dec50c96d63c45eef.tar.bz2 | |
rudementary event bind and trigger for jqlite
| -rw-r--r-- | src/Compiler.js | 94 | ||||
| -rw-r--r-- | src/Scope.js | 19 | ||||
| -rw-r--r-- | src/directives.js | 2 | ||||
| -rw-r--r-- | test/directivesSpec.js | 7 | 
4 files changed, 111 insertions, 11 deletions
diff --git a/src/Compiler.js b/src/Compiler.js index ece44805..115ed094 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -50,7 +50,39 @@ Template.prototype = {  //JQLite  ////////////////////////////////// +var jqCache = {}; +var jqName = 'ng-' + new Date().getTime(); +var jqId = 1; +function jqNextId() { return jqId++; } + +var addEventListener = window.document.attachEvent ? +    function(element, type, fn) { +      element.attachEvent('on' + type, fn); +    } : function(element, type, fn) { +      element.addEventListener(type, fn, false); +    }; + +var removeEventListener = window.document.detachEvent ? +    function(element, type, fn) { +      element.detachEvent('on' + type, fn); +    } : function(element, type, fn) { +      element.removeEventListener(type, fn, false); +    }; + +function jqClearData(element) { +  var cacheId = element[jqName], +      cache = jqCache[cacheId]; +  if (cache) { +    foreach(cache.bind || {}, function(fn, type){ +      removeEventListener(element, type, fn); +    }); +    delete jqCache[cacheId]; +    delete element[jqName]; +  } +}; +  function JQLite(element) { +  //todo: change to this[0];    this.element = element;  } @@ -64,6 +96,67 @@ function jqLite(element) {  }  JQLite.prototype = { +  data: function(key, value) { +    var element = this.element, +        cacheId = element[jqName], +        cache = jqCache[cacheId || -1]; +    if (isDefined(value)) { +      if (!cache) { +        element[jqName] = cacheId = jqNextId(); +        cache = jqCache[cacheId] = {}; +      } +      cache[key] = value; +    } else { +      return cache ? cache[key] : null; +    } +  }, + +  removeData: function(){ +    jqClearData(this.element); +  }, + +  dealoc: function(){ +    (function dealoc(element){ +      jqClearData(element); +      for ( var i = 0, children = element.childNodes; i < children.length; i++) { +        dealoc(children[0]); +      } +    })(this.element); +  }, + +  bind: function(type, fn){ +    var element = this.element, +        bind = this.data('bind'), +        eventHandler; +    if (!bind) this.data('bind', bind = {}); +    eventHandler = bind[type]; +    if (!eventHandler) { +      bind[type] = eventHandler = function() { +        var self = this; +        foreach(eventHandler.fns, function(fn){ +          fn.apply(self, arguments); +        }); +      }; +      eventHandler.fns = []; +      addEventListener(element, type, eventHandler); +    } +    eventHandler.fns.push(fn); +  }, + +  trigger: function(type) { +    var cache = this.data('bind'); +    if (cache) { +      (cache[type] || noop)(); +    } +  }, + +  click: function(fn) { +    if (fn) +      this.bind('click', fn); +    else +      this.trigger('click'); +  }, +    eachTextNode: function(fn){      var i, chldNodes = this.element.childNodes || [], size = chldNodes.length, chld;      for (i = 0; i < size; i++) { @@ -96,6 +189,7 @@ JQLite.prototype = {    },    remove: function() { +    this.dealoc();      this.element.parentNode.removeChild(this.element);    }, diff --git a/src/Scope.js b/src/Scope.js index 7b1d2673..a3e128b6 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -73,7 +73,7 @@ Scope.prototype = {      // todo: this is a hack, which will need to be cleaned up.      var self = this,          listenFn = listener || noop, -        expr = bind(self, self.compile(fn), {scope: self, self: self.state}); +        expr = self.compile(fn);      this.evals.push(function(){        self.apply(listenFn, expr());      }); @@ -117,23 +117,24 @@ Scope.prototype = {    compile: function(exp) {      if (isFunction(exp)) return exp; -    var expFn = Scope.expressionCache[exp]; +    var expFn = Scope.expressionCache[exp], self = this;      if (!expFn) {        var parser = new Parser(exp);        expFn = parser.statements();        parser.assertAllConsumed();        Scope.expressionCache[exp] = expFn;      } -    return expFn; +    return function(context){ +      context = context || {}; +      context.self = self.state; +      context.scope = self; +      return expFn.call(self, context); +    };    },    eval: function(expressionText, context) {  //    log('Scope.eval', expressionText); -    var expression = this.compile(expressionText); -    context = context || {}; -    context.scope = this; -    context.self = this.state; -    return expression(context); +    return this.compile(expressionText)(context);    },    //TODO: Refactor. This function needs to be an execution closure for widgets @@ -209,7 +210,7 @@ Scope.prototype = {    addWatchListener: function(watchExpression, listener) {      // TODO: clean me up!      if (!isFunction(listener)) { -      listener = bind(this, this.compile(listener), {scope: this, self: this.state}); +      listener = this.compile(listener);      }      var watcher = this.watchListeners[watchExpression];      if (!watcher) { diff --git a/src/directives.js b/src/directives.js index 9f98badb..adcfa508 100644 --- a/src/directives.js +++ b/src/directives.js @@ -85,7 +85,7 @@ angularDirective("ng-repeat", function(expression, element){  angularDirective("ng-action", function(expression, element){    return function(){      var self = this; -    jQuery(element.element).click(function(){ +    element.click(function(){        self.$eval(expression);      });    }; diff --git a/test/directivesSpec.js b/test/directivesSpec.js index 447698a3..7e0446ef 100644 --- a/test/directivesSpec.js +++ b/test/directivesSpec.js @@ -12,6 +12,11 @@ describe("directives", function(){      };    }); +  afterEach(function(){ +    element.remove(); +    expect(_(jqCache).size()).toEqual(0); +  }); +    it("should ng-init", function() {      var scope = compile('<div ng-init="a=123"></div>');      expect(scope.get('a')).toEqual(123); @@ -100,7 +105,7 @@ describe("directives", function(){      scope.updateView();      expect(scope.get('clicked')).toBeFalsy(); -    jQuery(element.element).click(); +    element.click();      expect(scope.get('clicked')).toEqual(true);    });  });  | 
