clicking on list elements - problem

R

Random

window.event always exists in IE, though outside of an event handler
(or recursively-called functions) its value is reported as null. It
doesn't seem possible to retrieve a reference to the window.event
object -- it always gives back a copy of itself (see code segment
below).

Based on this and several other quick-and-dirty experiments, it seems
most likely that IE has an internal class it uses to represent an
event, which it instantiates and exposes as window.event. When the
event's registered handler finishes, the value of window.event is
reverted to null (rather than a pointer or reference to an internal IE
object). The actual object is destroyed per normal garbage collection:
when its internal reference counter reaches 0.

It is also possible that it's not exposing an internal object but
instantiating a JavaScript object, but I doubt it-- trying to set
..srcElement to a string yields 'type mismatch', and error we're not
very used to seeing in JS.

Because of the garbage collection, it is possible to have two 'Event
objects' instantiated (by keeping at least one reference to an event
that was already processed), but I'm not certain that there is a way to
make two events _fire_ simultaneously. I've never tried on a
dual-processor machine. I did attempt in a very cursory fashion to make
IE process two events simultaneously, but it wouldn't do it. It wanted
to handle each sequentially.
It would mean that we have 2 global vars with the same name and
different values (nonsense).

Not necessarily.

An onClick for a submit button is processed in its entirety before IE
'bubbles' upward, instantiating a new Event object and referencing it
with window.event then calling the form's onClick. When the form's
onClick return()s, IE 'bubbles' again, instantiating a new Event
object, to the body. When bubbling has finished, it instantiates an
Event and calls the form's registered onSubmit handler.

In fact, I couldn't get IE to run any other code while a handler was
running, so I couldn't get a better look at some of the finer details
in question here.

Point being, only one value for window.event is ever required at any
given moment.


Code segment referenced above:
<html>
<script>

var x = window.event;
var y;

function onload() {
y = window.event;
alert( x );
setTimeout( 'alert(y)', 1000 );
setTimeout( 'alert(x)', 2000 );
setTimeout( 'alert(window.event == y)', 3000 );
}

</script>
<body onload=onload() />
</html>

believe
there is in Gecko-based browsers.

Should we say "There is an event dispatcher in all browsers that..."
This way we are escaping a confusion between the Event as a programming
term definition (like Function, Subroutine, Loop etc) and some real
entity.

before bubbling starts.

Don't agree. It is rather simple to recreate a situation when we are
handling several events at once (say drag and mousemove). It would mean
that we have 2 global vars with the same name and different values
(nonsense). Actually Microsoft says the same on their usual baby-talk:
"The event object is available only during an event-that is, you can
use it in event handlers but not in other code".
So the eventstamp "event" acts as private variable: generic to the
event handler and its inner functions.

outerFunction.arguments[0].som­eEventProperty.
Not a recommende way

Just thinking off a way to work with intrinsic event handler having
some arguments to pass to other function:

<div onclick="f1(arg0,arg1,arg3)"> - no problem with IE, but in FF arg0
must be sacrificed to event/event property. It is not very convenient
to reserve first argument in each function for e, just in case if it
will be called from an intrinsic event handler.
?
 
M

Michael Winter

On 24/05/2005 08:57, VK wrote:

[snip]
Don't agree. It is rather simple to recreate a situation when we are
handling several events at once (say drag and mousemove).

Though reentrancy may occur, events are handled synchonously. As far as
a script is concerned, there is only one event to deal with at a time.
What occurs within the application is of no consequence to us.

[snip]
"The event object is available only during an event-that is, you can
use it in event handlers but not in other code". [...]

Microsoft mean that an event object doesn't persist once it has finished
bubbling through the document.
So the eventstamp "event" acts as private variable: generic to the
event handler and its inner functions.

It has nothing to do with inner functions. In IE, the event object is
global. It's as simple as that. However, the object is transient, not
persistent.

[snip]
<div onclick="f1(arg0,arg1,arg3)"> - no problem with IE, but in FF arg0
must be sacrificed to event/event property.

Utter nonsense. Read how an intrinsic event listener is defined
internally, again. I've already demonstrated it twice in this thread.
I'm not doing it a third time.

