MSIE Does Not Do OnMouseXXX Events On Span Elements?

M

mavigozler

IE7 does not appear to set an event on contained text inside SPAN elements
whose 'onclick', 'onmouseover', and 'onmouseout' events, defying the HTML
recommendation. Firefox appears to conform.

Is that so?
 
E

Elegie

mavigozler wrote:

Hi,
IE7 does not appear to set an event on contained text inside SPAN elements
whose 'onclick', 'onmouseover', and 'onmouseout' events, defying the HTML
recommendation. Firefox appears to conform.

<span onmouseover="this.innerHTML=new Date()">Hello, World</span>

.... works fine on IE7, could you post a simple test case demonstrating
your issue? Thanks.
 
M

mavigozler

Elegie said:
mavigozler wrote:

Hi,


<span onmouseover="this.innerHTML=new Date()">Hello, World</span>

... works fine on IE7, could you post a simple test case demonstrating
your issue? Thanks.

I forgot to add that the SPAN element is dynamically added to the
document. I am creating a document that dynamically adds text to the
document, and I want that text to be highlighted when the mouse is over
it, so the text is contained within a SPAN element. Note that I clone a
template span node whenever I need it, with the attributes for
"onmouseover" and "onmouseout" set to highlight and un-highlight text,
respectively.

A working example with validated HTML is below. Works in Firefox, but not
in IE7 (browser object embedded in Firefox).


========== Interactive HTML document start ================

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Mouseover Dynamic SPAN Element</title>
<script type="text/javascript">
var spanElemTemplate = document.createElement("span");
spanElemTemplate.setAttribute("style", "border:1px solid green;");
spanElemTemplate.setAttribute("onmouseover", "hiliteText(this, true);");
spanElemTemplate.setAttribute("onmouseout", "hiliteText(this, false);");

function hiliteText(spanObj, status)
{
if (status == true)
// yellow text hilite
spanObj.style.backgroundColor = "yellow";
else
spanObj.style.backgroundColor = "";
/* note that spanObj.setAttribute("style",
"background-color:yellow"); also works in FF */
}

function insertSpan()
{
var insertPoint = document.getElementById("insert-span-here");
var templateInstance = spanElemTemplate.cloneNode(true);
templateInstance.appendChild(document.createTextNode(
"This text should turn yellow when the mouse is over it"));
insertPoint.appendChild(templateInstance);
}

</script>
</head>
<body>

<button onclick="insertSpan();">Insert span element example</button>
<p>
Span element is inserted below:
<p id="insert-span-here">

</body>
</html>

========== Interactive HTML document end ================
 
E

Elegie

mavigozler wrote:

Hi,

Note that I clone a
template span node whenever I need it, with the attributes for
"onmouseover" and "onmouseout" set to highlight and un-highlight text,
respectively.

While this approach is certainly sound theoretically, it should actually
fail. I am unsure about which observed behavior is the correct one,
given the existing specifications, or what the actual mechanisms
implemented by user agents are; what follows is just some personal
interpretation (corrections welcome).

In HTML, you can define event attributes, such as onmouseover,
onmouseout. However, these are special, as they should translate into
event listeners, at parsing time. As a result, should they still be
considered as attributes? Probably not, though one could probably keep
some simple text attribute for the record. And if they're not
attributes, they should not be cloneable.

So your problem is the combined use of setAttribute and cloneNode.
Defining a string to be implicitly transformed into listeners by the
browser is risky; while it works in Firefox, it does not in IE.
Generally, we never use setAttribute for event listeners, but rather
event-specific methods (such as addEventListener, attachEvent, or even
the simple elem.on<event>) - actually we never use it at all in HTML
scripting.

As a result, refine your pattern; it would be better to use some
factory, which would create the element, fill in the properties, and
assign the listeners.
if (status == true)

if(status) is better, and a conditional (?:) statement would be even
better here.


HTH,
Elegie.
 
R

RobG

mavigozler wrote:

Hi,



While this approach is certainly sound theoretically, it should actually
fail. I am unsure about which observed behavior is the correct one,
given the existing specifications, or what the actual mechanisms
implemented by user agents are; what follows is just some personal
interpretation (corrections welcome).

In HTML, you can define event attributes, such as onmouseover,
onmouseout. However, these are special, as they should translate into
event listeners, at parsing time. As a result, should they still be
considered as attributes? Probably not, though one could probably keep
some simple text attribute for the record. And if they're not
attributes, they should not be cloneable.

I think they are and should be cloneable - but maybe that's just me.

So your problem is the combined use of setAttribute and cloneNode.
Defining a string to be implicitly transformed into listeners by the
browser is risky; while it works in Firefox, it does not in IE.
Generally, we never use setAttribute for event listeners, but rather
event-specific methods (such as addEventListener, attachEvent, or even
the simple elem.on<event>) - actually we never use it at all in HTML
scripting.

The problem is cloning nodes with event handlers - I'd previously
discovered that with in-line hanlders, IE and Firefox keep them when
nodes are cloned. When added to the dot property ( el.onclick =
function(){...}; or = someFn;) both will drop the handler from cloned
nodes. But for attachEvent/addEventListener, IE keeps them and
Firefox drops them.

