Absolute element offsets--exercise in futility

G

Gregor Kofler

Am Fri, 17 Apr 2009 11:48:42 +0100 schrieb The Natural Philosopher:
Gregor Kofler wrote:
I think if you start designing to the 'lowest common factor' of sentient
beings you probably are heading for a site design that will immediately
eliminate all but that lowest 1% of potential accessors.
Huh?

And you certainly shouldn't be using javascript in any meaningful way.

Bullshit. I use to "equip" date inputs with calendar widgets. With
disabled JS (or if one prefers the keyboard) the plain input alternative
is available.
Like homosexuality, I don't object to 'accessibility'. I just don't want
it to be made compulsory.

Whatever your "analogy" is supposed to mean - it's beyond my grasp.
Anyway, you can design your (private) site in whatever way you want.
I note that everyiones favorite Irish airline, is proposing to weigh
people as well as their luggage, and charge accordingly. Is this
discrimination against fat people, or is not doing it discrimination
against thin people?

It's a private enterprise, and they easily argue with technical
restrictions. But then it ain't my favourite airline anyway...
I think we should pass a law making the laws of physics allow aeroplanes
to fly on the same fuel, regardless of how much they weigh.

A-ha... Physical restrictions fall in the same category as omitted alt
attributes. I see. No further questions.

Gregor
 
D

David Mark

Gregor said:
Am Fri, 17 Apr 2009 09:33:27 +0100 schrieb The Natural Philosopher:
Indeed. Always bear in mind that your site, advertising expensive sports
equipment for the extremely physically able, must be accessible by a
broke brainless amoeba using IP over carrier pigeon transport at 20
bytes a day, running lynx on a an 8086 Venix machine.
To design your site otherwise, is to engaeg in illegal discrimination
aginst penniless amoebae.
[1] Accessible in this context meaning more than just "can" be used.
It means "designed for" alternative (non-visual) user agents.
Exactly. Make sure the olfactory plugins are available. And work.
I suppose meaningful semantics and properly filled alt and/or title
attributes would already deal with 90% of the shortcomings of todays
webpages when it comes to accessibility.

I think if you start designing to the 'lowest common factor' of sentient
beings you probably are heading for a site design that will immediately
eliminate all but that lowest 1% of potential accessors.

And you certainly shouldn't be using javascript in any meaningful way.

'For everyone else, there is the telephone'..

Like homosexuality, I don't object to 'accessibility'. I just don't want
it to be made compulsory.

I note that everyiones favorite Irish airline, is proposing to weigh
people as well as their luggage, and charge accordingly. Is this
discrimination against fat people, or is not doing it discrimination
against thin people?

I think we should pass a law making the laws of physics allow aeroplanes
to fly on the same fuel, regardless of how much they weigh.

God, it seems, is a great discriminator. Why, apparently Heaven is a
closed shop, reserved for good Christians only. Manifestly unfair.
I bet they have flash movies there.

They don't make lobotomies like they used to. :)
 
T

The Natural Philosopher

Gregor said:
Am Fri, 17 Apr 2009 11:48:42 +0100 schrieb The Natural Philosopher:


Bullshit. I use to "equip" date inputs with calendar widgets. With
disabled JS (or if one prefers the keyboard) the plain input alternative
is available.


Whatever your "analogy" is supposed to mean - it's beyond my grasp.
Anyway, you can design your (private) site in whatever way you want.


It's a private enterprise, and they easily argue with technical
restrictions. But then it ain't my favourite airline anyway...


A-ha... Physical restrictions fall in the same category as omitted alt
attributes. I see. No further questions.

Gregor
You don't do subtlety do you?
Sigh..
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
I suppose meaningful semantics and properly filled alt and/or title
attributes would already deal with 90% of the shortcomings of todays
webpages when it comes to accessibility.

No. One cannot expect the general public to know that the text size of
a Web page can easily be adjusted. Given the number of pages that set a
fixed size font below, say, 12-pt or equivalent, ISTM that 15% of the
shortcomings is insufficient to accommodate that.

Of course, it does not matter if "accessibility" is to be taken to mean
"accessibility for those lacking normal ability"; the semi-blind will
have been told about these things, and how to deal with them. It's
those who can pass for normal who are thereby adversely affected.
 
G

Garrett Smith

David said:
That is ridiculous. If you declare a display:none rule in CSS,
expecting to override it with script, you have just committed the
textbook accessibility blunder of creating a document that is
unreadable with script. Hard to imagine as the jQuery definition of
progressive enhancement applies only to script or no script (there is
no middle ground to be had.)

It sound like you think it is inherently wrong to use display: none in
the CSS.
So, you are new to browser scripting and you define such a rule in CSS
and use:

How would you handle degraded content, such as that which is only shown
for a script?

For example, a message div (for things like: "there was a server error")

How about a tooltip div or a widget that is not shown unless supported
(and requested by user). For example, a picker widget (date picker, user
picker, etc).

Garrett
 
J

Jeremy J Starcher

How would you handle degraded content, such as that which is only shown
for a script?

For example, a message div (for things like: "there was a server error")

How about a tooltip div or a widget that is not shown unless supported
(and requested by user). For example, a picker widget (date picker, user
picker, etc).

Garrett

Preferred method? Have the script create the needed elements.

Case in point: One of my websites is graphical parts lookup and I have a
few extraneous divs in there used by scripting. A few of my customers
use ancient mobile browsing devices [Stuck on HTML 3.2] so they can
purchase parts while climbing over the bike looking, and they see the
stray divs at the bottom of the page.

