this vs event.scrElement

F

fusillo

Hi, i've tried a test code about the Event Listener API but i've some
problem about detaching the element firing the event with IE. Here's my
code:

<html>
<head>
<style type="text/css">
..cliccabile {background-color: #FFCCCC; cursor:pointer;}
..testo {color: #009966;}
</style>
</head>
<body>
<div id="tabella">
<table id="DOMtable">
<tr>
<td id="a" class="cliccabile">clicca qui 0</td>
<td id="b" class="cliccabile"><span id="d" class="testo">clicca qui
1</span></td>
</tr>
</table>
</div>
<script type="text/javascript">
<!--
function dump_props(obj, obj_name) {
var result = "";
for (var i in obj)
result += obj_name + "." + i + " = " + obj + "<br />";
result += "<hr />";
return result;
}

function fun(evt){
if (this.className=="cliccabile") //browser standard
window.alert("this "+this.id);
else if (evt.srcElement.className=="cliccabile") //microsoft IE
window.alert("evt.srcElement "+evt.srcElement.id);
document.write(dump_props(this,"this")+dump_props(evt.srcElement,"evt.srcElement"));
}

if (document.getElementById("a").addEventListener){ //browser standard
document.getElementById("a").addEventListener('click',fun,false);
document.getElementById("b").addEventListener('click',fun,false);
}else if (document.getElementById("a").attachEvent){ //microsoft IE
document.getElementById("a").attachEvent('onclick',fun);
document.getElementById("b").attachEvent('onclick',fun);
}
// -->
</script>
</body>
</html>

When I click the element with id=b using IE it dumps the window object
by this and the span object by evt.srcElement.
Do you know an alternative to this in that case?

Thanks

fusillo
 
F

fusillo

Here's a possible solution for my problem:

<td id="b" class="testo cliccabile">clicca qui 1</td>

function fun(evt){
if (evt.srcElement &&
evt.srcElement.className.indexOf("cliccabile")>-1) //microsoft IE
window.alert("evt.srcElement "+evt.srcElement.id);
else if (this.className && this.className.indexOf("cliccabile")>-1)
//browser standard
window.alert("this "+this.id);
document.write(dump_props(this,"this")+dump_props(evt.srcElement,"evt.srcElement"));
}
 
M

Michael Winter

On 26/05/2006 02:56, fusillo wrote:

[snip]

Whilst I realise that what you posted is just an example, there are some
issues with the markup, of which you may not be aware.

HTML documents should have a document type declaration (DOCTYPE), which
nowadays should be Strict.
<head>
<style type="text/css">
.cliccabile {background-color: #FFCCCC; cursor:pointer;}
.testo {color: #009966;}

When specifying a foreground colour, a background colour should usually
be paired with it (and vice versa). Furthermore, once you set one colour
combination, you should set them all (such as link colours)[1].

It is definitely a mistake to assume that anyone is using the same
default colours as you. Consider a visitor with a desktop theme that is
light-on-dark (as opposed to the usual dark-on-light). If you set a pale
background, overriding their default dark one, but assume that their
foreground colour will be black, which it isn't, you will have just
rendered the document unreadable.

[snip]
<div id="tabella">

This div element would seem to be unnecessary...
<table id="DOMtable">

....and a table element with only one row (or one column) is always
suspect. A table should be used to contain tabular data, nothing more.

[snip]
<script type="text/javascript">
<!--

'Hiding' the contents of script elements has been unnecessary for years.

[snip]
result += "<hr />";

You aren't writing XHTML, so don't use its syntax: <hr> not <hr/>. The
same applies to the line break.

[snip]
function fun(evt){
if (this.className=="cliccabile") //browser standard
window.alert("this "+this.id);
else if (evt.srcElement.className=="cliccabile") //microsoft IE
window.alert("evt.srcElement "+evt.srcElement.id);
document.write(dump_props(this,"this")+dump_props(evt.srcElement,"evt.srcElement"));
}

if (document.getElementById("a").addEventListener){ //browser standard

You should use feature detection, rather than assuming that the
getElementById method is supported.

var a, b;

if (document.getElementById
&& (a = document.getElementById('a'))
&& (b = document.getElementById('b'))) {
if (a.addEventListener) {
/* ... */
} else if (a.attachEvent) {
/* ... */
}
}
document.getElementById("a").addEventListener('click',fun,false);
document.getElementById("b").addEventListener('click',fun,false);
}else if (document.getElementById("a").attachEvent){ //microsoft IE
document.getElementById("a").attachEvent('onclick',fun);
document.getElementById("b").attachEvent('onclick',fun);
}

The attachEvent method as currently implemented in IE is broken (in my
opinion). Rather than setting the this operator value to something
useful, namely the element to which the listener is attached, it refers
to the global object. In this instance, it would better to assign a
reference to the listener to the onclick property of the elements:

if (a.addEventListener) {
/* ... */
} else {
a.onclick = b.onclick
= fun;
}

[snip]

Now, whether you should be using the this operator or the target or
srcElement properties of the event object depends on what you're really
doing. The this operator will always refer to the element to which the
event listener is attached, whereas the target/srcElement property will
refer to the element that dispatched the event (the element that was
clicked). You'll have to choose which is the most appropriate. If you
choose the latter, the listener should be rewritten to something like:

function fun(e) {
var target;

if ((e = e || window.event)
&& (target = e.target || e.srcElement)) {
if (target.className == 'cliccabile') {
alert('Target: ' + target.id);
}
document.write(dump_props(this, 'this')
+ dump_props(target, 'Event target'));
}
}

Hope that helps,
Mike


Please refrain from using tabs when posting code to Usenet. Use a couple
of spaces, instead.

[1] If You Pick One Color, Pick Them All
<http://www.w3.org/QA/Tips/color>
 
L

Lasse Reichstein Nielsen

fusillo said:
document.getElementById("b").attachEvent('onclick',fun);
....

When I click the element with id=b using IE it dumps the window object
by this and the span object by evt.srcElement.

The IE attachEvent method does not invoke the handler as a property of
the target element, which is why "this" refers to the global object.

You know the object at the time the handler is assigned, so you
should remember it there.

I would use a helper function like:

function addEventHandler(elem, eventtype, handler) {
if (elem.addEventListener) {
elem.addEventListener(eventType, handler, false);
} else if (elem.attachEvent) {
elem.attachEvent("on"+eventtype, function(evt){
return handler.call(elem,evt)});
} else { // or whatever fallback
elem["on"+eventtype] = handler;
}
}
and then:

addEventHandler(document.getElementById("a"), "click", fun);
addEventHandler(document.getElementById("b"), "click", fun);

This would ensure that the "this" property refers to the correct
object when the handler is executed.

You should also be aware that "srcElement" is a proprietary IE property,
and the corresponding standard property is "target".
Inside the handler function, you could do:

var tgt = evt.target || evt.srcElement;

/L
 
F

fusillo

I've tried to use the call method of Function object assigning this
explicitly, but i've some problem to detach the listener, actually i
don't find a solution in my new test code. Here's:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<style type="text/css">
..cliccabile {background-color: #FFCCCC; cursor:pointer;}
..cliccato {background-color: #FF6666;}
..festivo {color: #009966;}
#tabella{background-color:#FFFFFF;}
</style>
</head>
<body>
<div id="tabella"></div>
<script type="text/javascript">
<!--

function myAddListener(obj,strtype,listener,usecapture){
if (obj.addEventListener)
obj.addEventListener(strtype,listener,usecapture);
else if (obj.attachEvent){
obj.attachEvent('on'+strtype,function myCall(evt){ window.alert('I
view myCall function'); listener.call(obj,evt); });
}
//else it throws an Error exception
}

function myRemoveListener(obj,strtype,listener,usecapture){
if (obj.removeEventListener)
obj.removeEventListener(strtype,listener,usecapture);
else if (obj.detachEvent){
myCall(null);
obj.detachEvent('on'+strtype,myCall);//I view myCall function but i
don't detach the event
}
//else it throws an Error Exception
}

function myListener(evt){
window.alert('click');
var oldclickedcell=document.getElementById('DOMtable').clickedcell;
if (oldclickedcell){

oldclickedcell.className=oldclickedcell.className.replace('cliccato','cliccabile');
myAddListener(oldclickedcell,'click',myListener,false);
}
var
newclickedcell=(this.className&&this.className.indexOf('cliccabile')>-1?this:false);
if (newclickedcell){

newclickedcell.className=newclickedcell.className.replace('cliccabile','cliccato');
myRemoveListener(newclickedcell,'click',myListener,false);
document.getElementById('DOMtable').clickedcell=newclickedcell;
}
}

function handlerGo(table_id){
document.getElementById(table_id).clickedcell=false;
var i=0,j,myrow,mycell;
while (myrow=document.getElementById(table_id).rows.item(i++)){
j=0;
while (mycell=myrow.cells.item(j++))
if (mycell.className.indexOf('cliccabile')>-1)
myAddListener(mycell,'click',myListener,false);
else if (mycell.className.indexOf('cliccato')>-1){
myRemoveListener(mycell,'click',myListener,false);
document.getElementById(table_id).clickedcell=mycell;
}
}
}
strtabella="<table id=\"DOMtable\"><tr><td id=\"2006-5-4\"
class=\"cliccabile festivo\">4</td><td id=\"2006-5-5\"
class=\"cliccabile\">5</td></tr></table>";
document.getElementById('tabella').innerHTML=strtabella;
handlerGo('DOMtable');

newclickedcell=document.getElementById('DOMtable').rows.item(0).cells.item(0);

newclickedcell.className=newclickedcell.className.replace('cliccabile','cliccato');
myRemoveListener(newclickedcell,'click',myListener,false);
document.getElementById('DOMtable').clickedcell=newclickedcell;

strtabella="<table id=\"DOMtable\"><tr><td id=\"2006-5-4\"
class=\"cliccabile festivo\">4</td><td id=\"2006-5-5\"
class=\"cliccabile\">5</td></tr></table>";
document.getElementById('tabella').innerHTML=strtabella;
handlerGo('DOMtable');
// -->
</script>
</body>
</html>

I'm conscious about importance of getElementById feature detection, but
i don't care it in this test case.
Every advice to better my programmation style is really
well-appreciated. Thanks for your helps.
Sorry for the tab usage on my previous post.

fusillo
 
L

Lasse Reichstein Nielsen

fusillo said:
I've tried to use the call method of Function object assigning this
explicitly, but i've some problem to detach the listener, ....
function myAddListener(obj,strtype,listener,usecapture){
if (obj.addEventListener)
obj.addEventListener(strtype,listener,usecapture);
else if (obj.attachEvent){
obj.attachEvent('on'+strtype,function myCall(evt){ window.alert('I
view myCall function'); listener.call(obj,evt); });

This "function myCall" is a function expression. The "myCall" name is
only visible inside the body of the function.

If you need it later, and you do if you want to detach it, you will
have to store it until it needs to be detached. You could return it
for later use:

/** returns the actual listener to remove with myRemoveListener */
function myAddListener(obj,strtype,listener,usecapture) {
if (obj.addEventListener) {
obj.addEventListener(strtype,listener,usecapture);
return listener;
} else if (obj.attachEvent) {
var myCall = function myCall(evt){
window.alert('I view myCall function');
listener.call(obj,evt);
};
obj.attachEvent('on'+strtype,myCall);
return myCall;
}
}

and then myRemoveListener should work if you pass it the return value
of myAddListeren, and not the original function.
function myRemoveListener(obj,strtype,listener,usecapture){
if (obj.removeEventListener)
obj.removeEventListener(strtype,listener,usecapture);
else if (obj.detachEvent){

obj.detachEvent("on"+strtype,listener); // returned listener,
//not original

myCall(null);

There was no myCall in scope

/L
 
T

Thomas 'PointedEars' Lahn

fusillo said:
I've tried to use the call method of Function object assigning this
explicitly, but i've some problem to detach the listener, actually i
don't find a solution in my new test code. Here's:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

You should discard XHTML 1.0 Transitional in favor of HTML 4.01 Transitional
(or better: Strict) immediately. You do not need XHTML here at all, and it
only gets you into more trouble than you realize(d).
<head>
<style type="text/css">

This is not supposed to work in XHTML. It is an XML application, therefore
XML stylesheet rules apply. In XML, the stylesheet to be used to render a
document must be defined via an <?xml-stylesheet ... ?> processing
instruction (PI) before the DOCTYPE declaration. This can be facilitated
with

<?xml-stylesheet href="#foo" type="text/css"?>
<!DOCTYPE ...>
<html ...>
<head ...>
...
<style type="text/css" id="foo">
...
</style>
...
</head>

...
</html>

But it is recommended that you refer to an external stylesheet resource
instead (because there is also the PCDATA issue, see below):

<URL:http://www.w3.org/TR/xhtml1/#C_13>

It "works" anyway because you serve XHTML as text/html, instead of the
recommended media type application/xhtml+xml. This will have UAs with
tag soup parsers to parse XHTML as if it were wrongfully error-corrected
HTML. Search the archives.

.cliccabile {background-color: #FFCCCC; cursor:pointer;}
.cliccato {background-color: #FF6666;}
.festivo {color: #009966;}
#tabella{background-color:#FFFFFF;}

Use Web-safe triplets (#fcc, #f66, #096, #fff), and take heed of
</style>
</head>
<body>
<div id="tabella"></div>

If this was parsed by an XML parser, you could write it as

<div id="tabella"/>

(If this does not work, it is a proof that an XML parser is _not_ used.)
<script type="text/javascript">
Correct.

<!--

This long-ago-obsolete ever-nonsense will get you into trouble when
a) an SGML parser is used to parse this as HTML, or b) an XML parser
is rightfully used to parse what you declared as XHTML.

a) The content model of the HTML `script' element is (and has been) CDATA,
so it is not parsed by the markup parser. However, that means the script
engine is passed the comment delimiter, which should be regarded as a
syntax error. You are relying on a proprietary, hardly documented
ECMAScript extension that allows a script engine to discard this
character sequence (and all characters that follow it up to the line
terminator) if it occurs in a line; this is error-prone.

And RFC2854 (June 2000 CE) eventually obsoleted HTML versions prior to
HTML 3.2 (January 1997 CE), so every HTML UA that can be considered
working MUST know about the `script' element (even if it does not support
client-side scripting). There is no reason for trying to hide anything
here except of the misguided attempt of keeping completely b0rken
software alive. (Do you really want that?)

b) Since the content model of the _XHTML_ `script' element is PCDATA, it is
parsed by the markup parser (in contrast to CDATA content). And an XML
parser regards this as a comment that it is allowed to remove. You
and have none said:
function myAddListener(obj,strtype,listener,usecapture){
if (obj.addEventListener)
obj.addEventListener(strtype,listener,usecapture);
else if (obj.attachEvent){
obj.attachEvent('on'+strtype,function myCall(evt){ window.alert('I
view myCall function'); listener.call(obj,evt); });
}
//else it throws an Error exception

But it does not throw an exception then.
}

function myRemoveListener(obj,strtype,listener,usecapture){
if (obj.removeEventListener)
obj.removeEventListener(strtype,listener,usecapture);
else if (obj.detachEvent){
myCall(null); ^^^^^^^^^^^^
obj.detachEvent('on'+strtype,myCall);//I view myCall function but i ^^^^^^
don't detach the event

`myCall' is undefined, and cannot be called.
}
//else it throws an Error Exception

Again, it does not.
}

function myListener(evt){
window.alert('click');
var oldclickedcell=document.getElementById('DOMtable').clickedcell;

You SHOULD NOT try to augment host objects in order to store user-defined
data; use native objects instead.
if (oldclickedcell){

oldclickedcell.className=oldclickedcell.className.replace('cliccato','cliccabile');
myAddListener(oldclickedcell,'click',myListener,false);
}
var
newclickedcell=(this.className&&this.className.indexOf('cliccabile')>-1?this:false);

(<URL:http://www.w3.org/TR/xhtml1/#h-4.8>)

An XML parser must regard the character data of the `script' element to end
here because of the `>' which is a specified as a markup character. (Point
b) above and this, is the reason why you get a parse error when you do
not "comment out" the `script' element's content, and you do not get the
error if you "comment it out".)

There are different _reasonable_ ways to avoid that; in recommended order:

1. Declare HTML instead of XHTML, and replace XML syntax with SGML syntax.
Watch that you escape ETAGO (`</') delimiters in the (then) CDATA-typed
script code, preferably via `<\/'.

or

Move the script code to an external resource and include that resource
with <script type="text/javascript" src="external_resource.js"/> (XHTML),
or <script type="text/javascript" src="external_resource.js"></script>
(XHTML, and HTML 4.01), respectively.

2. Declare the content of the element to be a CDATA section that is not to
be parsed:

<script type="text/javascript">
<![CDATA[
...
]]>
</script>

3. Escape all markup characters in the script code:

<script type="text/javascript">
...
if (1 &lt;= 2 &amp;&amp; (4 &lt;&lt; 1) &gt;= 3)
{
window.alert(42);
}
</script>

(2. and 3. are XHTML-only solutions.)

Source code should be posted so that it does not exceed 80 columns per line.
function handlerGo(table_id){
document.getElementById(table_id).clickedcell=false;

See above. Don't do that.
[...]
strtabella="<table id=\"DOMtable\"><tr><td id=\"2006-5-4\"
class=\"cliccabile festivo\">4</td><td id=\"2006-5-5\"
class=\"cliccabile\">5</td></tr></table>";
document.getElementById('tabella').innerHTML=strtabella;

`innerHTML' is a proprietary property, while document.getElementById()
is part of a Web standard. Do not mix both, at least not without
feature-testing each part of the reference.

handlerGo('DOMtable');
newclickedcell=document.getElementById('DOMtable').rows.item(0).cells.item(0);

Do not use reference worms, see above. And you do not need `.items(...)',
you can use [...] instead; the same goes for `.namedItems("...")' which can
be replaced by `["..."]'.
[...]
// -->
</script>
</body>
</html>

I'm conscious about importance of getElementById feature detection, but
i don't care it in this test case.

Your problem. You should always care.
Every advice to better my programmation style is really
well-appreciated.

[x] done
Thanks for your helps.

You are welcome.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Lasse said:
XHTML 1.0 Transitional inherits the style element from HTML 4.01.
It should work, as long as the contents are valid PCDATA
<URL:http://www.w3.org/TR/xhtml1/#h-4.8>
<URL:http://www.w3.org/TR/xhtml1/#C_4>

Please read my comment in context. I am well aware of the fact that the
`style' element is declared in the XHTML 1.0 (Transitional) DTD(s) (and not
inherited from somewhere). However, for an XML renderer to take notice of
the style rules defined therein, it is required that it is referred to in
an XML-stylesheet PI.

On more thorough reading, you will also observe that I referred to
subsection 4.8 in my followup already, and that I mentioned the possibility
that subsection C.4 states. However, I also referred to subsections C.13
(and C.14) in my followup only a few lines below the text that you quoted
above; those parts of the specification explain in detail (again) that and
why the above is not supposed to work as is in XHTML (where the terms
"XHTML documents delivered as HTML" and "XHTML documents delivered as XML"
as used there, are highly questionable, as is the idea behind the entire
"HTML Compatibility Guidelines").


PointedEars
 
F

fusillo

Thanks for your useful advises, but i have a dubt about this:

Thomas 'PointedEars' Lahn ha scritto:
You SHOULD NOT try to augment host objects in order to store user-defined
data; use native objects instead.

When i use a native object don't i augumt the window host object in a
web contest?

an example to explain what i itend:

a=new String('hello from italy');
window.alert(window.a);

So why not adding property to a table object?
 
T

Thomas 'PointedEars' Lahn

fusillo said:
Thomas 'PointedEars' Lahn ha scritto:

When i use a native object don't i augumt the window host object in a
web contest?

Probably you mean _context_. No, you don't.
an example to explain what i itend:

a=new String('hello from italy');

That identifier should be declared a variable to avoid side effects, and
`new String' is just nonsense.

var a = 'hello from italy';
window.alert(window.a);

There is no point in posting this line without saying what the result is
for you. However, probably you observe the value of `a' to be displayed.

`window' would then be a host-defined property of the Global Object (as
that is the Variable Object in global context) that refers to its owner
(provided that there is not the known IE scope chain issue). This
possibility is mentioned already in subsection 10.1.5 of the ECMAScript
Specification, Edition 3 Final (and the corresponding subsection in
previous editions), and does not have anything to do with host objects
(cf. subsection 4.3.8).
So why not adding property to a table object?

Because it is a host object, and the ECMAScript Specification (Ed. 3 Final,
subsection 8.6.2) states that host objects do not need to implement the
property access methods [[Put]] and [[Get]] as specified there. Code that
makes use of host objects as data containers (without using their defined
properties) is therefore inherently error-prone.


PointedEars
 

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

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top