[snip]

Mike
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Mon, 23 May 2005
17:46:01, seen in Lasse Reichstein Nielsen
When you create a new object based on the Date function, the new
object inherits methods from Date.prototype. It is also assigned a
value that is the current time, as reported by the operating system
(the Date function is a host object, so it can access non-Javascript
resources).


The latter only, however, if it is given no parameter.

If it is given a numeric parameter, its initialisation should be, and
IIRC on my system is, much faster, since it does not have to ask for the
time.

If it is given a string parameter, it has to work out what the parameter
means - and of course may get an answer other than the intended one (for
example, if the intended year was low-numbered).
 
L

Lasse Reichstein Nielsen

VK said:
Should we say "There is an event dispatcher in all browsers that..."

It's true, so let's :)
Don't agree. It is rather simple to recreate a situation when we are
handling several events at once (say drag and mousemove).

Nope. JScript is not multithreaded, and each event his handled
completely before the next is fired. You might trigger two events at
one time, but the JScript system fires the one at a time.
It would mean that we have 2 global vars with the same name and
different values (nonsense).

Same variable, different time.
Actually Microsoft says the same on
their usual baby-talk: "The event object is available only during an
event-that is, you can use it in event handlers but not in other
code".

Which is correct, since even if you can store a reference to the event
inside the event handler code, then using it later gives the values of the
new event, not the old one.
So the eventstamp "event" acts as private variable: generic to the
event handler and its inner functions.

The name "private variable" has a quite different meaning. The "event"
variable is global. Its value is constrained to making sense only
during event handling.
<div onclick="f1(arg0,arg1,arg3)"> - no problem with IE, but in FF arg0
must be sacrificed to event/event property. It is not very convenient
to reserve first argument in each function for e, just in case if it
will be called from an intrinsic event handler.

If the function can be called both during event handling and not, then
it doesn't use the event, and there is no need to pass it as an
parameter.

If the function uses the event, then it should be called during event
handling, and I see no problem with passing it as a parameter. In fact,
I prefer the event as a paramter to using a global variable.

So, I can't see a problem here.

/L
 
M

Michael Winter

<div onclick="f1(arg0,arg1,arg3)"> - no problem with IE, but in FF arg0
must be sacrificed to event/event property.

As I said very gruffly previously (I apologise), this isn't true. For
simplicity, I'll refer to the IE and Netscape event models. This isn't
accurate as other user agents also implement these models; Opera, for
instance, implements both.

When a listener is attached directly to an element, its first argument,
under the Netscape model, will receive the event object. That is, if a
listener is added using the addEventListener method, or if a reference
to a function object is assigned to an on<type> event property, then
that listener will only be called with one argument: the event object.

Code that is added via HTML attributes is different. It becomes the
function body of a listener created by the user agent itself. As such,
there are no constraints; you can do whatever you want with it. Do you
see the difference?

<div onclick="/* some code */">

and

<div id="myDiv">

document.getElementById('myDiv').onclick = function(event) {
/* some code */
};

are identical from a practical point of view. If you display the value
of the onclick property in both cases in a user agent that follows the
Netscape model, you will see the same string value.

If you wanted to call a function from within these listeners to do the
real event handling, you don't have to pass the event object first. You
are free to define the code within these listeners as you please.

<div onclick="myFunction(event, this);">

and

<div onclick="myFunction(this, event);">

are both fine. The event identifier provided by a user agent won't
suddenly stop working if you use the latter.

The difference that does exist between the listener created by the user
agent when it parsed intrinsic event attribute, and those listeners that
you add directly yourself, is that the user agent always provides the
event object through the identifier, 'event'.

<div onclick="/* You must use 'event' here to access the object. */">

This is true under either event model.

When you add the listener yourself, you can use any identifier you like
under the Netscape model.

<div id="myDiv">

document.getElementById('myDiv').onclick = function( whatever ) {
/* You now use 'whatever', here. */
};

Under the IE model, you must still use 'event':

document.getElementById('myDiv').onclick = function() {
/* No argument is passed to this listener.
* You must use the global, 'event', instead.
*/
};