It didn't harm usability, so its a low-priority fix for me, but none-the-
less, it is a real-world example.
 
D

David Mark

It sound like you think it is inherently wrong to use display: none in
the CSS.

You need to qualify that a bit, but basically yes.
How would you handle degraded content, such as that which is only shown
for a script?

If it is only "shown for a script", then the element(s) should be
created by script.
For example, a message div (for things like: "there was a server error")

Case in point.
How about a tooltip div or a widget that is not shown unless supported
(and requested by user). For example, a picker widget (date picker, user
picker, etc).

Other cases in point.
 
N

Nisse Engström

I suppose meaningful semantics and properly filled alt and/or title
attributes would already deal with 90% of the shortcomings of todays
webpages when it comes to accessibility.

In my experience, non-clickable links and non-submitable
forms are much bigger problems.


/Nisse
 
D

David Mark

In my experience, non-clickable links and non-submitable
forms are much bigger problems.

Part of that is authors that can't (or won't) write documents that
work without scripting.

A bigger problem is that scripts create phony Ajaxified links, but
they don't look before they leap (i.e. they assume that all required
features are present and usable.)

For years, most of the freebie "cross-browser" scripts relied on
browser sniffing in lieu of feature testing. These scripts used to be
downloaded piecemeal from sites like Dynamic Drive. Later the trend
became large, monolithic libraries that attempted to solve "common"
browser scripting problems (as their authors see them.) In any event,
users of these scripts (e.g. Website developers, application
developers) rely on blind faith in the authors.

Interesting that ten years after browser sniffing had been determined
unfeasible, jQuery is "leading" the pack to switch to feature
testing. Unfortunately, having spent those years learning nothing,
the authors of jQuery were not up to the task. The "feature testing"
implemented in the latest rewrite of jQuery purports only to support
Opera 9+, FF3+, Safari 3+ and IE. Fails miserably at that.

I glanced at their much ballyhooed replacement code last week as it
was the subject of a complaint about memory leaks in IE.

http://groups.google.com/group/jquery-dev/browse_thread/thread/d127129441e26e52#

(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.



div.style.display = "none";


No test for the style property.


div.innerHTML = ' <link/><table></table><a href="/a"
style="color:red;float:left;opacity:.5;">a</a><select><option>text</
option></select><object><param/></object>';


XHTML markup and the innerHTML property don't mix. No test for this
proprietary property and all but one of the following tests could have
done without it (feature tests should be as simple and direct as
possible.)


var all = div.getElementsByTagName("*"),
a = div.getElementsByTagName("a")[0];


No test for gEBTN.


// Can't get basic test support
if ( !all || !all.length || !a ) {
return;
}


Short-circuit *all* of the tests because gEBTN didn't work with "*" or
the XHTML assignment failed to create elements? That is mind-
boggling.



jQuery.support = {
// IE strips leading whitespace when .innerHTML is used
leadingWhitespace: div.firstChild.nodeType == 3,


Certainly didn't need to skip that due to gEBTN failings.


// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
tbody: !div.getElementsByTagName("tbody").length,

// Make sure that you can get all elements in an <object> element
// IE 7 always returns no results
objectAll: !!div.getElementsByTagName("object")[0]
.getElementsByTagName("*").length,

// Make sure that link elements get serialized correctly by
innerHTML
// This requires a wrapper element in IE
htmlSerialize: !!div.getElementsByTagName("link").length,


Make sure an XHTML LINK element is error corrected to HTML when
descended from a DIV and created with innerHTML? This is used for a
dodgy object inference in the function that turns HTML into nodes.


// Get the style information from getAttribute
// (IE uses .cssText insted)
style: /red/.test( a.getAttribute("style") ),


They just mark land mines as they step on them. Their map(s) would
have been out of date in the year 2000.



// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
hrefNormalized: a.getAttribute("href") === "/a",


Land mine #2. That should have been enough to spot the well-known
pattern.


// Make sure that element opacity exists
// (IE uses filter instead)
opacity: a.style.opacity === "0.5",


Browser sniffing by object inference. Implies DirectX filters exist
for UA's without opacity style support. No wonder they keep lopping
off the old browsers from the supported list. Pretty pitiful to let
them crash and burn on something as simple as opacity.


// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
cssFloat: !!a.style.cssFloat,


Also a bad inference.


// Will be defined later
scriptEval: false,
noCloneEvent: true,
boxModel: null
};

script.type = "text/javascript";
try {
script.appendChild( document.createTextNode( "window." + id +
"=1;" )

);


Well, this is no good at all. If there's one thing we've been over a
million times, it is dynamic script injection. I think the discussion
dates back to 2003. The point is to test whether the snippet
executes. Unfortunately, this rendition tests whether a UA can append
a child to a script node. Odd, that it looks a bit like the test in
my library. It's like they copied it but didn't understand what they
were copying.


} catch(e){}

root.insertBefore( script, root.firstChild );


The root variable may be undefined at this point.


// Make sure that the execution of code works by injecting a script
// tag with appendChild/createTextNode
// (IE doesn't support this, fails, and uses .text instead)


So they didn't understand what they were supposed to be testing.
Obviously the failure of the first test does not imply the existence
of a text property. Certainly it does not imply that it will do
anything if set.

There's a third branch too (innerText IIRC.)


if ( window[ id ] ) {
jQuery.support.scriptEval = true;
delete window[ id ];
}


The usual bad assumptions regarding the window object.


root.removeChild( script );

if ( div.attachEvent && div.fireEvent ) {


Ineffectual feature detection (by type conversion) and browser
sniffing by object inference. Wants to test whether cloned nodes
preserve attached listeners. Infers that only UA's with attachEvent
and fireEvent are suspect (likely IE in the minds of the authors.)


div.attachEvent("onclick", function(){


Circular reference involving a host object.

http://www.jibbering.com/faq/faq_notes/closures.html#clMem


// Cloning a node shouldn't copy over any
// bound event handlers (IE does this)
jQuery.support.noCloneEvent = false;
div.detachEvent("onclick", arguments.callee);


This is the only shot to plug that leak.


});
div.cloneNode(true).fireEvent("onclick");
}

// Figure out if the W3C box model works as expected
// document.body must exist before we can do this
jQuery(function(){


Odd that feature testing code would need to create a new jQuery.


var div = document.createElement("div");
div.style.width = div.style.paddingLeft = "1px";

document.body.appendChild( div );
jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth ===2;


Which style did they forget? And AIUI, this flag is deprecated, which
means that after all of these years of trying, they are giving up on
supporting IE quirks mode. As with "old" browsers like Opera 8 and
FF2, they will simply cut the tether, meaning the next compulsory
upgrade will break every site, app and plug-in ever built and tested
in quirks mode (and nobody will help you fix them.)


document.body.removeChild( div ).style.display = 'none';


That's the first I've seen that one. If you remove a node, do you
really care about its display style?


});

Assuming the fireEvent test completes, it looks like "Drip" is
mistaken. Hard to say for sure though (that is what Task Manager is
for.) Also hard to imagine why this line is missing:


root = div = script = null;


At the very least, that will make "Drip" shut up. The fact that such
logic is missing is the sort of glaring omission that is typical of
jQuery. Not surprising that it wasn't suggested either.


})();


