diff options
| author | Misko Hevery | 2011-07-26 12:06:14 -0700 | 
|---|---|---|
| committer | Igor Minar | 2011-10-11 10:53:05 -0700 | 
| commit | bda2bba2be7a52bf39fb1b257b6363edc7b71173 (patch) | |
| tree | 70de396d785f7632377391d3463032826aa2d4c9 | |
| parent | ca08c004c893310ed9b3b4a5d2a4d16314eaa677 (diff) | |
| download | angular.js-bda2bba2be7a52bf39fb1b257b6363edc7b71173.tar.bz2 | |
feat(jqlite): added .inheritedData method and $destroy event.
- refactored .scope() to use .inheritedData() instead.
- .bind('$destroy', callback) will call when the DOM element is removed
| -rw-r--r-- | src/Angular.js | 6 | ||||
| -rw-r--r-- | src/jqLite.js | 65 | ||||
| -rw-r--r-- | test/jqLiteSpec.js | 27 | 
3 files changed, 89 insertions, 9 deletions
| diff --git a/src/Angular.js b/src/Angular.js index 367a7752..407fc263 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -985,8 +985,12 @@ function bindJQuery(){    if (jQuery) {      jqLite = jQuery;      extend(jQuery.fn, { -      scope: JQLitePrototype.scope +      scope: JQLitePrototype.scope, +      inheritedData: JQLitePrototype.inheritedData      }); +    JQLitePatchJQueryRemove('remove', true); +    JQLitePatchJQueryRemove('empty'); +    JQLitePatchJQueryRemove('html');    } else {      jqLite = jqLiteWrap;    } diff --git a/src/jqLite.js b/src/jqLite.js index 13bd55ba..ae540e89 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -99,6 +99,46 @@ function camelCase(name) {  }  ///////////////////////////////////////////// +// jQuery mutation patch +///////////////////////////////////////////// + +function JQLitePatchJQueryRemove(name, dispatchThis) { +  var originalJqFn = jQuery.fn[name]; +  originalJqFn = originalJqFn.$original || originalJqFn; +  removePatch.$original = originalJqFn; +  jQuery.fn[name] = removePatch; + +  function removePatch() { +    var list = [this], +        fireEvent = dispatchThis, +        set, setIndex, setLength, +        element, childIndex, childLength, children, +        fns, data; + +    while(list.length) { +      set = list.shift(); +      for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) { +        element = jqLite(set[setIndex]); +        if (fireEvent) { +          data = element.data('events'); +          if ( (fns = data && data.$destroy) ) { +            forEach(fns, function(fn){ +              fn.handler(); +            }); +          } +        } else { +          fireEvent = !fireEvent; +        } +        for(childIndex = 0, childLength = (children = element.children()).length; childIndex < childLength; childIndex++) { +          list.push(jQuery(children[childIndex])); +        } +      } +    } +    return originalJqFn.apply(this, arguments); +  } +} + +/////////////////////////////////////////////  function jqLiteWrap(element) {    if (isString(element) && element.charAt(0) != '<') {      throw new Error('selectors not implemented'); @@ -137,9 +177,15 @@ function JQLiteRemoveData(element) {    var cacheId = element[jqName],    cache = jqCache[cacheId];    if (cache) { -    forEach(cache.bind || {}, function(fn, type){ -      removeEventListenerFn(element, type, fn); -    }); +    if (cache.bind) { +      forEach(cache.bind, function(fn, type){ +        if (type == '$destroy') { +          fn({}); +        } else { +          removeEventListenerFn(element, type, fn); +        } +      }); +    }      delete jqCache[cacheId];      element[jqName] = undefined; // ie does not allow deletion of attributes on elements.    } @@ -241,13 +287,16 @@ var SPECIAL_ATTR = makeMap("multiple,selected,checked,disabled,readonly,required  forEach({    data: JQLiteData, +  inheritedData: function(element, name, value) { +    element = jqLite(element); +    while (element.length) { +      if (value = element.data(name)) return value; +      element = element.parent(); +    } +  },    scope: function(element) { -    var scope; -    while (element && !(scope = jqLite(element).data($$scope))) { -      element = element.parentNode; -    } -    return scope; +    return jqLite(element).inheritedData($$scope);    },    removeAttr: function(element,name) { diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 24795331..f66b6244 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -83,6 +83,33 @@ describe('jqLite', function(){    }); +  describe('inheritedData', function() { + +    it('should retrieve data attached to the current element', function() { +      var element = jqLite('<i>foo</i>'); +      element.data('myData', 'abc'); +      expect(element.inheritedData('myData')).toBe('abc'); +      dealoc(element); +    }); + + +    it('should walk up the dom to find data', function() { +      var element = jqLite('<ul><li><p><b>deep deep</b><p></li></ul>'); +      var deepChild = jqLite(element[0].getElementsByTagName('b')[0]); +      element.data('myData', 'abc'); +      expect(deepChild.inheritedData('myData')).toBe('abc'); +      dealoc(element); +    }); + + +    it('should return undefined when no data was found', function() { +      var element = jqLite('<ul><li><p><b>deep deep</b><p></li></ul>'); +      var deepChild = jqLite(element[0].getElementsByTagName('b')[0]); +      expect(deepChild.inheritedData('myData')).toBeFalsy(); +      dealoc(element); +    }); +  }); +    describe('scope', function() {      it('should retrieve scope attached to the current element', function() {        var element = jqLite('<i>foo</i>'); | 