So it depends on how you add the handler and which browser you are
using. I haven't time to test other browsers at the moment, nor have
I tested adding handlers with setAttribute (I never use that method of
adding hanlders, I nearly always use the dot property method).
 
M

mavigozler

RobG said:
I think they are and should be cloneable - but maybe that's just me.



The problem is cloning nodes with event handlers - I'd previously
discovered that with in-line hanlders, IE and Firefox keep them when
nodes are cloned. When added to the dot property ( el.onclick =
function(){...}; or = someFn;) both will drop the handler from cloned
nodes. But for attachEvent/addEventListener, IE keeps them and
Firefox drops them.

So it depends on how you add the handler and which browser you are
using. I haven't time to test other browsers at the moment, nor have
I tested adding handlers with setAttribute (I never use that method of
adding hanlders, I nearly always use the dot property method).

First, my thanks for the contributions of posters Elegie and RobG in
particular, and generally to those reading & joining the thread.

Based on the comments of Elegie and RobG, I continued playing around
with the code, and the validated interactive HTML code below appears to
achieve the wanted effect.

Some notes:

1. This particular re-coding I have done now attaches method (event
handler/listener) code to each dynamically created SPAN element, so if
as many as hundreds of SPAN elements are attached, I have no idea what
effect this will have on the memory heap (?) or stack (?) of the
browser's host resources. Fortunately for my use, which is to create a
development environment using an interactive HTML document to teach,
build/create and render both VML and SVG elements/objects, I don't
anticipate this problem.

For the sake of keeping resource (memory stack and/or heap) use to a
mimumum, it would be useful to also see if cloned elements could have
static functions assigned to event handlers, since this should (would?)
stop the interpreter from generating method code for each new object
instance. However the IE-specific attachEvent() and DOM-defined
addEventListener() methods do not allow the passing of parameters, and
the 'this' keyword to change object properties only works in Firefox and
causes an error in IE7, in the hour-or-so code testing I did.

Would some sort of use of prototyping be possible in this case?