Why these support.* properties are exposed for others to infer God
knows what from is anyone's guess. Seems a recipe for disaster,
especially since the meaning of these flags is undocumented (and
unknown even to the author.) Lets see, if flags A, B and C are set,
but not D, then it is safe to call method X (at least until the next
upgrade.)

These flags aren't of much interest to calling apps anyway. Where's
the indication that Ajax is available or centering an element is
possible? There is none, so the apps blunder into broken "lightboxes"
and other ill-advised aspirations. Never mind that end-users *hate*
(or are at best ambivalent about) such things.

The developers write what *they* want. They like animations and new
"skills" on their résumé. However, they won't like it when these
ridiculous HTML/JS concoctions go the way of the Dodo. It won't be
the fault of the language or the browsers either.

As for jQuery specifically, there's no fixing it at this point.
Lopping additional browsers off the supported list is clearly not an
option. Even if they knew how to fix it, they can't release a new
revision every month and there is too much broken to fix all at once.
They should just admit defeat. Seems most of the remaining "supported
browsers" have selector queries and animations built-in anyway.
 
D

David Mark

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;

The former isn't even appropriate for what it is used for:

root.insertBefore( script, root.firstChild );

Presumably, the first child of the HTML element is the HEAD element.
You don't insert scripts *before* the head.
I found a message back from 2001 mentioning that `style` is missing in
NN<6
<http://groups.google.com/group/comp.lang.javascript/msg/f15bc56de91d18a7>

Okay. Regardless, it isn't difficult or time consuming to do
something like:

if (root && root.style) {
Do you know of any other clients, or do you not care who's missing what
and always test for every host object/property that's being used?

I wouldn't skip those two. If you can't find the documentElement (or
the body), you should bail out. If an arbitrary element has no style
property, you should skip assigning functions that require that
property. Neither action buys much today, other than to allow older
or unknown browsers to degrade gracefully. But, take it one step
further:

if (typeof root.style.display == 'string') {

....and you know something a bit more relevant (some UA's do not allow
scripts to modify the layout) and can prune more unusable functions
from your API (e.g. the requisite "show" function.)

That is the only (sane) way to maintain dependencies between a cross-
browser API and its calling apps. The calling apps know nothing about
the myriad possible DOM, style, etc. combinations; rather, their
gateways detect the higher-level methods of the API. I've been doing
it like that for ten years and that's why I have code around from
before the turn of the century that still works in the latest
browsers.

When jQuery proponents crow about browser abstraction through
"layers", this is the sort of scenario they envision. Unfortunately,
you can't abstract something you don't understand and you definitely
can't abstract an unknown browser with a static set of methods and a
handful of unrelated flags. Still, many bought into the
"Unobtrusiveness" of it all and built plug-ins, widgets, etc. on top
of the initial mistake. Look where they are today and imagine where
they will be tomorrow.
 
G

Garrett Smith

David said:
On 17 Apr 2009 09:52:41 GMT, Gregor Kofler 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.

When would |root| not be defined?
div.style.display = "none";


No test for the style property.

The style property should available in the browsers they support. Why
wouldn't it?
div.innerHTML = ' <link/><table></table><a href="/a"
style="color:red;float:left;opacity:.5;">a</a><select><option>text</
option></select><object><param/></object>';


XHTML markup and the innerHTML property don't mix. No test for this
proprietary property and all but one of the following tests could have
done without it (feature tests should be as simple and direct as
possible.)

Whatever they are expecting that invalid HTML to do, and how that should
be represented in the browser would not be a reasonable expectation.

Instead, they should use valid HTML and make assertions about the results.
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
tbody: !div.getElementsByTagName("tbody").length,

A tbody should be inserted, though it should be anonymous. IE exposes
this tbody in the DOM.
// Get the style information from getAttribute
// (IE uses .cssText insted)
style: /red/.test( a.getAttribute("style") ),

The problem here is using getAttribute.
They just mark land mines as they step on them. Their map(s) would
have been out of date in the year 2000.



// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
hrefNormalized: a.getAttribute("href") === "/a",


Land mine #2. That should have been enough to spot the well-known
pattern.

The comment is wrong. The problem is not with href, it is with IE's
getAttribute (as above).

The href property should be a URI[1].
// Make sure that element opacity exists
// (IE uses filter instead)
opacity: a.style.opacity === "0.5",


Browser sniffing by object inference. Implies DirectX filters exist
for UA's without opacity style support. No wonder they keep lopping
off the old browsers from the supported list. Pretty pitiful to let
them crash and burn on something as simple as opacity.


// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
cssFloat: !!a.style.cssFloat,


Also a bad inference.

Only because the HTML in the beginning is invalid.

The value of a style property should be a string value. If the
expectation is that the value is "left", converting that to a boolean
should result in |true|.

But it might be also more explicit if the code read:-

if(a.style.cssFloat == "left")

I would favor the in operator.

'cssFloat' in root.style.

Or possibly:-

typeof root.style.cssFloat === "string"

If that property is present, I am going to use it.
// Will be defined later
scriptEval: false,
noCloneEvent: true,
boxModel: null
};

script.type = "text/javascript";

// script.canHaveChildren.
try {
script.appendChild( document.createTextNode( "window." + id +
"=1;" )

);


Well, this is no good at all. If there's one thing we've been over a
million times, it is dynamic script injection. I think the discussion
dates back to 2003. The point is to test whether the snippet
executes. Unfortunately, this rendition tests whether a UA can append
a child to a script node. Odd, that it looks a bit like the test in
my library. It's like they copied it but didn't understand what they
were copying.


That is a pretty serious accusation. You ought to post up code from your
library alongside.
} catch(e){}

root.insertBefore( script, root.firstChild );


The root variable may be undefined at this point.

How would it be undefined?

The only problem I have with that code is that it should result in
inserting an element before the head tag. This should result in a dom
heirarchy error[2].

Kangax and others have reported that it "works", but I am still cautious
about that. It seems the standard expects an error to be thrown, though
browsers do not do that.
// Make sure that the execution of code works by injecting a script
// tag with appendChild/createTextNode
// (IE doesn't support this, fails, and uses .text instead)


So they didn't understand what they were supposed to be testing.
Obviously the failure of the first test does not imply the existence
of a text property. Certainly it does not imply that it will do
anything if set.

There's a third branch too (innerText IIRC.)


if ( window[ id ] ) {
jQuery.support.scriptEval = true;
delete window[ id ];
}


The usual bad assumptions regarding the window object.

That should work, but would result in unsupported operation in IE (bug).

I wonder why they did not just add a property to the jQuery.support object?

document.createTextNode( "jQuery.support.scriptEval=true;");
});

Assuming the fireEvent test completes, it looks like "Drip" is
mistaken. Hard to say for sure though (that is what Task Manager is
for.) Also hard to imagine why this line is missing:


root = div = script = null;

I do this a lot in feature tests. Nullify stuff you don't need in a
closure.

There is no marker in the language for which variables you want in scope
and which variables are just temporal. So, you just have to remember to
set them to null.
})();


Why these support.* properties are exposed for others to infer God
knows what from is anyone's guess.

Ask on the jQuery list.

[...]

[1]http://www.w3.org/TR/html401/struct/links.html#adef-href
[2]http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-952280727
 
D

David Mark

David said:
On 17 Apr 2009 09:52:41 GMT, Gregor Kofler 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.

When would |root| not be defined?

When it isn't. This script is typically deployed on the public
Internet. Doesn't matter what they claim to "support."
The style property should available in the browsers they support. Why
wouldn't it?

Same as above. It is just sloppy.
Whatever they are expecting that invalid HTML to do, and how that should
be represented in the browser would not be a reasonable expectation.

Instead, they should use valid HTML and make assertions about the results..




A tbody should be inserted, though it should be anonymous. IE exposes
this tbody in the DOM.




The problem here is using getAttribute.

As it has been since 1999. (!)
They just mark land mines as they step on them.  Their map(s) would
have been out of date in the year 2000.
           // Make sure that URLs aren't manipulated
           // (IE normalizes it by default)
           hrefNormalized: a.getAttribute("href") ==="/a",
Land mine #2.  That should have been enough to spot the well-known
pattern.

The comment is wrong. The problem is not with href, it is with IE's
getAttribute (as above).
Yep.


The href property should be a URI[1].




           // Make sure that element opacity exists
           // (IE uses filter instead)
           opacity: a.style.opacity === "0.5",
Browser sniffing by object inference.  Implies DirectX filters exist
for UA's without opacity style support.  No wonder they keep lopping
off the old browsers from the supported list.  Pretty pitiful to let
them crash and burn on something as simple as opacity.
           // Verify style float existence
           // (IE uses styleFloat instead of cssFloat)
           cssFloat: !!a.style.cssFloat,
Also a bad inference.

Only because the HTML in the beginning is invalid.

