Absolute element offsets--exercise in futility

T

Thomas 'PointedEars' Lahn

kangax wrot:
As per my observations, Safari 2.x seems to crash when accessing a
non-built-in property of a nodelist which contains textnodes. It does
not crash when there are no textnodes or when accessing a built-in
property such as "length" or "item".

IOW, the foolishness of the person augmenting host objects
backfires on them. Works as designed *g*


PointedEars
 
G

Garrett Smith

kangax said:
Not exactly.

There's no augmentation going on. You don't have to extend nodelist with
anything to make Safari blow up. Prototype.js actually does not extend
nodelists either (although, it does extend/augments tons of other stuff
quite carelessly). All that triggers an "error" is a mere property
access if a property is "unknown" to Safari.

That was what I understood from your earlier post, though you used
"built-in" to describe a property of a host object. That is the wrong term.

A built-in object is a native ecmascript object that is provided by the
language itself, not the language and not the host environment. A
NodeList is where the error occured. A NodeList is not a built-in.

I took that to mean: The crash did not occur when there are no text
nodes or when accessing a property that is found in the NodeList's
prototype.

The Safari crash occurs when the node is a part of the DOM.
Historically, testing properties of host objects has been done with
`typeof` (and, IIRC, David mentioned that he had no problems with it for
the past 10 years), but in this case even `typeof` can't help. This was
just an example of `in` being safer than `typeof` (in this particular
case) and I wanted to let everyone know about it.

Thanks. It seems the jQuery and Mootools guys noticed the problem, too.
The problem occurs when you get in a situation with an array-like
object, where a nodeList gets passed in (as to be expected), but the
node is not part of the document.
Of course, `in` is not a replacement to `isHostMethod` (as the latter
one checks the result of `typeof` for particular values). Maybe `in`
could simply be used as a guard before `isHostMethod`.

The |in| operator could be used in lieu of it and that should work for
most cases (except the document.styleSheets case, recently seen here).

The generic isHostMethod doesn't really tell you much about the value of
a arbitrary host object property.

Garrett
 
G

Garrett Smith

Garrett said:
[...]

A built-in object is a native ecmascript object that is provided by the
language itself, not the language and not the host environment. A
NodeList is where the error occured. A NodeList is not a built-in.

Edit/Correction:

A built-in object is a native ecmascript object that is provided by the
language itself, not the host environment.

