diff --git a/CHANGELOG b/CHANGELOG index fa101e6..71f7cea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Added Element#store and Element#retrieve for safe, hash-backed storage of element metadata (no memory leaks). Also added Element#getStorage for working with the element's storage hash directly. Hat tip: Mootools. (ZenCocoon, Andrew Dupont) + * Fix issue where certain versions of Safari treat class names case-insensitively in Selector/$$ queries. (Andrew Dupont, kangax, Brice) * Fix issue where Function#argumentNames returned incorrect results in IE when comments were intermixed with argument names. (Christophe Porteneuve, T.J. Crowder) diff --git a/src/dom/dom.js b/src/dom/dom.js index 0b59ca1..e90766f 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -1205,3 +1205,41 @@ document.viewport = { window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + if (Object.isUndefined(element._prototypeUID)) + element._prototypeUID = [Element.Storage.UID++]; + + var uid = element._prototypeUID[0]; + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + element.getStorage().set(key, value); + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + + var hash = element.getStorage(), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + } +}); diff --git a/test/unit/dom_test.js b/test/unit/dom_test.js index 00d695c..4145e40 100644 --- a/test/unit/dom_test.js +++ b/test/unit/dom_test.js @@ -1365,6 +1365,23 @@ new Test.Unit.Runner({ constants.each(function(pair) { this.assertEqual(Node[pair.key], pair.value); }, this); + }, + + testElementStorage: function() { + var element = $('test-empty'); + element.store('foo', 'bar'); + this.assertEqual("bar", element.retrieve("foo"), "Setting and reading a property"); + element.store('foo', 'thud'); + this.assertEqual("thud", element.retrieve("foo"), "Re-setting and reading property"); + + element.store('bar', 'narf'); + this.assertEnumEqual($w('foo bar'), element.getStorage().keys(), "Getting the storage hash"); + element.getStorage().unset('bar'); + this.assertEnumEqual($w('foo'), element.getStorage().keys(), "Getting the storage hash after unsetting a key"); + + + var clonedElement = $('test-empty').cloneNode(false); + this.assert(!('_prototypeUID' in clonedElement), "Cloning a node should not confuse the storage engine"); } });