How to explain this?

R

Ralph

Hi

I have a problem understanding why events are triggered in the way they are in the example below.
I have a function assigning events to DOM objects:

addEventHandler = function (oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
} else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = fnHandler;
}
};

Using this function I'm attaching event handling functions like this:

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

Where test function is to display types of events in textarea:

function() {
var e = EventUI.getEvent();
var test = document.getElementById('teste');
test.innerHTML += e.type + "\n";
return false;
}

OK now to the point:

When I drag across my div in IE I get following events:

mouseover - mousedown - mousedown - drag - mouseover - mouseup

And thats what I'm expecting it to do (I removed a lot mouseover events to keep it clear).
BTW: The cursor is still an arrow when I'm dragging across div.

In FF on the other hand I get only:

mouseover - mousedown - mouseover

So I'dont get second on mousedown and I don't get onmouseup. While dragging my cursor takes shape of
cross out circle.

I found the solution to it by attaching the events in this manner:

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
document.getElementById('contDiv').onmousedown=test;
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

Now it works in FF and IE.

FF:
mouseover - mousedown - mousedown - mouseover - mouseup

IE:
mouseover - mousedown - mousedown - drag - mouseover - mouseup

WHY ?

If anyone knows why its like this please respond.

Thank you very much.
 
D

Daz

Ralph said:
Hi

I have a problem understanding why events are triggered in the way they are in the example below.
I have a function assigning events to DOM objects:

addEventHandler = function (oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
} else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = fnHandler;
}
};

Using this function I'm attaching event handling functions like this:

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

Where test function is to display types of events in textarea:

function() {
var e = EventUI.getEvent();
var test = document.getElementById('teste');
test.innerHTML += e.type + "\n";
return false;
}

OK now to the point:

When I drag across my div in IE I get following events:

mouseover - mousedown - mousedown - drag - mouseover - mouseup

And thats what I'm expecting it to do (I removed a lot mouseover events to keep it clear).
BTW: The cursor is still an arrow when I'm dragging across div.

In FF on the other hand I get only:

mouseover - mousedown - mouseover

So I'dont get second on mousedown and I don't get onmouseup. While dragging my cursor takes shape of
cross out circle.

I found the solution to it by attaching the events in this manner:

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
document.getElementById('contDiv').onmousedown=test;
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

Now it works in FF and IE.

FF:
mouseover - mousedown - mousedown - mouseover - mouseup

IE:
mouseover - mousedown - mousedown - drag - mouseover - mouseup

WHY ?

If anyone knows why its like this please respond.

Thank you very much.

Firefox doesn't support an 'ondrag' event. You need to create your own
methods that will check if the object is one that's meant to be
dragable, and then detect mouse down and mouse up. When the mouse goes
down, use the mouse position to change the absolute position of the div
you are dragging (this should mean it stays with the cursor). Once you
let go of the button (onmouseup), the method should stop moving the
div.

I think the best way to handle it, would be to have a variable that is
set to true if you are dragging something, and false if it's not. Or
perhaps you can set it to the object you are dragging, then set it to
null when you finish. I am not sure why the 'mouseup' and 'mousedown'
events aren't working. I would suggest you try adding it like this, to
see if it makes any difference.

var el = document.getElementById('divElement');
el.onmouseup = function(){ alert("mouse up!); }
el.onmousedown = function(){ alert("mouse down!); }

You also need to be sure that you are using 'mouseup' and not
'mouseUp'.

Please see
http://developer.mozilla.org/en/docs/XUL_Tutorial:More_Event_Handlers#Mouse_Events
for more information.

Please let me know how you get on.

Daz.
 
R

Ralph

Daz wrote:

Thank you for response. I have not been clear in my first post. I don't drag anything. My code is to
select blocks of time on the schedule. So I have a table 48x7 with small images (7 columns and 48
rows) I wrote the code to select blocks of time. And it's working OK using events handlers assigned
like this (look at my previous post to see the code for the function addEventHandler):

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
document.getElementById('contDiv').onmousedown=test;// This line does the trick in FF
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

The ondrag event is assigned only to make it work on IE and all it does is return false.

But when I use the code like this:

addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
addEventHandler(el, 'mousedown', test); // If this line is like this it does not work in FF
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

It still works in IE but it does not in FF.
The only difference is the line addEventHandler(el, 'mousedown', test); instead of
document.getElementById('contDiv').onmousedown=test;

Now I don't understand why code does not work when I use addEventHandler(el, 'mousedown', test); in FF.

Thank you
 
D

Daz

Ralph said:
Daz wrote:

Thank you for response. I have not been clear in my first post. I don't drag anything. My code is to
select blocks of time on the schedule. So I have a table 48x7 with small images (7 columns and 48
rows) I wrote the code to select blocks of time. And it's working OK using events handlers assigned
like this (look at my previous post to see the code for the function addEventHandler):

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
document.getElementById('contDiv').onmousedown=test;// This line does the trick in FF
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

The ondrag event is assigned only to make it work on IE and all it does is return false.

But when I use the code like this:

addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
addEventHandler(el, 'mousedown', test); // If this line is like this it does not work in FF
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

It still works in IE but it does not in FF.
The only difference is the line addEventHandler(el, 'mousedown', test); instead of
document.getElementById('contDiv').onmousedown=test;

Now I don't understand why code does not work when I use addEventHandler(el, 'mousedown', test); in FF.

Thank you

It is certainly bizzare, no doubt about it. May I suggest you use try
and catch blocks, around the addEventHandler calls? As drag is not
supported by Firefox, it would certainly make sense to a) put it to the
bottom of the block of code, and b) to setup an alert to any errors
which might be caused by it.

Sorry I couldn't be of any more help. If you find that the 'mousedown'
line, and the 'ondrag' line aren't throwing errors, then perhaps you
have a bug that might be worth reporting. Another thing to do, would be
to comment out the ondrag addEventHandler function call, and see if
that makes any difference.

Good luck! :)

Daz.
 
R

Ralph

Daz said:
It is certainly bizzare, no doubt about it. May I suggest you use try
and catch blocks, around the addEventHandler calls? As drag is not
supported by Firefox, it would certainly make sense to a) put it to the
bottom of the block of code, and b) to setup an alert to any errors
which might be caused by it.