No. See the code that uses this flag.
The value of a style property should be a string value. If the
expectation is that the value is "left", converting that to a boolean
should result in |true|.

But it might be also more explicit if the code read:-

if(a.style.cssFloat == "left")

I would favor the in operator.

'cssFloat' in root.style.

Or possibly:-

typeof root.style.cssFloat === "string"

There you go, but you don't infer that "styleFloat" exists.
If that property is present, I am going to use it.





// script.canHaveChildren.

Discussed ad nauseum here since at least 2003.
That is a pretty serious accusation. You ought to post up code from your
library alongside.

We did that last time. You dig it up this time. And how is it a
serious accusation? The jQuery code (as with most freebie scripts) is
obviously pulp and always has been.
How would it be undefined?

When document.documentElement does not exist.
The only problem I have with that code is that it should result in
inserting an element before the head tag. This should result in a dom
heirarchy error[2].

That's a pretty big problem and is easily avoided.
Kangax and others have reported that it "works", but I am still cautious
about that. It seems the standard expects an error to be thrown, though
browsers do not do that.

That we know of. Today. Obviously, pinning *feature testing* on such
observations is madness.
   // Make sure that the execution of code works by injecting a script
   // tag with appendChild/createTextNode
   // (IE doesn't support this, fails, and uses .text instead)
So they didn't understand what they were supposed to be testing.
Obviously the failure of the first test does not imply the existence
of a text property.  Certainly it does not imply that it will do
anything if set.
There's a third branch too (innerText IIRC.)
   if ( window[ id ] ) {
           jQuery.support.scriptEval = true;
           delete window[ id ];
   }
The usual bad assumptions regarding the window object.

That should work, but would result in unsupported operation in IE (bug).

I wonder why they did not just add a property to the jQuery.support object?

Because they are stupid. It's a recurring theme.
document.createTextNode( "jQuery.support.scriptEval=true;");






I do this a lot in feature tests. Nullify stuff you don't need in a
closure.

Once again, there are two camps. Resig and co. can't figure out what
to do with the references once the temporary elements have been
removed. Everyone else sets them to null, circular references or not.
There is no marker in the language for which variables you want in scope
and which variables are just temporal. So, you just have to remember to
set them to null.

Yes, as with any programming, you must pay attention your logic.
Ask on the jQuery list.

Their reasoning on that is of no interest. I would guess poor
planning and a rush to replace the UA sniffing object with...
something. Of course, the "browser" object is still in there and
still in use, but it is now officially "deprecated." In 2009.
 
G

Garrett Smith

David said:
David said:
On Apr 18, 3:23 am, Nisse Engström <[email protected]>
wrote:
On 17 Apr 2009 09:52:41 GMT, Gregor Kofler 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.
When would |root| not be defined?

When it isn't. This script is typically deployed on the public
Internet. Doesn't matter what they claim to "support."
The style property should available in the browsers they support. Why
wouldn't it?

Same as above. It is just sloppy.

Is there a case where it would fail? Can you explain where
documentElement would be unavailable?

The code should be running in an HTML document.

You make some assumptions, right? You assume the script runs in a
browser, and that there is a window. OK so far? There is a document
object, primitive values, nested functions, try/catch are all supported.
There is a documentElement property on document -- you say no?

[...]
No. See the code that uses this flag.

Looks like trying to type convert "left" or undefined to boolean. What
am I missing?
There you go, but you don't infer that "styleFloat" exists.

And if there is another property that should be used instead, it is
unknown to all of us.

So, the fallback would be (correct me if I am wrong):

var floatProp = "cssFloat",
styleFloat = "styleFloat";

var floatProp = typeof style[floatProp] === "string" ? cssFloat :
typeof style[styleFloat] === "string" ? styleFloat : undefined;

Assigning el[cssFloat] = "left", where there was a hypothetical browser
that had cssFloat === undefined, would result in an expando of
"undefined" instead of an expando of "styleFloat":-

el["undefined"] = "left"

At this point, it doesn't matter what the expando's name is.

So that code could be shortened to:-

var cssFloat = "cssFloat",
styleFloat = "styleFloat";

cssFloat = typeof style[cssFloat] === "string" ? cssFloat : styleFloat;
We did that last time. You dig it up this time. And how is it a
serious accusation? The jQuery code (as with most freebie scripts) is
obviously pulp and always has been.

What "last time"? The time you said jQuery copied from your positioning
function? I did not see code on that thread.


Finding an element's position is insanely hard. Unless your PPK, of
course:
http://www.quirksmode.org/blog/archives/2008/02/the_cssom_view.html#link5
and of course this was picked up by Ajaxian. And of course the cssom
draft, replete with its glaring flaws, is going forward with those flaws.

I just got email with a feature test that I think my getOffsetCoords
function omits.
When document.documentElement does not exist.

I don't have that problem. If there is a time when it might occur, I'd
like to know about it.
The only problem I have with that code is that it should result in
inserting an element before the head tag. This should result in a dom
heirarchy error[2].

That's a pretty big problem and is easily avoided.
Kangax and others have reported that it "works", but I am still cautious
about that. It seems the standard expects an error to be thrown, though
browsers do not do that.

That we know of. Today. Obviously, pinning *feature testing* on such
observations is madness.

That script that expects browsers to be non-standard. If a browser
follows the standard, it would cause the script to malfunction.

Browsers do throw HIERARCHY_REQUEST_ERR exception when appending to
document.

http://groups.google.com/group/comp.lang.javascript/msg/67bce9d0f3cbd37b?dmode=source

