C
Csaba Gabor
One of the things that I never understood was the motivation for not
being able to iterate over the event listeners added via
..addEventListener It's particularly vexing because if you do
element.cloneNode(bDeep), you frequently get a stunted clone, often
with several key features missing, and one of these is associated event
handlers. Of course, it could be the case that the event handlers have
a closure including a reference to the original node, but still...
So I rewrote addEventListener, and removeEventListener so that
cloneNode could be accomodated. The below is a framework, and needs
some work, (including the transfer of attributes).
Csaba Gabor from Vienna
How it works. When you enter a character, you get a message box.
This is what lets you verify that the cloning of event handlers
worked. Before cloning, make a selection to see that the selection
is transferred, too.
<form action="" method=get>
<textarea id=foo name=foo style="color:red">This is some
starter text in a textarea</textarea>
<button type=button onclick="replaceWithClone(elem('foo'))"
accesskey=c><u>C</u>lone</button>
</form>
<script type='text/javascript'>
function elem(id) { return document.getElementById(id); }
fixCloneNode(elem('foo'));
elem('foo').addEventListener("input",
function() { alert("New text: " + this.value); }, false);
function fixCloneNode(elem) {
var oldAEL = elem.addEventListener;
var aListeners = [];
elem.addEventListener =
function (oldAEL, aListeners) {
return function (evt, func, bCapture) {
oldAEL.call (this, evt, func, bCapture)
aListeners.push( [evt, func, bCapture] ); } }
(oldAEL, aListeners);
var oldREL = elem.addEventListener;
elem.removeEventListener =
function (oldREL, aListeners) {
return function (evt, func, bCapture) {
for (var i=aListeners.length;--i
if (aListeners[0]==evt && aListeners[1]==func &&
aListeners[2]==bCapture)
aListeners.splice(i,1);
} } (oldREL, aListeners);
var oldClone = elem.cloneNode;
elem.cloneNode =
function (oldAEL, aListeners, oldClone) {
return function (bDeep) {
// does not reproduce the event listeners
var elem = oldClone.call (this, bDeep);
elem.addEventListener = this.addEventListener;
elem.removeEventListener = this.removeEventListener;
elem.cloneNode = this.cloneNode;
if (elem.nodeName=="TEXTAREA") elem.value = this.value;
for (var i=0;i<aListeners.length;++i) {
var aList=aListeners;
this.removeEventListener(aList[0], aList[1], aList[2]);
oldAEL.call (elem, aList[0], aList[1], aList[2]); }
return elem; } } (oldAEL, aListeners, oldClone);
}
function replaceWithClone(ta) {
var newTa = ta.cloneNode(true);
var start = ta.selectionStart, end=ta.selectionEnd;
ta.parentNode.replaceChild(newTa, ta);
// Doesn't work properly with reverse selections
newTa.setSelectionRange (start, end);
}
</script>
being able to iterate over the event listeners added via
..addEventListener It's particularly vexing because if you do
element.cloneNode(bDeep), you frequently get a stunted clone, often
with several key features missing, and one of these is associated event
handlers. Of course, it could be the case that the event handlers have
a closure including a reference to the original node, but still...
So I rewrote addEventListener, and removeEventListener so that
cloneNode could be accomodated. The below is a framework, and needs
some work, (including the transfer of attributes).
Csaba Gabor from Vienna
How it works. When you enter a character, you get a message box.
This is what lets you verify that the cloning of event handlers
worked. Before cloning, make a selection to see that the selection
is transferred, too.
<form action="" method=get>
<textarea id=foo name=foo style="color:red">This is some
starter text in a textarea</textarea>
<button type=button onclick="replaceWithClone(elem('foo'))"
accesskey=c><u>C</u>lone</button>
</form>
<script type='text/javascript'>
function elem(id) { return document.getElementById(id); }
fixCloneNode(elem('foo'));
elem('foo').addEventListener("input",
function() { alert("New text: " + this.value); }, false);
function fixCloneNode(elem) {
var oldAEL = elem.addEventListener;
var aListeners = [];
elem.addEventListener =
function (oldAEL, aListeners) {
return function (evt, func, bCapture) {
oldAEL.call (this, evt, func, bCapture)
aListeners.push( [evt, func, bCapture] ); } }
(oldAEL, aListeners);
var oldREL = elem.addEventListener;
elem.removeEventListener =
function (oldREL, aListeners) {
return function (evt, func, bCapture) {
for (var i=aListeners.length;--i
if (aListeners[0]==evt && aListeners[1]==func &&
aListeners[2]==bCapture)
aListeners.splice(i,1);
} } (oldREL, aListeners);
var oldClone = elem.cloneNode;
elem.cloneNode =
function (oldAEL, aListeners, oldClone) {
return function (bDeep) {
// does not reproduce the event listeners
var elem = oldClone.call (this, bDeep);
elem.addEventListener = this.addEventListener;
elem.removeEventListener = this.removeEventListener;
elem.cloneNode = this.cloneNode;
if (elem.nodeName=="TEXTAREA") elem.value = this.value;
for (var i=0;i<aListeners.length;++i) {
var aList=aListeners;
this.removeEventListener(aList[0], aList[1], aList[2]);
oldAEL.call (elem, aList[0], aList[1], aList[2]); }
return elem; } } (oldAEL, aListeners, oldClone);
}
function replaceWithClone(ta) {
var newTa = ta.cloneNode(true);
var start = ta.selectionStart, end=ta.selectionEnd;
ta.parentNode.replaceChild(newTa, ta);
// Doesn't work properly with reverse selections
newTa.setSelectionRange (start, end);
}
</script>