Sorry I couldn't be of any more help. If you find that the 'mousedown'
line, and the 'ondrag' line aren't throwing errors, then perhaps you
have a bug that might be worth reporting. Another thing to do, would be
to comment out the ondrag addEventHandler function call, and see if
that makes any difference.

I did everything like you have said. And it is not working. The only time it's working is when i
have it like this:

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
document.getElementById('contDiv').onmousedown=test;// This line does the trick in FF
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

If anyone wants to see the whole code and try to solve this puzzle here is the link to the code:

http://radioflag.com/sched/

the s.php file is the page with the schedule. The schedule.js is where everything is happening.

If you have any comments let me know.

PS: right now it may be slow because table is generated every time someone enters the page but I
will change it once i have everything working.

Thank you
 
V

VK

var el = document.getElementById('contDiv');
addEventHandler(el, 'drag', test);
addEventHandler(el, 'mouseup', test);
document.getElementById('contDiv').onmousedown=test;
addEventHandler(el, 'mousedown', test);
addEventHandler(el, 'mouseover', test);

Now it works in FF and IE.

WHY ?

This is a complicated problem with two overlapping issues here. So
sorry, but some long reading ahead.


Part 1 : Drag Confidential

There is undocumented system-level event in each browser
$MouseDragAtomicUnit - I placed $ sign before the name to stress out
its internal nature plus the possibility to be called different names
in C++ source code. So do not search for it on MSDN, MDC, W3C or
particular engine's specs. The same $naming $convention further.

It is the fallback option for $MouseSelectDiscreteUnits which is
checked first.

Say you started to drag some object - thus pressed down (left) mouse
button and started to move your mouse in any direction without
releasing the button.

1) First the system gets the object where the mouse was pressed.

2) Then it checks object's $AtomicSelection property. If true then go
to step 4 (your case)

3) If false then this object consists of discrete units which can be
selected individually: say block of text. In such case the system
checks if $MouseSelectDiscreteUnits action is possible to the direction
of mouse move. If yes, then the selection starts.


4) If $AtomicSelection is true then the whole object gets selected and
$MouseDragAtomicUnit starts. Unlike in Flash you are not allowed to
move displayed elements across the page by mouse means. You can only
implement such behavior via your own scripting. Thus
$MouseDragAtomicUnit gets flag $notAllowed and respectively mouse
pointer changes to "not-allowed" shape. Yet the action itself is not
cancelled until the mouse released. This is because you may drag out of
the active window boundaries and release your mouse on some other
recipient: desktop or other application window. In such case if not
prohibited by security settings and if OLE supported a reference to
dragged object will be passed to recipient. This is how documents
scraps and other interesting things are being made. This way
$MouseDragAtomicUnit has little practical sense within browser window -
it is almost always not-allowed - but it has big practical sense
overall.

The problem is that browser and specs producers seems mistook dragging
for some nasty sexual perversion :) : in ten years no one dared to
describe the exact dragging mechanics so developers, generation by
generation, are forced to re-discover it on their own problems. - And
yes, back in 1998 I myself just like your was hitting my head over the
wall why dragging <layer> either working or giving me crossed circle in
seemingly random order.


Part 2 : Killing Kenny
In order to bypass this obstacle in programmed dragging we have to tell
to the system in advance that this or that event is not what she thinks
it is. Particularly we have to warn the system that by pressing mouse
button down we are expressing _no_ intention to select something or to
use OLE dragging.
W3C and Microsoft ways to override default event behavior are
completely different, so to make cross-scripting not so painful it was
agreed to implement common shortcut: if event handler returns false
then it means "call $preventDefaultEventAction subroutine" however it
is really implemented on this or that browser.
So when you have:
document.getElementById('contDiv').onmousedown=test;
and test() has
return false;
then you call $preventDefaultEventAction for mousedown event which
otherwise would be "wait for click, select or drag".