Appending to documentElement is risky. It might work in a lot of
browsers, but it should be expected to result in an error. I don't use
XHTML dom documents (use html instead), but I would not be surprised if
a HIERARCHY_REQUEST_ERR were raised in some of these same browsers where
it works for html dom.

Were innerHTML in XHTML is supported a script setting innerHTML of a DIV
to have a LINK might also have a HIERARCHY_REQUEST_ERR, or the browser
could drop the LINK. Boris has informed on WHATWG that LINK in BODY is
treated differently in Gecko. There is no standard way that an
implementation should handle that.

A script's proper functioning should not depend on undefined behavior.

[...]
Once again, there are two camps. Resig and co. can't figure out what
to do with the references once the temporary elements have been
removed. Everyone else sets them to null, circular references or not.

How about this: Remove the node from the dom, and then, after that, set
the style.display = "none".

j/k.
Yes, as with any programming, you must pay attention your logic.

Java has featured final variables being accessible from an anonymous
inner class since 1.2, I think.

To use an outer variable in an anonymous inner class in Java, it can be
done by declaring the variable as final.

Javascript has no such feature.
Their reasoning on that is of no interest. I would guess poor
planning and a rush to replace the UA sniffing object with...
something. Of course, the "browser" object is still in there and
still in use, but it is now officially "deprecated." In 2009.

I would have guessed that the support.* properties were exposed so that
plugins could know about what is supported.

Then again, I don't know what their reasoning because I didn't ask.

Garrett
 
D

David Mark

David said:
David Mark wrote:
On Apr 18, 3:23 am, Nisse Engström <[email protected]>
wrote:
On 17 Apr 2009 09:52:41 GMT, Gregor Kofler 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.
When would |root| not be defined?
When it isn't.  This script is typically deployed on the public
Internet.  Doesn't matter what they claim to "support."
Same as above.  It is just sloppy.

Is there a case where it would fail? Can you explain where
documentElement would be unavailable?

In browsers that don't feature that property.
The code should be running in an HTML document.

What does that mean?
You make some assumptions, right?

Very few. You know what they lead to.
You assume the script runs in a
browser,
Usually.

and that there is a window. OK so far? There is a document
object, primitive values, nested functions, try/catch are all supported.

Oops, you lost me on that last one.
  There is a documentElement property on document -- you say no?
Yes.
[...]
           // Verify style float existence
           // (IE uses styleFloat instead of cssFloat)
           cssFloat: !!a.style.cssFloat,
Also a bad inference.
Only because the HTML in the beginning is invalid.
No.  See the code that uses this flag.

Looks like trying to type convert "left" or undefined to boolean. What
am I missing?

Just a bad inference in later code. The absence of cssFloat does not
imply the presence of styleFloat. This is a sneaky way of sniffing
for IE without the UA string. They do that a lot.
And if there is another property that should be used instead, it is
unknown to all of us.

That is a proprietary IE property (see above.)
So, the fallback would be (correct me if I am wrong):

var floatProp = "cssFloat",
     styleFloat = "styleFloat";

var floatProp = typeof style[floatProp] === "string" ? cssFloat :
   typeof style[styleFloat] === "string" ? styleFloat : undefined;

Something like that. You are dissecting the wrong problem though. It
is just a minor example of a recurring object inference theme. This
particular oversight is not the end of the world (at least not in a
handful of modern browsers.)
Assigning el[cssFloat] = "left", where there was a hypothetical browser
that had cssFloat === undefined, would result in an expando of
"undefined" instead of an expando of "styleFloat":-

Certainly not what I would do.
el["undefined"] = "left"

This is your code.
At this point, it doesn't matter what the expando's name is.

I don't create expandos when setting styles.
So that code could be shortened to:-

var cssFloat = "cssFloat",
     styleFloat = "styleFloat";

cssFloat = typeof style[cssFloat] === "string" ? cssFloat : styleFloat;

We are getting off the path with this float stuff. That was the least
of the problems noted.
What "last time"? The time you said jQuery copied from your positioning
function? I did not see code on that thread.

Then you left before it concluded.
Finding an element's position is insanely hard. Unless your PPK, of
course:http://www.quirksmode.org/blog/archives/2008/02/the_cssom_view.html#l...

Is that meant to be a joke?
and of course this was picked up by Ajaxian. And of course the cssom
draft, replete with its glaring flaws, is going forward with those flaws.

Of course.
I just got email with a feature test that I think my getOffsetCoords
function omits.

In general, nobody needs or should want such a function.
I don't have that problem. If there is a time when it might occur, I'd
like to know about it.

What are you talking about? There is an obvious gap in the logic.
And you don't need to know if that object does not exist (your script
will have bailed out safely.) Furthermore, what makes you think that
some little old lady in Pasadena using an ancient browser is going to
report the exception to you? What would you do if she did? Fix the
ineffectual logic?
The only problem I have with that code is that it should result in
inserting an element before the head tag. This should result in a dom
heirarchy error[2].
That's a pretty big problem and is easily avoided.
That we know of.  Today.  Obviously, pinning *feature testing* on such
observations is madness.

That script that expects browsers to be non-standard. If a browser
follows the standard, it would cause the script to malfunction.

Exactly. Pure madness.
Browsers do throw HIERARCHY_REQUEST_ERR exception when appending to
document.

http://groups.google.com/group/comp.lang.javascript/msg/67bce9d0f3cbd...