So, combining them, you get:

document.getElementById('myDiv').onclick = function( whatever ) {
whatever = whatever || event;
};


Unless you state what you don't understand about this, I doubt anyone
will be able to help you. I think you might be trying to over analyse it
all. Your theories as to what occurs within the application, for
example, are irrelevant. It has no effect on how you need to write event
handling code.

Mike
 
V

VK

1. About the nature of the event object in IE:
IE creates new public event object for each event. This object is
called "event" and it is available until anyone is using it. So it can
be any amount of event objects (up to the capacity of your program
stack). All these objects are equally named "event". Only one event
object is visible to the program context at the given time. Which one -
it depends on who is the original caller (aka original event owner).
Overall it's a re-incarnation of the application message queue.

Testcase (IE only of course):

<html>
<head>
<title>Event test 009</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">
<script>

function test1() {
document.getElementById('p2').fireEvent('onmouseup');
alert(test2());
}

function test2() {
return event.srcElement.innerText;
}

function test3() {
alert(event.type);
}
</script>
</head>

<body bgcolor="#FFFFFF">
<p id="p1" onclick="test1()">Line One</p>
<p id="p2" onmouseup="test3()">Line Two</p>
</body>
</html>

Click on Line One, get the event type for Line Two, get the original
event info for Line One after that.

Besides theoretical blah-blah, it answers the question about
time-consuming operations (like db connections) on events. Nothing
terrible will happen as you can see: the system will keep bubbling, but
the instance of the original event will wait you however long you want
(until the end of the session).