But if you are using addEventListener / attachEvent methods then return
false; shortcut doesn't work anymore. It happens because in this case
there are not caller->callee relations where callee could return
something to its patiently waiting caller. Instead you have system
event dispatcher that notifies listeners one by one from its table.
System event dispatcher doesn't care what notified listener will do,
what will it return or if it returns anything. It notifies one and
moves to other right away.
It is also important that Gecko event dispatcher stores registered
listeners in internal array while IE in internal hash table. That means
that registered listeners on Gecko will be notified in order they were
added, while in IE they will be notified in an "organized disorder"
imposed by the internal hash storage mechanics.

This way you have two options to choose from in your particular case: a
bad one and a good one. I'll start from the good one :)
1) You drop addEventListener/attachEvent all together because in your
case they are not implied by the program logic, they do not add any
simplicity, portability or reliability. Use instead explicit event
handlers and return false; in them to prevent default actions.

2) You keep using addEventListener/attachEvent. In this case you cannot
use the universal return false; shortcut. Instead you have to use then
underlying browser-specific tools. For Gecko it will be
EventObject.preventDefault(); method and for IE
event.returnValue=false; property change.
 
R

Ralph

VK said:
This is a complicated problem with two overlapping issues here. So
sorry, but some long reading ahead.


Part 1 : Drag Confidential

There is undocumented system-level event in each browser
$MouseDragAtomicUnit - I placed $ sign before the name to stress out
its internal nature plus the possibility to be called different names
in C++ source code. So do not search for it on MSDN, MDC, W3C or
particular engine's specs. The same $naming $convention further.

It is the fallback option for $MouseSelectDiscreteUnits which is
checked first.

Say you started to drag some object - thus pressed down (left) mouse
button and started to move your mouse in any direction without
releasing the button.

1) First the system gets the object where the mouse was pressed.

2) Then it checks object's $AtomicSelection property. If true then go
to step 4 (your case)

3) If false then this object consists of discrete units which can be
selected individually: say block of text. In such case the system
checks if $MouseSelectDiscreteUnits action is possible to the direction
of mouse move. If yes, then the selection starts.


4) If $AtomicSelection is true then the whole object gets selected and
$MouseDragAtomicUnit starts. Unlike in Flash you are not allowed to
move displayed elements across the page by mouse means. You can only
implement such behavior via your own scripting. Thus
$MouseDragAtomicUnit gets flag $notAllowed and respectively mouse
pointer changes to "not-allowed" shape. Yet the action itself is not
cancelled until the mouse released. This is because you may drag out of
the active window boundaries and release your mouse on some other
recipient: desktop or other application window. In such case if not
prohibited by security settings and if OLE supported a reference to
dragged object will be passed to recipient. This is how documents
scraps and other interesting things are being made. This way
$MouseDragAtomicUnit has little practical sense within browser window -
it is almost always not-allowed - but it has big practical sense
overall.

The problem is that browser and specs producers seems mistook dragging
for some nasty sexual perversion :) : in ten years no one dared to
describe the exact dragging mechanics so developers, generation by
generation, are forced to re-discover it on their own problems. - And
yes, back in 1998 I myself just like your was hitting my head over the
wall why dragging <layer> either working or giving me crossed circle in
seemingly random order.


Part 2 : Killing Kenny
In order to bypass this obstacle in programmed dragging we have to tell
to the system in advance that this or that event is not what she thinks
it is. Particularly we have to warn the system that by pressing mouse
button down we are expressing _no_ intention to select something or to
use OLE dragging.
W3C and Microsoft ways to override default event behavior are
completely different, so to make cross-scripting not so painful it was
agreed to implement common shortcut: if event handler returns false
then it means "call $preventDefaultEventAction subroutine" however it
is really implemented on this or that browser.
So when you have:
document.getElementById('contDiv').onmousedown=test;
and test() has
return false;
then you call $preventDefaultEventAction for mousedown event which
otherwise would be "wait for click, select or drag".

But if you are using addEventListener / attachEvent methods then return
false; shortcut doesn't work anymore. It happens because in this case
there are not caller->callee relations where callee could return
something to its patiently waiting caller. Instead you have system
event dispatcher that notifies listeners one by one from its table.
System event dispatcher doesn't care what notified listener will do,
what will it return or if it returns anything. It notifies one and
moves to other right away.
It is also important that Gecko event dispatcher stores registered
listeners in internal array while IE in internal hash table. That means
that registered listeners on Gecko will be notified in order they were
added, while in IE they will be notified in an "organized disorder"
imposed by the internal hash storage mechanics.

This way you have two options to choose from in your particular case: a
bad one and a good one. I'll start from the good one :)
1) You drop addEventListener/attachEvent all together because in your
case they are not implied by the program logic, they do not add any
simplicity, portability or reliability. Use instead explicit event
handlers and return false; in them to prevent default actions.

2) You keep using addEventListener/attachEvent. In this case you cannot
use the universal return false; shortcut. Instead you have to use then
underlying browser-specific tools. For Gecko it will be
EventObject.preventDefault(); method and for IE
event.returnValue=false; property change.
Thank you very much! That what I was looking for. Excellent explanation!
I'm still very new to JS especially with cross browser scripting so mentioning the preventDefault
and returnValue did the trick. Once again thank you.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top