Appending to documentElement is risky. It might work in a lot of
browsers, but it should be expected to result in an error. I don't use
XHTML dom documents (use html instead), but I would not be surprised if
a HIERARCHY_REQUEST_ERR were raised in some of these same browsers where
it works for html dom.

I have little doubt that is the case. Ironic that most of these
scripts are deployed with transitional XHTML. Of course, such sites
are designed with error correction in mind (also madness.)
Were innerHTML in XHTML is supported a script setting innerHTML of a DIV

Virtually nowhere.
to have a LINK might also have a HIERARCHY_REQUEST_ERR, or the browser
could drop the LINK. Boris has informed on WHATWG that LINK in BODY is
treated differently in Gecko. There is no standard way that an
implementation should handle that.

The property is not standard to begin with. Therefore hinging the
entire "feature testing" process on it is the final lunatic touch that
reveals the script to be the product of a delusional mind.
A script's proper functioning should not depend on undefined behavior.

Agreed. And virtually everything in jQuery relies on such hacks.
That's why they keep rewriting it and losing the next to last released
versions of the major browsers.
[...]


Once again, there are two camps.  Resig and co. can't figure out what
to do with the references once the temporary elements have been
removed.  Everyone else sets them to null, circular references or not..

How about this: Remove the node from the dom, and then, after that, set
the style.display = "none".

j/k.

Glad to see that. I was starting to wonder.
Java has featured final variables being accessible from an anonymous
inner class since 1.2, I think.

To use an outer variable in an anonymous inner class in Java, it can be
done by declaring the variable as final.

Javascript has no such feature.
Okay.



I would have guessed that the support.* properties were exposed so that
plugins could know about what is supported.

And this seems sane to you? What in God's name can they infer from
those "tests?" What will happen when the meaning of the flag(s)
change in the next jQuery version?
Then again, I don't know what their reasoning because I didn't ask.

Prudent.
 
D

David Mark

Garrett said:
David Mark wrote: [...]
        // Verify style float existence
        // (IE uses styleFloat instead of cssFloat)
        cssFloat: !!a.style.cssFloat,
Also a bad inference.
Only because the HTML in the beginning is invalid.
The value of a style property should be a string value. If the
expectation is that the value is "left", converting that to a boolean
should result in |true|.
But it might be also more explicit if the code read:-
if(a.style.cssFloat == "left")
I would favor the in operator.
'cssFloat' in root.style.
Or possibly:-
typeof root.style.cssFloat === "string"

I only recently found out (while exercising in removing sniffing from
Prototype.js) that there's at least one case when `typeof` fails but
`in` works. Safari 2.x would simply crash entirely when an arbitrary
property was being accessed on a nodelist. Surprisingly, even `typeof`
kept crashing it,

In all of Safari 2.x, using the typeof operator on any nodelist
property will throw an exception? Sounds more like a bad build.
but `in` worked just fine.

The - in - operator doesn't tell you anything except that the property
is there. What properties of nodelists do you need to detect in this
way?
 
D

David Mark

David said:
Garrett Smith wrote:
David Mark wrote:
[...]
        // Verify style float existence
        // (IE uses styleFloat instead of cssFloat)
        cssFloat: !!a.style.cssFloat,
Also a bad inference.
Only because the HTML in the beginning is invalid.
The value of a style property should be a string value. If the
expectation is that the value is "left", converting that to a boolean
should result in |true|.
But it might be also more explicit if the code read:-
if(a.style.cssFloat == "left")
I would favor the in operator.
'cssFloat' in root.style.
Or possibly:-
typeof root.style.cssFloat === "string"
I only recently found out (while exercising in removing sniffing from
Prototype.js) that there's at least one case when `typeof` fails but
`in` works. Safari 2.x would simply crash entirely when an arbitrary
property was being accessed on a nodelist. Surprisingly, even `typeof`
kept crashing it,
In all of Safari 2.x, using the typeof operator on any nodelist
property will throw an exception?  Sounds more like a bad build.

Sorry, I should have been more explicit.

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".

Here's a minimal test case which fails for me in Safari 2.0.4 (last
version from 2.x series, AFAIK) on Mac OSX 10.5.6:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8">
     <title></title>
   </head>
   <body>
     <script type="text/javascript">
       var el = document.createElement('div');
       el.appendChild(document.createTextNode('x'));
       document.write(typeof el.childNodes.foo);
     </script>
   </body>
</html>

Once you open this document, Safari should crash.


The - in - operator doesn't tell you anything except that the property
is there.  What properties of nodelists do you need to detect in this
way?

A `toArray` function delegates execution to an object that's being
passed if that object happens to implement `toArray` method itself. In
other words, something along the lines of:

function toArray(o) {
   if (!o) return [];
   if (typeof o.toArray == 'function') return o.toArray();
   var length = o.length || 0, results = new Array(length);
   while (length--) {
     results[length] = o[length];
   }
   return results;

}

I ended up making "toArray" check use `in`:

...
if ('toArray' in Object(o)) return o.toArray();
...

(probably should have added `typeof` "function" too)

The would just remove the line (and the one before it) and update the
documentation. This function is clearly aimed at host objects (like
nodelists) and unless one is doing something very silly, there is no
need to sniff out a "toArray" property on those.

But, I assume this is for Prototype (why?), so you are hemmed in by
the expectations of their ever-dwindling user base. Wait a few months
and you can do anything you want to that script (nobody will notice.)
 
D

David Mark

David said:
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;

