Skip to content

Commit

Permalink
Add Element.purge for cleaning up event listeners and element stora…
Browse files Browse the repository at this point in the history
…ge keys on elements that will be removed from the page. Make `Element.update` perform similar cleanup automatically. (Andrew Dupont, Tobie Langel)
  • Loading branch information
savetheclocktower committed May 7, 2010
1 parent 38e85b8 commit c9d6c3e
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 7 deletions.
10 changes: 6 additions & 4 deletions CHANGELOG
@@ -1,10 +1,12 @@
Fix issue where `Element.Layout#get` would fail to interpret negative pixel values. (Sebastien Gruhier, Andrew Dupont)
* Add `Element.purge` for cleaning up event listeners and element storage keys on elements that will be removed from the page. Make `Element.update` perform similar cleanup automatically. (Andrew Dupont, Tobie Langel)

Fix bugs in layout.js. Add tests for `Element.Layout#toCSS`, `#toObject`, and `#toHash`. (RStankov, Andrew Dupont)
* Fix issue where `Element.Layout#get` would fail to interpret negative pixel values. (Sebastien Gruhier, Andrew Dupont)

Add `Element.Layout#toObject` and `Element.Layout.toHash`. (Andrew Dupont)
* Fix bugs in layout.js. Add tests for `Element.Layout#toCSS`, `#toObject`, and `#toHash`. (RStankov, Andrew Dupont)

Make `Element.Layout#toCSS` return camelized property names, as expected by `Element.setStyle`. [#1021 state:resolved] (njakobsen, Andrew Dupont)
* Add `Element.Layout#toObject` and `Element.Layout.toHash`. (Andrew Dupont)

* Make `Element.Layout#toCSS` return camelized property names, as expected by `Element.setStyle`. [#1021 state:resolved] (njakobsen, Andrew Dupont)

*1.7_rc1* (April 1, 2010)

Expand Down
50 changes: 47 additions & 3 deletions src/dom/dom.js
Expand Up @@ -189,6 +189,19 @@ if (!Node.ELEMENT_NODE) {
Element.idCounter = 1;
Element.cache = { };

// Performs cleanup on an element before it is removed from the page.
// See `Element#purge`.
function purgeElement(element) {
// Must go first because it relies on Element.Storage.
Element.stopObserving(element);

var uid = element._prototypeUID;
if (uid) {
element._prototypeUID = void 0;
delete Element.Storage[uid];
}
}

/**
* mixin Element.Methods
*
Expand Down Expand Up @@ -449,6 +462,11 @@ Element.Methods = {
* Note that this method allows seamless content update of table related
* elements in Internet Explorer 6 and beyond.
*
* Any nodes replaced with `Element.update` will first have event
* listeners unregistered and storage keys removed. This frees up memory
* and prevents leaks in certain versions of Internet Explorer. (See
* [[Element.purge]]).
*
* ##### Examples
*
* language: html
Expand Down Expand Up @@ -551,7 +569,14 @@ Element.Methods = {

function update(element, content) {
element = $(element);


// Purge the element's existing contents of all storage keys and
// event listeners, since said content will be replaced no matter
// what.
var descendants = Element.select(element, '*'),
i = descendants.length;
while (i--) purgeElement(descendants[i]);

if (content && content.toElement)
content = content.toElement();

Expand Down Expand Up @@ -3715,8 +3740,8 @@ Element.addMethods({
uid = 0;
} else {
if (typeof element._prototypeUID === "undefined")
element._prototypeUID = [Element.Storage.UID++];
uid = element._prototypeUID[0];
element._prototypeUID = Element.Storage.UID++;
uid = element._prototypeUID;
}

if (!Element.Storage[uid])
Expand Down Expand Up @@ -3786,5 +3811,24 @@ Element.addMethods({
}
}
return Element.extend(clone);
},

/**
* Element.purge(@element) -> null
*
* Removes all event listeners and storage keys from an element.
*
* To be used just before removing an element from the page.
**/
purge: function(element) {
if (!(element = $(element))) return;
purgeElement(element);

var descendants = Element.select(element, '*'),
i = descendants.length;

while (i--) purgeElement(descendants[i]);

return null;
}
});
30 changes: 30 additions & 0 deletions test/unit/dom_test.js
Expand Up @@ -1501,6 +1501,36 @@ new Test.Unit.Runner({
this.assert(deepClone.firstChild);
this.assertEqual('SPAN', deepClone.firstChild.nodeName.toUpperCase());
this.assert(!deepClone.down('span')._prototypeUID);
},

testElementPurge: function() {
var element = new Element('div');
element.store('foo', 'bar');

var uid = element._prototypeUID;
this.assert(uid in Element.Storage, "newly-created element's uid should exist in `Element.Storage`");

element.purge();

this.assert(!(uid in Element.Storage), "purged element's UID should no longer exist in `Element.Storage`");
this.assert(!(Object.isNumber(element._prototypeUID)), "purged element's UID should no longer exist in `Element.Storage`");

// Should purge elements replaced via innerHTML.
var parent = new Element('div');
var child = new Element('p').update('lorem ipsum');

parent.insert(child);
child.store('foo', 'bar');
child.observe('test:event', function(event) { event.stop(); });
var childUID = child._prototypeUID;

parent.update("");

// At this point, `child` should have been purged.
this.assert(!(childUID in Element.Storage), "purged element's UID should no longer exist in `Element.Storage`");

var event = child.fire('test:event');
this.assert(!event.stopped, "fired event should not have been stopped");
}
});

Expand Down

0 comments on commit c9d6c3e

Please sign in to comment.