feature detection to replace use of "navigator.userAgent" in Yahoo! UI event.js?

P

petermichaux

Hi,

I'm picking apart the Yahoo! UI event.js library and stripping it down
to just what I need. I'm also trying to make the parts I use better.
I'm stumped on how to fix the code for the getPageX() method. This
method is supposed to give the same value in IE as other browsers for
the event position relative to the left of the page. This value will be
greater than the position relative to the left of the browser if the
browser is scrolled to the right. What would be the appropriate feature
detection to use for the conditional in the following line?

if ( this.isIE ) {

Thank you,
Peter


isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),

isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
navigator.userAgent.match(/msie/gi)),


getPageX: function(ev) {
var x = ev.pageX;
if (!x && 0 !== x) {
x = ev.clientX || 0;

if ( this.isIE ) {
x += this._getScroll()[1];
}
}
return x;
},

_getScroll: function() {
var dd = document.documentElement, db = document.body;
if (dd && dd.scrollTop) {
return [dd.scrollTop, dd.scrollLeft];
} else if (db) {
return [db.scrollTop, db.scrollLeft];
}
return [0, 0];
}
 
R

RobG

Hi,

I'm picking apart the Yahoo! UI event.js library and stripping it down
to just what I need. I'm also trying to make the parts I use better.
I'm stumped on how to fix the code for the getPageX() method. This
method is supposed to give the same value in IE as other browsers for
the event position relative to the left of the page. This value will be
greater than the position relative to the left of the browser if the
browser is scrolled to the right. What would be the appropriate feature
detection to use for the conditional in the following line?

if ( this.isIE ) {

Don't use browser sniffing at all, use the stuff from quirksmode for
detecting the mouse coordinates:

<URL: http://www.quirksmode.org/js/events_properties.html >


Matt Kruse also has a utilities library to do much the same thing:

<URL: http://www.javascripttoolbox.com/lib/util/ >


[...]
 
P

petermichaux

RobG said:
Don't use browser sniffing at all, use the stuff from quirksmode for
detecting the mouse coordinates:

<URL: http://www.quirksmode.org/js/events_properties.html >


Matt Kruse also has a utilities library to do much the same thing:

<URL: http://www.javascripttoolbox.com/lib/util/ >

Hi Rob,

Thanks for the links. The quirksmode link gives a nice, concise
solution. Trusting that it is a robust way of doing things, I ended up
with a very short function

getPageX: function(e) {
if (e.pageX) {
return e.pageX;
} else if (e.clientX) {
return e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
}
},

What to do in the case neither e.pageX nor e.clientX exist? Probably
will never happen?

Thanks again!
Peter
 
R

RobG

RobG wrote: [...]
Don't use browser sniffing at all, use the stuff from quirksmode for
detecting the mouse coordinates:

<URL: http://www.quirksmode.org/js/events_properties.html >


Matt Kruse also has a utilities library to do much the same thing:

<URL: http://www.javascripttoolbox.com/lib/util/ >

Hi Rob,

Thanks for the links. The quirksmode link gives a nice, concise
solution. Trusting that it is a robust way of doing things, I ended up
with a very short function

getPageX: function(e) {
if (e.pageX) {
return e.pageX;
} else if (e.clientX) {
return e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
}
},

I like use an ePos() function that returns an object with x & y
properties that are the event co-ords - but that's just my preference.
Then I can test the returned value simply:

var eventXY = ePos(event);
if (ePos){...}

If you just return a value, then to account for the fact that zero is a
valid return value you have to do something like:

var eventX = getPageX(event);
if ('number' == typeof eventX) {...}

What to do in the case neither e.pageX nor e.clientX exist? Probably
will never happen?

Never say never :) Mobile browsers are becoming more prevelent, while
their support for JavaScript is generally great, their scriptable DOM
support leaves a lot to be desired.

According to Quirksmode, pageX/clientX goes back to IE 5 and Navigator
4, hopefully that is far enough for you. Anyhow, return some value you
can recognise as "not supported" (say null) and deal with it in the
calling function.