Yes, indeed. I suppose even if we take "ancient" browsers out of
consideration, there's a whole slew of mobile clients with unknown
capabilities.
Exactly.
The former isn't even appropriate for what it is used for:
root.insertBefore( script, root.firstChild );
Presumably, the first child of the HTML element is the HEAD element.
You don't insert scripts *before* the head.

I experimented with inserting an element right into a
`document.documentElement` (at the time when `body` might not be
available) and had no problems in any browser I tried it with. The idea
was to create an INPUT element, attach an "onclick" event listener to
it, insert it into a document and call its `click` method. An event
listener would then analyze an event object (e.g. testing for types of
`preventDefault`, `stopPropagation`, etc.) and build an event system
accordingly.

Something like:

var HAS_PREVENTDEFAULT, HAS_RETURNVALUE;
(function () {
   if (document.createElement) {
     var i = document.createElement("input"),
         root = document.documentElement;
     if (i && i.click && root && root.appendChild && root.removeChild) {
       i.type = "checkbox";
       i.onclick = function(e) {
         e = e || window.event;
         HAS_PREVENTDEFAULT = typeof e.preventDefault == "function";
         HAS_RETURNVALUE = "returnValue" in e;
       };
       root.appendChild(i);
       i.click();
       root.removeChild(i);
       i.onclick = i = null;
     }
   }

})();

var preventDefault = (function(){
   if (HAS_PREVENTDEFAULT) {
     return function(e){
       e.preventDefault();
     }
   }
   else if (HAS_RETURNVALUE) {
     return function(e){
       e = e || window.event;
       e.returnValue = false;
     }
   }

})();

You could avoid all of this with the lazy pattern.

http://www.google.com/url?sa=U&star...zKDPBQ&usg=AFQjCNGXENG61wk-VnfvNiPo7O-uv9spfw

I wouldn't worry about it as an extra test on canceling a default
action isn't going to affect the performance of a typical application.
I'm not sure if it's a "healthy" type of inference. Are there any
implications I'm not seeing?

Here's the thing. You just can't do this test until the body is
ready. Your end-around has been noted to work in a few browsers, only
because those browsers are not following standards. I wouldn't bet
that all agents to now deviate from the standard in this way or that
future agents will continue the trend. This is why scripts like
Prototype must be prodded constantly, yet never seem to progress
anywhere.
[...]
That is the only (sane) way to maintain dependencies between a cross-
browser API and its calling apps.  The calling apps know nothing about
the myriad possible DOM, style, etc. combinations; rather, their
gateways detect the higher-level methods of the API.  I've been doing
it like that for ten years and that's why I have code around from
before the turn of the century that still works in the latest
browsers.

I noticed that you test low-level methods (in higher ones) with `typeof`
"undefined". Isn't it redundant? It seems that a plain type conversion
would suffice:

Very good eye. But in fact, where such logic exists in my library, it
is not redundant. As the script is built by a script on the server,
there are cases where modules need to use the typeof operator to
detect methods in other modules, which may not be included in the
build. A good example is the OOP layer, which has no defined
dependencies, yet sniffs out nearly every method in the API. Granted,
if the server side script were a little smarter, it could skip the
unneeded bits of that module. That's an extreme case. Other cases
are for modules that are optionally enhanced by others. On partial
builds, the test pages talk you through such possibilities.

All just a curiosity at this point. Don't expect I will update that
site again.
Instead of:

...
if (typeof getEBI != 'undefined' &&
     typeof getEBTN != 'undefined' &&
     typeof getChildren != 'undefined' &&
     typeof getAttribute != 'undefined' &&
     (global.document.expando ||
     typeof global.document.expando == 'undefined'))
...

Shouldn't it be safe to just do:

...
if (getEBI &&
     getEBTN &&
     getChildren &&
     getAttribute &&
     (global.document.expando ||
     typeof global.document.expando == 'undefined'))
...

That looks like the gateway to the query module. You may have spotted
an inconsistency there as I believe those are all DOM module methods,
which is required by the query module. In that case, the latter
example is appropriate.
Since you're the one defining those variables (and not host
environment), the only possible values they could have are either
`undefined` or a reference to some Function object (if certain tests
were successful).
Correct.


Am I missing something?

Just the server side stuff.
 
D

David Mark

David said:
[...]
I ended up making "toArray" check use `in`:
...
if ('toArray' in Object(o)) return o.toArray();
...
(probably should have added `typeof` "function" too)
The would just remove the line (and the one before it) and update the
documentation.  This function is clearly aimed at host objects (like
nodelists) and unless one is doing something very silly, there is no
need to sniff out a "toArray" property on those.

It's not possible to just remove stuff and document it as such :) Back
compatibility should not be broken so carelessly.

I didn't say do it carelessly.
Another possibility is to check "toArray" only when an object is a
nodelist, but since determining whether something is a nodelist is
rather expensive task for such a low level method, it would only need to
be done in a separate branch of `toArray` (i.e. redefining a function).
The problem is that there's obviously no way to test whether a browser
will crash. The way it was done before was to use
`Prototype.Browser.WebKit` sniff to fork for this behavior. This is of
course retarded and is exactly why I tried to remove the sniff.
Right.


You'll be surprised. Prototype's user base is far from millions of
jQuery users, but there's still a lot. There are also legacy
applications which can't afford to transition to another library or
remove a library altogether.

I was exaggerating. The legacy apps will dry up and blow away as they
were built on a browser sniffing script.
 

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,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top