2. Event handling
Dear Michael, I know very well how to get event properties in a FF/IE
compatible way. Still thank you for your long responce.
The question was & is: what is the most universal and reliable way if
we need the bubbles back-tracking?
Consider the code below (instead of div's could be table cells, span's,
ul's - just search this newsgroup for samples). So we have some
universal update(objectRef, newContent) function and we want to use it
on OuterLayer, and only on it (filtering out the underlaying elements).
What update() function should we use?

[1]
...."OuterLayer" onclick="update(this,newContent)"...
....
function update(obj, content) {
// Doesn't work at all within ECMA:
// var trg = (event)? event.srcElement : /* what to do with FF? */
//if (obj == trg) {
// obj.innerHTML = content + obj.innerHTML;
//}
}

[2]
...."OuterLayer" onclick="update(this,newContent)"...
....
function update(obj, content) {
/* It works, but ECMA doesn't promise (but neither prohibits) this
functionality: */
var trg = (event)? event.srcElement : obj.onclick.arguments[0].target;
if (obj == trg) {
obj.innerHTML = content + obj.innerHTML;
}
}

[3]
....OuterLayer onclick="update(event.target, this, newContent)"...
....
function update(tar, obj, content) {
/* It works, it's ECMA-obeyant, but the first argument is reserved for
POSSIBLE argument */
var trg = (tar)? tar : event.srcElement;
if (obj == trg) {
obj.innerHTML = content + obj.innerHTML;
}
}

If I'm writing a library for further distribution, I need to take a
decision right here. My update() function can be called from anywhere:
from an event handler, from another function, directly. What is the way
to make it maximum usage-friendly?

<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">
<script>

</script>
<body bgcolor="#FFFFFF">
<div id="OuterLayer" onclick="<!-- do what ? -->"
style="position:absolute; width:400px; height:400px;
background-color:#FFFF99; z-index:1; left: 50px; top: 50px">
<div id="InnerLayer1" style="position:absolute; width:300px;
height:300px; background-color:#66FF66; z-index:2; left: 50px; top:
50px">
<div id="InnerLayer2" style="position:absolute; width:200px;
height:200px; background-color:#CCCCFF; z-index:3; left: 50px; top:
50px"></div>
</div>
</div>

</body>
</html>
 
V

VK

[3]
...OuterLayer onclick="update(event.target, this, newContent)"...

Actually here is FF who doesn't act by ECMA, because it doesn't let you
forward an argument from the outer function to the inner one.
....onclick="update(event, this, newContent)... - this will fail
("event" is UOA - Undefined On Arrival :)
You have to pull out the needed properties right on the spot, or you
are out of luck. The fact that obj.onclick.arguments[0] works like a
charm - it shows that this might be not an error, but an intentional
block. But why?
 
M

Michael Winter

1. About the nature of the event object in IE:

I'm not going to comment on this. As I said previously, it's entirely
irrelevant.

[snip]
Dear Michael, I know very well how to get event properties in a FF/IE
compatible way. [...]

But there seems to be some doubt about that, otherwise you wouldn't be
posting a question that I already answered.

[snip]
...OuterLayer onclick="update(event.target, this, newContent)"...
...
function update(tar, obj, content) {
/* It works, it's ECMA-obeyant, but the first argument is reserved for
POSSIBLE argument */

Only because *you've* chosen to reserve the first argument. Either you
didn't read my previous post, or you didn't understand it. I will try
one last time. If you don't get it this time, I give up.

Say that we're going to add this onclick event via addEventListener (I'm
skipping feature detection and whatnot for simplicity):

var outerLayer = document.getElementById('OuterLayer');

outerLayer.addEventListener('click', listener, false);

When listener is called, it will be passed the event object as it's
first argument, so we need a function along the lines of:

function listener(e) {
/* ... */
}

Now we call your update function with the following signature:

function update(object, content, event) {}

with

function listener(e) {
update(this, '...', e);
}

OK? That's simple enough.


Now instead, we'll use the onclick attribute. The process is exactly the
same (!) with only one difference: the user agent will create 'listener'
for us internally, with 'event' instead of 'e':

onclick="update(this, '...', event);"

That's it. Do you see? The onclick attribute just specifies code for the
body of a generated function. What you put in that function body is up
to you - you can pass the event object in any way you choose. It's your
decision.

I already said this in my previous post, and I think I've made it as
clear as I possibly can. If you don't understand, well, I'm really not
sure what else I can do, especially if you just keep repeating yourself
or going off on tangents, rather than helping me to help you.


Using what I wrote above, your update function would look something like:

/* The event argument is optional. If missing,
* the content will be prepended to the object
* unconditionally.
*/
function update(object, content, event) {
var target;

/* First, check if an event object was passed to the
* function. If so, attempt to obtain the target
* element of that event.
*/
if(event) {target = event.target || event.srcElement;}

/* If no target was found (because no event object
* was passed), OR the target was the object argument,
* prepend content to object.
*/
if(!target || (target == object)) {
object.innerHTML = content + object.innerHTML;
}
}

Even if you still haven't understood (and I hope to &deity; that you
have), just try what I've suggested. You'll see that it works.

Mike
 
T

Thomas 'PointedEars' Lahn

VK said:
The best trick for all this event mess so far I found is from Lasse
Reichstein Nielsen:
...
<li id="i" onclick="show(this, (event.target||event.srcElement))">Some
text­</li>
...

That is not the best way. Consider that, however unlikely, the `event'
reference is `undefined' or `null', this would result in a script error;
what you are relying on in the above is still non-standard host-specific
behavior.

The below `show' method, on the other hand, can check whether the passed
argument is `undefined' or `null' before accessing its properties. That
would result in:
function show(src,trg) {
if (src == trg) {
alert(src.id);
}
}

<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript">
function show(src, e)
{
var trg = e && (e.target || e.srcElement);
if (trg && (src == trg))
{
alert(src.id);
}
}
</script>
...
Works for IE 6.x and FF 1.0.3/4

And no more is for sure without change.


PointedEars
 
T

Thomas 'PointedEars' Lahn

VK said:
[3]
...OuterLayer onclick="update(event.target, this, newContent)"...

Actually here is FF who doesn't act by ECMA, because it doesn't let you
forward an argument from the outer function to the inner one.

But it does.
...onclick="update(event, this, newContent)... - this will fail
("event" is UOA - Undefined On Arrival :)

No, it is not. Either your test case is flawed or your Firefox nightly
is buggy.
You have to pull out the needed properties right on the spot, or you
are out of luck.

No, it works long since without referring to properties of `event'
within the event handler attribute value and that did not change
to date.


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,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top