2010/02/21
IE + closure library + cloneNode
http://code.google.com/p/closure-library/source/detail?r=43
これまでgoog/demos/css以下にあったcssがgoog/cssに昇格したようです。
デモ用のcssをいちいちコピーするのが面倒だったので助かります。
さて、IEだとcloneNode時にイベントや独自に追加したプロパティも一緒にコピーされてしまいます。
このせいでclosure libraryのイベントで厄介な問題につまづきました。
備忘録兼腹いせとしてここに記録しておきます。
<html>
<head>
<script type="text/javascript" src="../closure-library-read-only/closure/goog/base.js"></script>
<script>
goog.require('goog.events');
goog.require('goog.dom');
goog.require('goog.events.EventType');
goog.require('goog.events.EventHandler');
</script>
</head>
<body>
<div id="hoge">hoge</div>
<script>
var onMouseDown = function(e) {
var target = e.target || e.srcElement;
alert(target.id);
};
var onMouseDownEx = function(e) {
var target = e.target || e.srcElement;
alert(target.id + ' Ex');
};
goog.events.listen(goog.dom.getElement('hoge'), goog.events.EventType.MOUSEDOWN, onMouseDown, false);
// goog.dom.getElement('hoge').attachEvent('onmousedown', onMouseDown);
// "hoge" をコピーして "fuga" を作る
var clone = goog.dom.getElement('hoge').cloneNode(true);
clone.id = 'fuga';
clone.innerHTML = 'fuga';
document.body.appendChild(clone);
// IEだとイベントもコピーされているため外す
goog.events.unlisten(clone, goog.events.EventType.MOUSEDOWN, onMouseDown, false);
// clone.detachEvent('onmousedown', onMouseDown);
// 別のイベントをつける
goog.events.listen(goog.dom.getElement('fuga'), goog.events.EventType.MOUSEDOWN, onMouseDownEx, false);
// goog.dom.getElement('fuga').attachEvent('onmousedown', onMouseDownEx);
</script>
</body>
</html>
id="hoge"のdiv要素をcloneNodeして別のイベントをlistenしています。
これでIEでもFireFoxでも"hoge"を押下したら「hoge」が、"div"を押下したら「fuga Ex」が表示されるように見えます。
しかしIEでは"hoge"を押下しても何も表示されません。
理由はgoog.events.listen/unlistenの中で使っているgoog.getHashCodeにあります。
http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/base.js
/**こいつは見ての通り与えられたオブジェクトにプロパティを追加し、そこにユニークなハッシュコード(という名の連番)をセットしてます。
* Adds a hash code field to an object. The hash code is unique for the
* given object.
* @param {Object} obj The object to get the hash code for.
* @return {number} The hash code for the object.
*/
goog.getHashCode = function(obj) {
// In IE, DOM nodes do not extend Object so they do not have this method.
// we need to check hasOwnProperty because the proto might have this set.
// TODO: There is a proposal to add hashcode as a global function to JS2
// we should keep track of this process so we can use that whenever
// it starts to show up in the real world.
if (obj.hasOwnProperty && obj.hasOwnProperty(goog.HASH_CODE_PROPERTY_)) {
return obj[goog.HASH_CODE_PROPERTY_];
}
if (!obj[goog.HASH_CODE_PROPERTY_]) {
obj[goog.HASH_CODE_PROPERTY_] = ++goog.hashCodeCounter_;
}
return obj[goog.HASH_CODE_PROPERTY_];
};
goog.events.listen/unlistenではこのハッシュコードでunlistenするイベントハンドラを取得したり、同じ全くイベントを監視しないようにしたりしています。
IEだとcloneNode時にこのハッシュコードもコピーしてしまうため、イベント管理まわりで思ったように動かないことがあります。
IEがタコなのか、closure libraryがまずいのか、cloneNodeが黒魔術なのか。
怖いなあ、これ。
- Category(s)
- JavaScript
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/uchida/ie-closure-library-clonenode/tbping