if ('number' == typeof eventX) {
/* do something with the returned value */
} else {
/* not supported, deal with it */
}
 
R

Richard Cornford

Hi Rob,

Thanks for the links. The quirksmode link gives a nice, concise
solution. Trusting that it is a robust way of doing things, I ended up
with a very short function

getPageX: function(e) {
if (e.pageX) {
return e.pageX;
} else if (e.clientX) {
return e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
}
},

What to do in the case neither e.pageX nor e.clientX exist?
Probably will never happen?

That may never happen, but a browser providing - pageX - only can still
have its value at zero and so return undefined. It is also possible
that the code may be exposed to a browser where - clientX - is not
accompanied by both of - body - and - documentElement -, so error out,
or that both of - body - and - documentElement - may be returning the
same scroll value for the browser (that was certainly true of some
Opera 7 releases, and usually worked as most scripts employed the first
of the two that appeared to provide a value so it did not matter if
both did).

(Opera <= 6 also had a bug in that they only supported - clientX/Y - on
events but returned page related offsets instead of window related).

Probably a better strategy might be to stop thinking in terms of
getting scroll positions from objects at the point of working out mouse
offsets from the page but instead to use a reliable cross-browser
scroll-offset reporting method and only apply it when an event only has
- clientX/Y - available.

<URL:
http://jibbering.com/faq/faq_notes/not_browser_detect.html#bdScroll >

Richard.
 
P

petermichaux

Richard said:
That may never happen, but a browser providing - pageX - only can still
have its value at zero and so return undefined. It is also possible
that the code may be exposed to a browser where - clientX - is not
accompanied by both of - body - and - documentElement -, so error out,
or that both of - body - and - documentElement - may be returning the
same scroll value for the browser (that was certainly true of some
Opera 7 releases, and usually worked as most scripts employed the first
of the two that appeared to provide a value so it did not matter if
both did).

(Opera <= 6 also had a bug in that they only supported - clientX/Y - on
events but returned page related offsets instead of window related).

Probably a better strategy might be to stop thinking in terms of
getting scroll positions from objects at the point of working out mouse
offsets from the page but instead to use a reliable cross-browser
scroll-offset reporting method and only apply it when an event only has
- clientX/Y - available.

<URL:
http://jibbering.com/faq/faq_notes/not_browser_detect.html#bdScroll >

Hi Richard,

Thanks for the info and the link.

I really did think that the quirksmode way of assuming document.body
and document.documentElement both exist seems a little suspicious.

The link you sent is an interesting approach. It seems a bit convoluted
but looks like it must be very efficient in use as it doesn't have to
if-else with each call. Is this code your work?

Thanks again,
Peter
 
P

petermichaux

Richard said:
Probably a better strategy might be to stop thinking in terms of
getting scroll positions from objects at the point of working out mouse
offsets from the page but instead to use a reliable cross-browser
scroll-offset reporting method and only apply it when an event only has
- clientX/Y - available.

Looking in Flanagan's book (4th ed p383), It looks like pageX/Y in
Netscape 4 would also need the scroll amounts added.



Using the function on jibbering, how does this function look?

getPageX: function(e) {
var x;
if (e.pageX) {
x=e.pageX;
} else if (e.clientX) {
x=e.clientX
} else {
return null;
}
return x + scrollInterface.getScrollX();
},


I wanted to cut this down to something like the following but I
couldn't get it working

getPageX: function(e) {
var x = (e.pageX) ? e.pageX : (e.clientX) ? e.clientX : return
null;
return x + scrollInterface.getScrollX();
},


I'm still surprised that a little tasks like finding an event location
is so challenging.

In fact, I don't really care about supporting Netscape 4 with it's lack
of clientX. Similarly, I don't really care about supporting browsers
without document.getElementById().

Thanks,
Peter
 
R

Richard Cornford

Using the function on jibbering, how does this function
look?