Garrett
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
[...]
(function(){
   jQuery.support = {};
   var root = document.documentElement,
   script = document.createElement("script"),
   div = document.createElement("div"),
   id = "script" + (new Date).getTime();
Interesting start.  No test to see if root is defined.  No check for
createElement.  Stored references to host objects.
Are there any known non-ancient clients that don't have
`document.documentElement` defined? I searched the archives but don't
see any mention of missing `document.documentElement`.
Depends on what you mean by non-ancient.  Regardless, it isn't too
difficult to do something like:
var root = document.documentElement || document.body;

It would make as much sense to use:-

var root = document.documentElement || document.unknown

Actually, that makes no sense at all. What are you saying?
Do you have a browser where document.body is the body element and
document.documentElement is undefined? Please share it.

Doesn't matter whether I have one or not, does it?
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
[...]
(function(){
   jQuery.support = {};
   var root = document.documentElement,
   script = document.createElement("script"),
   div = document.createElement("div"),
   id = "script" + (new Date).getTime();
Interesting start.  No test to see if root is defined.  No check for
createElement.  Stored references to host objects.
Are there any known non-ancient clients that don't have
`document.documentElement` defined? I searched the archives but don't
see any mention of missing `document.documentElement`.
Depends on what you mean by non-ancient.  Regardless, it isn't too
difficult to do something like:
var root = document.documentElement || document.body;

It would make as much sense to use:-

var root = document.documentElement || document.unknown

Do you have a browser where document.body is the body element and
document.documentElement is undefined? Please share it.

I assume by "have" you mean have one installed on site. Turns out I
do. IE4 and it runs on XP to this day (thought it would.) Doesn't
really matter how many others. As I noted, the known varieties are
very old.

This was discussed last summer:

http://bytes.com/groups/javascript/820668-emulating-document-documentelement-pre-w3c-dom-browsers

Unfortunately, the discussion got off track before a proper solution
was suggested (use document.all.) The OP is also recommending
"filling in" the documentElement property, which is the absolute last
thing you should do.

And no, such "emulation" is not strictly necessary today. Still
recommended to check that a host element reference is indeed a host
element reference before calling one of its methods. Why not?
 
G

Garrett Smith

David said:
David said:
David Mark wrote:
David Mark wrote:
[...]
(function(){
jQuery.support = {};
var root = document.documentElement,
script = document.createElement("script"),
div = document.createElement("div"),
id = "script" + (new Date).getTime();
Interesting start. No test to see if root is defined. No check for
createElement. Stored references to host objects.
Are there any known non-ancient clients that don't have
`document.documentElement` defined? I searched the archives but don't
see any mention of missing `document.documentElement`.
Depends on what you mean by non-ancient. Regardless, it isn't too
difficult to do something like:
var root = document.documentElement || document.body;
It would make as much sense to use:-

var root = document.documentElement || document.unknown

Actually, that makes no sense at all. What are you saying?

The type of supposition and guesswork involved is equivalent.
Doesn't matter whether I have one or not, does it?

It doesn't make much sense to suppose that existence of a phenomenon
when no evidence of that thing having occurred is provided.

Such thinking is the basis for most religion. (or paranoid superstition).

In fact, now that I think of it, it kind of reminds me of the old people
who go to church because God might be watching them. Sounds like a
low-cost insurance, right? A little church to avoid eternal hell? (you
never know!)

I have as many browsers where:-

document.documentElement || document.unknown;

results in document.unknown being something equivalent to
documentElement as you have browsers where:-

document.documentElement || document.body;

- results in document.body being something equivalent to documentElement.

Creative imagination can lead to useful conjecture. This conjecture can
lead to tests. What we are lacking here is a test. There is no evidence
of the need for document.body when document.documentElement is falsy.

You've provided conjecture, but have not followed through with a test.

If there is such a browser, I would be interested to know about it. That
way, I might be able to investigate it (to find its other quirks, etc).

If you (or anyone) has something other than guesswork and supposition,
please share it.

Garrett
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
David Mark wrote:
[...]
(function(){
   jQuery.support = {};
   var root = document.documentElement,
   script = document.createElement("script"),
   div = document.createElement("div"),
   id = "script" + (new Date).getTime();
Interesting start.  No test to see if root is defined.  No check for
createElement.  Stored references to host objects.
Are there any known non-ancient clients that don't have
`document.documentElement` defined? I searched the archives but don't
see any mention of missing `document.documentElement`.
Depends on what you mean by non-ancient.  Regardless, it isn't too
difficult to do something like:
var root = document.documentElement || document.body;
It would make as much sense to use:-
var root = document.documentElement || document.unknown
Actually, that makes no sense at all.  What are you saying?

The type of supposition and guesswork involved is equivalent.

You should have read my replies in the other order. You could have
searched your own posts from last summer for that matter.

As for equivalence, that is not what my example is after (I want an
arbitrary element.) I suggested this for Resig's thing:

if (root && root.style) {

[snip]
 
G

Garrett Smith

kangax said:
Garrett said:
That was what I understood from your earlier post, though you used
"built-in" to describe a property of a host object. That is the wrong
term.
Understood.


A built-in object is a native ecmascript object that is provided by
the language itself, not the language and not the host environment. A
NodeList is where the error occured. A NodeList is not a built-in.

I took that to mean: The crash did not occur when there are no text
nodes or when accessing a property that is found in the NodeList's
prototype.

Let me try this again :)

The crash occurs when a *property which is not part of a NodeList
interface* (i.e. "item", "length" or any numeric one) is being accessed
on a NodeList object *which contains textnode elements* and *is not part
of a document*:

typeof el.childNodes.item; // "function"
typeof el.childNodes.length; // "number"
typeof el.childNodes[0]; // "object"
el.childNodes[999]; // null

typeof el.childNodes.foo; // boom!
The Safari crash occurs when the node is a part of the DOM.

Correction: is *not* part of the DOM.
Actually, it's the other way around. When an element is inserted in a
document, the crash does not occur. Thanks for catching this, I haven't
noticed it first time.

Right! Crash occurs when the node is *not* part of the dom.

I did confirm that crash, using your testcase, on my Mac,
using Safari 2.0.4.
Not sure about array-like objects (e.g. `arguments` object is not
"affected"). I only noticed this with NodeList's.

Right, but a method like jQuery makeArray, or the Prototype.js toArray
function is expected to be used with anything array-like, such as a
NodeList, but not limited to that (could be a string or arguments object).

Method jQuery.makeArray "Turns anything into a true array."
Well, AIUI, both - `isHostObjectProperty` and `isRealObjectproperty`
(from David's lib) would fail as well.

The typeof operator is limited and the wording very weak for host
objects (implementation-dependent) and the implementations differ. The
known values for callable host objects, when passed to tyeof includes:
"object", "function", "unknown", and "string".

A long string of typeof checks adds some (possibly important) clutter.

Garrett
 
T

Thomas 'PointedEars' Lahn

kangax said:
Not exactly.

There's no augmentation going on. You don't have to extend nodelist with
anything to make Safari blow up. Prototype.js actually does not extend
nodelists either (although, it does extend/augments tons of other stuff
quite carelessly).

Could that be the reason why this test breaks Safari 2.x? Maybe it has/had
host objects inherit from native objects like Gecko.
All that triggers an "error" is a mere property access if a property is
"unknown" to Safari.

Historically, testing properties of host objects has been done with
`typeof` (and, IIRC, David mentioned that he had no problems with it for
the past 10 years), but in this case even `typeof` can't help. This was
just an example of `in` being safer than `typeof` (in this particular
case) and I wanted to let everyone know about it.

The question remains why one would ever access the `foo' property of this
host object (I do understand `foo' to be a placeholder). You don't have a
case before you have showed that a property that is provided by Safari 3.x
WebCore or specified in W3C DOM Level 2+, and is *useful*, triggers that
behavior in Safari 2.x.

That said, can't Safari 2.x be considered FUBAR and obsolete by now?


PointedEars
 
D

David Mark

Let me try this again :)
The crash occurs when a *property which is not part of a NodeList
interface* (i.e. "item", "length" or any numeric one) is being accessed
on a NodeList object *which contains textnode elements* and *is not part
of a document*:
typeof el.childNodes.item; // "function"
typeof el.childNodes.length; // "number"
typeof el.childNodes[0]; // "object"
el.childNodes[999]; // null
typeof el.childNodes.foo; // boom!

Correction: is *not* part of the DOM.
Actually, it's the other way around. When an element is inserted in a
document, the crash does not occur. Thanks for catching this, I haven't
noticed it first time.

Right! Crash occurs when the node is *not* part of the dom.

I did confirm that crash, using your testcase, on my Mac,
using Safari 2.0.4.


Not sure about array-like objects (e.g. `arguments` object is not
"affected"). I only noticed this with NodeList's.

Right, but a method like jQuery makeArray, or the Prototype.js toArray
function is expected to be used with anything array-like, such as a
NodeList, but not limited to that (could be a string or arguments object)..

Method jQuery.makeArray "Turns anything into a true array."




Well, AIUI, both - `isHostObjectProperty` and `isRealObjectproperty`
(from David's lib) would fail as well.

The typeof operator is limited and the wording very weak for host
objects (implementation-dependent) and the implementations differ. The
known values for callable host objects, when passed to tyeof includes:
"object", "function", "unknown", and "string".

A long string of typeof checks adds some (possibly important) clutter.

That's why you use isHostMethod. It reduces such clutter and allows
for future discoveries.
 
T

Thomas 'PointedEars' Lahn

kangax said:
I don't think so. See my test case which does not include any other
scripts (and which Garrett confirmed).
OK.


You wouldn't access a property on its own. It could be passed to a
function from another routine

Another routine would still be one that is written by a user of the library,
so the question remains.
(and since we are talking about client-side scripting, there's a big
chance of host objects being passed, tested and performed certain actions
on).

There is little chance that anyone would access the property in Safari 2.x
unless it were useful in other environments.
An example I showed before demonstrated one such possibility.

But the mere possibility is not enough to satisfy the need for a rationale
for avoiding an otherwise bullet-proof approach in this UA for these type of
objects.
generic `toArray` function (which *does not augment host objects* and
does not require host objects to be augmented). `toArray` does a quite
common delegation technique and merely checks for a presence of certain
property on a given object. Little does it know that such "testing" blows
the entire browser up.

I daresay that a generic `toArray' function is not needed in the first place.
I don't know. But I know that Safari 2.x lacks quite a bit of other
useful functionality (no dynamic script injection, lack of
hasOwnProperty; I'm sure there are more) and is a constant PITA.
Prototype.js, for example, still tries to support it and so has to jumps
trough all these hoops to do so.

Does it? Or isn't it instead that the design of Prototype.js is flawed?


PointedEars
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
I daresay that a generic `toArray' function is not needed in the first place.

Perhaps.

All you really need, usually, is to convert either `arguments` object or
a nodelist. [...]
Why?

[...]
On a side note, speaking of Safari 2.x, I see that your dhtml.js (public
version of it) would fail in Safari 2.x in at least one method. Do you
support that browser in a new version of the script or did you drop it?

I have not considered it yet. I had no testing environment until shortly
ago, and now I don't have one anymore (since the company's MacBook had to be
updated to facilitate testing on Safari 3.x -- hence my asking about 2.x
being obsolete), much less was I am aware of Safari's existence at all more
than 3 years ago.

However, if you could point out where exactly it would fail and maybe
propose a workaround, I could take that under consideration. TIA.


PointedEars
 
G

Garrett Smith

Thomas said:
[...]


I have not considered it yet. I had no testing environment until shortly
ago, and now I don't have one anymore (since the company's MacBook had to be
updated to facilitate testing on Safari 3.x -- hence my asking about 2.x
being obsolete), much less was I am aware of Safari's existence at all more
than 3 years ago.

[...]

Running multiple versions of Safari on Mac:
http://michelf.com/projects/multi-safari/

Garrett
 
M

Matt Kruse

How can this be news to you?  You were my former proxy.

Actually I posted a reference is to this thread on the jquery thread
about memory leaks. It may be a slow process, but jQuery will improve
bit by bit. The developers just need a little nudging in the right
direction...

Matt Kruse
 
T

Thomas 'PointedEars' Lahn

Matt said:
Actually I posted a reference is to this thread on the jquery thread
about memory leaks. It may be a slow process, but jQuery will improve
bit by bit. The developers just need a little nudging in the right
direction...

Right. Do they need burping and diapering, too?


PointedEars
 
D

David Mark

Actually I posted a reference is to this thread on the jquery thread
about memory leaks. It may be a slow process, but jQuery will improve
bit by bit. The developers just need a little nudging in the right
direction...

The pattern is clear. If I spell everything out for them, somebody
acts. If not, years go by without action (see the - attr - method.)
Hell, they haven't even started *talking* about that mess yet (at
least not in the forums.)

Furthermore, if I announced I was going to rewrite it tomorrow, I
would own it. Of course, I'm not interested in owning such a thing.

Nobody cares about a group that is struggling to "smooth out browser
differences" years after browser behavior converged (save for IE.) Of
course, IE was stable for ten years. They blew that and then tried to
rush out a fix right ahead of IE8. But, they still don't understand
get IE6/7. We've been over all of this. They are making things
worse, rather than better (in every conceivable way.)
 

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,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top