2. The cloning of nodes, deep (set true) or otherwise, appears to clone
the attributes of those elements in Firefox but NOT in Internet
Explorer. Mozilla makes clear that the node cloning method includes
attributes and values of all nodes
(http://developer.mozilla.org/en/docs/DOM:element.cloneNode). The DOM
L2 specification requires this
(http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-3A0ED0A4). The
question is whether an event on a specific DOM element is really an
attribute. The HTML 4.01 specificiation clearly indicates that events
(onclick, onmouseXXX, etc) ARE attributes of elements, so in the absence
of any overriding/obsoleting specification, developers of script
interpreters not treating events as element attributes nor copying these
attributes in node cloning are not conforming to the specification. XML
documents which discuss how to incorporate event listening into the
object tree also refer to event handling specific to a node as an
attribute of that node, and one XML document notes that HTML document
"unfortunately" define events listeners as attributes of elements
(http://www.w3.org/TR/xml-events/).

As evidence that MSIE refuses to clone any attributes whatsoever and not
just those that event handlers/listeners, the 1 pixel green border is
not rendered at all in the cloning of the SPAN element, whereas Firefox
goes out of its way (in conforming to the specification?) in doing so,
as with the event handlers.


========= start validated interactive HTML code ==========

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">

<html>
<head>
<title>Mouseover Dynamic SPAN Element</title>
<script type="text/javascript">
var spanElemTemplate = document.createElement("span");
spanElemTemplate.setAttribute("style", "border:1px solid green;");

function insertSpan()
{
var insertPoint = document.getElementById("insert-span-here");
var templateInstance = spanElemTemplate.cloneNode(true);
templateInstance.onmouseover = function () {
this.style.backgroundColor = "yellow";
};
templateInstance.onmouseout = function () {
this.style.backgroundColor = "";
};
templateInstance.appendChild(document.createTextNode(
"This text should " +
"turn yellow when the mouse is over it"));
insertPoint.appendChild(templateInstance);
}

</script>
</head>
<body>

<button onclick="insertSpan();">Insert span element example</button>
<p>
Span element is inserted below:
<p id="insert-span-here">

</body>
</html>

========= end validated interactive HTML code ==========
 
E

Elegie

mavigozler wrote:

Hi,
1. This particular re-coding I have done now attaches method (event
handler/listener) code to each dynamically created SPAN element, so if
as many as hundreds of SPAN elements are attached, I have no idea what
effect this will have on the memory heap (?) or stack (?) of the
browser's host resources.

Instead of defining anonymous functions in the insertSpan function, you
could define two generic handlers outside of the function, and simply
assign references to them. This way, you'd limit the number of functions
to be created.

function mouseoverhandler(evt){/*...*/}
function insertSpan() {
/*...*/
foo.onmouseover=mouseoverHandler;
}


Also, JFTR, ECMAScript permits an implementation to join identical
function objects into a single function object. While the details of
this process are not specified, most clever implementations would
certainly try and join functions where possible (if the only difference
is a matter of scope, then it should be pretty feasible, that's the
principle of closures, working with couples {scope; function pointer}).
However the IE-specific attachEvent() and DOM-defined
addEventListener() methods do not allow the passing of parameters, and
the 'this' keyword to change object properties only works in Firefox and
causes an error in IE7, in the hour-or-so code testing I did.

That is a known IE issue with attachEvent, the "this" value refers to
the global object; instead of using directly the "this" keyword, you
could probably use
evt=evt||window.event;
elem=evt.srcElement||evt.target;

However, not using attachEvent is probably best when you do not have
more than one handlers to add, elem.on<event>=handler suffices. Also,
other patterns exist, still using elem.on<event>=handler, but permitting
many handlers (for instance keeping them into an array and having a
controller execute them, or stacking the handlers with closures).
2. The cloning of nodes, deep (set true) or otherwise, appears to clone
the attributes of those elements in Firefox but NOT in Internet
Explorer.

The situation is more complex than that, browsers' behaviors are simply
not consistent in regards of methods setAttribute and cloneNode, and the
specifications are (IMHO) too blurry to really tell who's right. Anyway,
in the end, only the result matters, so the conclusion is: use these
methods with care (or, better, adopt a safer approach, with other
approaches), after thoughtful testing in your target environments.

Let's discuss this a bit more. If you read the DTD, you'll see that
values for HTML attributes eventually resolve to text values, not
objects. However, using the DOM, we can see that elem.onevent returns a
function, and that elem.style returns an object.

This means that, during the parsing, the text attributes have been
transformed into objects, with a specific process (this process not
being described by any specification I think, though since it's been
years I haven't read them I might be mistaken).

For instance, event attributes would yield event listeners, and style
attributes would transform into an object representing the HTML style
attribute, whose property setting alters the computed style of the object.

In IE, setAttribute does not seem to trigger the process that transform
text values into objects; this means that you cannot use setAttribute to
define event handlers or style values with IE. In Firefox and Opera,
this works, though.

---
<form action=""><textarea rows="30" cols="40"></textarea></form>
<script type="text/javascript">
window.onload=function(evt){
function out(s){
document.forms[0][0].value += s+"\n";
}

// Test 1 - setAttribute
var div=document.createElement("div") ;
div.setAttribute("id", "foo");
div.setAttribute("foo", "bar");
div.setAttribute("style", "background-color:yellow");
div.setAttribute("onclick","alert('click')");

div.appendChild(document.createTextNode("Hello, world!"));
document.body.appendChild(div);

out("Id? " + (document.getElementById("foo")==div));
out("custom foo? " + (div.getAttribute("foo")=="bar"));
out("onclick? " + (typeof div.onclick=="function"));
out("style? " + div.style.backgroundColor);

/*
IE : true, true, false, <empty>
FF : true, true, true, yellow
Opera : true, true, true, #ffff00

Note: if div.foo instead of div.getAttribute(foo),
results differ.
*/
}
</script>
---

Now, suppose that you remove the setAttribute issue, by directly working
with objects (you can even remove the style issue by using a className).
In IE, the cloneNode method clones everything except HTML event handlers
(listeners attached with attachEvent are fine). Firefox and Opera copy
everything, except event listeners (all of them) and expando (custom)
attributes.

---
<form action=""><textarea rows="30" cols="40"></textarea></form>
<script type="text/javascript">
window.onload=function(evt){
function out(s){
document.forms[0][0].value += s+"\n";
}

// Test 2 - cloneNode
var div=document.createElement("div"), copy ;
div.id="foo";
div.foo="bar";
div.obj={hello:"Success"};
div.style.backgroundColor="yellow";
div.onclick=new Function("alert('click!')");
if(div.attachEvent) {
div.attachEvent("onclick", function(){alert('1')});
} else if (div.addEventListener) {
div.addEventListener("click", function(){alert('1')}, false);
}
div.appendChild(document.createTextNode("Hello, world!"));

copy=div.cloneNode(true);
document.body.appendChild(copy);

out("Id? " + (document.getElementById("foo")==copy));
out("custom foo? " + (copy.getAttribute("foo")=="bar"));
out("object value? " + (copy.obj && copy.obj.hello));
out("onclick? " + (typeof copy.onclick=="function"));
out("style? " + (copy.style.backgroundColor));

/*
IE : true, true, success, false, yellow,
FF : true, false, undefined, false, yellow
Opera : true, false, undefined, false, #ffff00

event listeners defined with attachEvent and addEventListener :
IE : copied
FF : not copied
Opera : not copied
*/
}
The
question is whether an event on a specific DOM element is really an
attribute. The HTML 4.01 specificiation clearly indicates that events
(onclick, onmouseXXX, etc) ARE attributes of elements, so in the absence
of any overriding/obsoleting specification, developers of script
interpreters not treating events as element attributes nor copying these
attributes in node cloning are not conforming to the specification.

<URL:http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/>
does not, AFAICS, mention the handling of HTML events or style
attributes, which is what matters here.


Regards,
Elegie.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top