getPageX: function(e) {
var x;
if (e.pageX) {

You have repeated one of the logical mistakes in the Yahoo library and
failed to consider that a - pageX - may legitimately be numeric zero,
which type-converts to boolean false;
x=e.pageX;
} else if (e.clientX) {
x=e.clientX
} else {
return null;

NaN is the sensible value to return to indicate a failure from a
function call that would otherwise return another numeric value, and
the - isNaN - function is available for performing a discriminating test
for failure on the result.
}
return x + scrollInterface.getScrollX();

If the event object has a - pageX - property you don't want to be adding
scroll offsets to the - x - value. That addition should be restricted to
the - if(typeof e.clientX == 'number') - branch (if not more guarded).
},


I wanted to cut this down to something like the following but I
couldn't get it working

getPageX: function(e) {
var x = (e.pageX)?e.pageX:(e.clientX)?e.clientX:return null;
<snip>

The - return - keyword forms a Statement, while the conditional operator
takes Expressions as its operands. A syntax error would be expected
here.

return (
(typeof e.pageX == 'number')?
e.pageX:
(
(typeof e.clientX == 'number')?
(
e.clientX + scrollInterface.getScrollX()
):
NaN
)
);

- would be the single Statement formulation of your code.
I'm still surprised that a little tasks like finding an event
location is so challenging.

You can rise to a challenge or hide from it. Why do you think the
general standard of scripting on the Internet is so poor?
In fact, I don't really care about supporting Netscape 4
with it's lack of clientX.

Why would that be a problem as it supports - pageX -? The code you have
written will work fine with Netscape 4, so long as the - pageX - is not
zero.
Similarly, I don't really care about supporting
browsers without document.getElementById().

That attitude will get in the way of your learning browser scripting.
Learn to design systems that still makes sense (and in e-commerce terms;
makes money) with client-side scripting disabled and you will find
yourself in a position to cope regardless of whether a browser
provides - document.getElementById - or not. And in a position to make
informed decisions about when designing/creating such a system is
appropriate.

Richard.
 
R

Richard Cornford

I really did think that the quirksmode way of assuming
document.body and document.documentElement both exist
seems a little suspicious.

I am not a fan of the quirksmode attitude towards browser scripting.
There seems to be a lot of throwing up of hands in horror and then
walking away from the problems.
The link you sent is an interesting approach. It seems
a bit convoluted

It is convoluted, but internal complexity inside self-contained
components that follow the logic of the problem through to the point
where they should not need ongoing maintenance is not a great concern of
mine. The external interface is simple and that should be the only
concern of anyone using the component.
but looks like it must be very efficient in use as it
doesn't have to if-else with each call.

Yes, I don't like repeating tests on each call to a function in an
environment/context where all tests after the first a bound to return
the same result as the first.
Is this code your work?

Would that matter?

Richard.
 
P

petermichaux

Hi Richard,

Thank you for the detailed reply.

[snip]
You can rise to a challenge or hide from it. Why do you think the
general standard of scripting on the Internet is so poor?

I definitely want to rise to the challenge. A lot of the browser
incompatibility workarounds are quite subtle and it's great exprienced
people here are willing to share their experience. I also think that
the prototype.js, Scriptaculous, Yahoo! UI developers should spend more
time here asking quesitons and reading the discussions. Perhaps they
have to maintain an appearance of expertise.

Peter
 
R

Richard Cornford

I definitely want to rise to the challenge. A lot of the
browser incompatibility workarounds are quite subtle and
it's great exprienced people here are willing to share
their experience. I also think that the prototype.js,
Scriptaculous, Yahoo! UI developers should spend more time
here asking quesitons and reading the discussions. Perhaps
they have to maintain an appearance of expertise.

"Maintain an appearance" or 'maintain a self-delusion'? None of the
people I consider experts in browser scripting would have created any of
those, except Yahoo, but that is only because I see Yahoo's motivation
as unrelated to what they have published.

Richard.
 

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,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top