document.layers & Mozilla

D

David List

I'm having a problem using different properties of the document object
in the example javascripts in my textbook with browsers that identify
themselves as using the Mozilla engine. One example of these
problems is using document.layers. I have Google'd for examples of how
to use the document object specifically with Mozilla, but I cannot
find anything that explains why my problems occur. Could anyone here
see through the included example and tell me if there is anything
absolutely wrong with this?

It seems to me that the examples in my textbook simplify browser
identification to the point where it doesn't work. Am I right in this?

----------example----------
<html>
<head>
<meta name="keywords" content="">
<meta name="description" content="">
<title>Test-titel</title>
<link rel="stylesheet" href="./style.css">
<script language="javascript">
<!--
var active = 0;
var browser = null;
function Init()
{
browser = new BrowserObj();
}
function BrowserObj()
{
this.navigator = null;
this.explorer = null;
this.other = null;
if((navigator.appName.toLowerCase()).
indexOf("netscape") >= 0)
this.navigator = 1;
else
if((navigator.appName.toLowerCase()).indexOf("explorer") >= 0)
this.explorer = 1;
else
this.other = 1;
this.major = parseInt(navigator.appVersion);
this.minor = parseFloat(navigator.appVersion);
}
function ChangeLayer(now)
{
if(browser.navigator != null)
{
document.layers["content" + active].visibility = "hide";
document.layers["content" + now].visibility = "show";
}
else
{
var current = document.all("content" + active).style;
var next = document.all("content" + now).style;
current.visibility = "hidden";
next.visibility = "visible";
active = now;
}
}
// -->
</script>
</head>
<body onLoad="Init()">
<div id="menua" style="top: 5; left: 5; visibility: visible;
position: absolute; z-index: 5;">
<p class="SWITCH">
<a href="#" onClick="ChangeLayer(0)">One</a>
<a href="#" onClick="ChangeLayer(1)">Two</a>
<a href="#" onClick="ChangeLayer(2)">Three</a>
</p>
</div>
<div id="content0" style="top: 40; left: 0; visibility: visible;
position: absolute;">
<h1>A test header</h1>
<p>Here is some text</p>
</div>
<div id="content1" style="top: 40; left: 0; visibility: visible;
position: absolute;">
<h1>One more test header</h1>
<p>Some more test</p>
</div>
<div id="content2" style="top: 40; left: 0; visibility: visible;
position: absolute;">
<h1>Yet one more test header</h1>
<p>Yet more text</p>
</div>
</body>
</html>
----------example----------
 
D

David Dorward

David List wrote:

<snip> Browser detection stuff </snip>

Don't try to work out what browser the visitor is using, its a moving
target. Use object detection instead:

http://www.xs4all.nl/~ppk/js/support.html
function ChangeLayer(now)
{
if(browser.navigator != null)
{
document.layers["content" + active].visibility = "hide";
document.layers["content" + now].visibility = "show";

if (document.layers) - but check for this _last_, its least likely to be
used.

else if (document.all) - but check for this second last. IE 4 is the only
browser that supports this but doesn't support DOM.

Start with the standards method:

if (document.getElementById) {
document.getElementById('id_of_element').....
}
<div id="menua" style="top: 5; left: 5; visibility: visible;

This is invalid CSS. Non-zero lengths require units.
<a href="#" onClick="ChangeLayer(0)">One</a>

Yuck. Why are you linking to the top of the page?

<a href="#content0" onclick="ChangeLayer(0)">One</a> would make more sense.
 
D

David List

David List wrote:

<snip> Browser detection stuff </snip>

Don't try to work out what browser the visitor is using, its a moving
target. Use object detection instead:

http://www.xs4all.nl/~ppk/js/support.html

I'll look into that.
function ChangeLayer(now)
{
if(browser.navigator != null)
{
document.layers["content" + active].visibility = "hide";
document.layers["content" + now].visibility = "show";

if (document.layers) - but check for this _last_, its least likely to be
used.
OK.

else if (document.all) - but check for this second last. IE 4 is the only
browser that supports this but doesn't support DOM.

Start with the standards method:

if (document.getElementById) {
document.getElementById('id_of_element').....

Will try that out.
}


This is invalid CSS. Non-zero lengths require units.

OK, I'll remember that.
Yuck. Why are you linking to the top of the page?

<a href="#content0" onclick="ChangeLayer(0)">One</a> would make more sense.

Just following the examples in my textbook into I get this stuff into
my fingers. Do you know of a reference that could explain to me what
'#content0' would mean in this context? I'm not sure whether it's
decided by the HTML or the javascript. The author of my textbook touts
using '#' as very useful, when you don't want to link outside of the
current document.

Thank you for your answer.
 
D

David Dorward

David said:
Just following the examples in my textbook into I get this stuff into
my fingers. Do you know of a reference that could explain to me what
'#content0' would mean in this context? I'm not sure whether it's
decided by the HTML or the javascript.

Its the HTML. href="#foo" is a reference to the element with id="foo" (or in
old style <a name="foo">) in the current document. Browsers will scroll
down to the element when told to go to http://example.com/blah/#foo.

If you had a browser which didn't handle the JavaScript, then the link would
still do something useful when followed.
The author of my textbook touts using '#' as very useful, when you don't
want to link outside of the current document.

The author of your textbook should be taken outside and shot[1]. If you want
a clickable element that only does something in the presence of JavaScript
then it shouldn't be a link.

[1] Both for this, but also for suggesting that you try to guess what
objects are available to JavaScript based on the user agent string. Oh, and
for the invalid CSS. And the invalid HTML (and use of obsolete parts of
HTML). And for needlessly using absolute positioning. And for not
mentioning DOM at all.
 
R

Richard Cornford

David List said:
I'm having a problem using different properties of the document
object in the example javascripts in my textbook with browsers
that identify themselves as using the Mozilla engine.

The majority of books on browser scripting are out of date (including
this one by the look of it), and browsers cannot be trusted to identify
themselves at all. All are capable of lying and many do so as a matter
of course.
One example of these problems is using document.layers.
I have Google'd for examples of how to use the document
object specifically with Mozilla, but I cannot
find anything that explains why my problems occur.

Mozilla based browsers do not have a document.layers collection.
Could anyone here see through the included example and tell me
if there is anything absolutely wrong with this?
OK.

It seems to me that the examples in my textbook simplify browser
identification to the point where it doesn't work. Am I right
in this?

Browser identification does not ever work, it is impossible. The whole
idea has been dropped in favour of feature/object detection related
specifically to the objects and features of the browser that the script
is interested in using (well, at least by everyone who knows what they
are doing). That approach achieves functionality up to the browser's
ability to support the script without ever needing to know any specifics
about which browser is executing the script.
----------example----------
<html>
<head>
<meta name="keywords" content="">
<meta name="description" content="">

Empty meta tags? We didn't need to see those. Newsgroup posts should be
edited down to the minimum (valid code) needed to explain the problem.
<title>Test-titel</title>
<link rel="stylesheet" href="./style.css">
<script language="javascript">

The language attribute has been deprecated in favour of the type
attribute (which is both backward and forward compatible):-


This "hide from older browsers" stuff is no longer needed. The browsers
that were young when it was introduced are now so old themselves that
they have all gone out of use.
var active = 0;
var browser = null;
function Init()
{
browser = new BrowserObj();
}
function BrowserObj()
{
this.navigator = null;
this.explorer = null;
this.other = null;
if((navigator.appName.toLowerCase()).
indexOf("netscape") >= 0)
this.navigator = 1;

These values (this.navigator, explorer and other) look like they are
boolean so assigning numeric values seems inappropriate. As the - if -
test expressions resolve to boolean values it would probably be more
efficient to assign the results of the resolved expressions to the
object properties directly:-

this.navigator=(navigator.appName.toLowerCase().indexOf("netscape")>=0)
else
if((navigator.appName.toLowerCase()).indexOf("explorer") >= 0)
this.explorer = 1;
else
this.other = 1;
this.major = parseInt(navigator.appVersion);
this.minor = parseFloat(navigator.appVersion);
}

Browser detecting is _absolutely_ wrong. Browser detecting based on the
userAgent and appVersion (and/or appName) is utterly useless, browser's
lye habitually so nothing can be learnt by asking these questions. Chuck
it all out!
function ChangeLayer(now)
{
if(browser.navigator != null)
{

This is where browser detecting demonstrates its inferiority to
feature/object detecting. This branch wants to use the -
document.layers - collection. There is no relationship between a browser
having the substring "netscape" in its - navigator.appName - property
and its support for a - document.layers - collection, but there is a
direct relationship between a browser's support for a -
doucment.layers - collection and that browser having
a -document.layers - collection. So that is what should be tested prior
to the use of that object (though not necessarily prior to each and
every invocation). The test should be:-

if(document.layers){
. . . // use the layers collection, it exists!
}
document.layers["content" + active].visibility = "hide";
document.layers["content" + now].visibility = "show";
}
else
{
var current = document.all("content" + active).style;

IE browsers are very tolerant of errors, second guessing the author and
letting them fall into bad habits that they will have to unlearn when
exposed to any other browser. One of those bad habits is using
parentheses to access object properties. The - document.all - collection
is an object (and it is supported on a very large number of current
browsers), so property access syntax is to use square brackets. Doing
that will make this code functional on any browser with a -
document.all - collection instead of just the ones that reproduce IE's
error correcting behaviour:-

var current = document.all["content" + active].style;
var next = document.all("content" + now).style;
current.visibility = "hidden";
next.visibility = "visible";
active = now;
}
}
// -->
</script>
</head>
<body onLoad="Init()">
<div id="menua" style="top: 5; left: 5; visibility: visible;
position: absolute; z-index: 5;">

O.T. but CSS property values that represent lengths/dimensions are
required to specify the unit (px, em, en, ex, etc.). It is always a good
idea to validate HTML and CSS as there are no standards for the handling
of invalid code so only valid code can reasonably be expected to produce
a consistent DOM for JavaScript manipulation.
<p class="SWITCH">
<a href="#" onClick="ChangeLayer(0)">One</a>
<a href="#" onClick="ChangeLayer(1)">Two</a>
<a href="#" onClick="ChangeLayer(2)">Three</a>
<snip>

Onclick handlers are allowed to cancel the navigation specified in the
HREF attribute by returning false. If the intention of the onclick code
is only to execute a function then it should cancel the navigation (even
if it is only to the top of the current page as in "#").

For contrast this is an alternative version of your page. Note that the
browser detecting is gone, this page is not interested in the browser at
all only its features. It will also work with Mozilla based browsers
because it branches to use the W3C Core DOM Level 1 -
document.getelementById - method to look up the reference to the DIVs,
and uses that method in preference to all others because it is common to
the largest number of current browsers including IE 5.0+.

<html>
<head>
<title>Test-titel</title>
<link rel="stylesheet" href="./style.css">
<script type="text/javascript">

var active = 0;

function getStyleObj(id){
var obj = null;
if(document.getElementById){
obj = document.getElementById(id);
}else if(document.all){
obj = document.all[id];
}else if(document.layers){
obj = document.layers[id];
}
return (obj && obj.style) || obj;
}

function ChangeLayer(now){
var current = getStyleObj("content" + active);
var next = getStyleObj("content" + now);
if(current && next){
current.visibility = "hidden";
next.visibility = "visible";
active = now;
}
return false;
}

</script>
</head>
<body>
<div id="menua"
style="top:5px;left:5px;visibility:visible;position:absolute">
<p class="SWITCH">
<a href="#" onClick="return ChangeLayer(0)">One</a>
<a href="#" onClick="return ChangeLayer(1)">Two</a>
<a href="#" onClick="return ChangeLayer(2)">Three</a>
</p>
</div>
<div id="content0"
style="top:40px;left:0px;visibility:hidden;position:absolute;">
<h1>A test header</h1>
<p>Here is some text</p>
</div>
<div id="content1"
style="top:40px;left:0px;visibility:hidden;position:absolute;">
<h1>One more test header</h1>
<p>Some more test</p>
</div>
<div id="content2"
style="top:40px;left:0px;visibility:hidden;position:absolute;">
<h1>Yet one more test header</h1>
<p>Yet more text</p>
</div>
</body>
</html>

Richard.
 
D

David List

The majority of books on browser scripting are out of date (including
this one by the look of it), and browsers cannot be trusted to identify
themselves at all. All are capable of lying and many do so as a matter
of course.



Mozilla based browsers do not have a document.layers collection.

I wasn't even able to find out that much. It may be me...
Browser identification does not ever work, it is impossible. The whole
idea has been dropped in favour of feature/object detection related
specifically to the objects and features of the browser that the script
is interested in using (well, at least by everyone who knows what they
are doing). That approach achieves functionality up to the browser's
ability to support the script without ever needing to know any specifics
about which browser is executing the script.


Empty meta tags? We didn't need to see those. Newsgroup posts should be
edited down to the minimum (valid code) needed to explain the
problem.
Sorry.


The language attribute has been deprecated in favour of the type
attribute (which is both backward and forward compatible):-

<script type="text/javascript">

OK. I'll remember that.
This "hide from older browsers" stuff is no longer needed. The browsers
that were young when it was introduced are now so old themselves that
they have all gone out of use.

I see.
These values (this.navigator, explorer and other) look like they are
boolean so assigning numeric values seems inappropriate. As the - if -
test expressions resolve to boolean values it would probably be more
efficient to assign the results of the resolved expressions to the
object properties directly:-

this.navigator=(navigator.appName.toLowerCase().indexOf("netscape")>=0)

Of course :)
Browser detecting is _absolutely_ wrong. Browser detecting based on the
userAgent and appVersion (and/or appName) is utterly useless, browser's
lye habitually so nothing can be learnt by asking these questions. Chuck
it all out!


This is where browser detecting demonstrates its inferiority to
feature/object detecting. This branch wants to use the -
document.layers - collection. There is no relationship between a browser
having the substring "netscape" in its - navigator.appName - property
and its support for a - document.layers - collection, but there is a
direct relationship between a browser's support for a -
doucment.layers - collection and that browser having
a -document.layers - collection. So that is what should be tested prior
to the use of that object (though not necessarily prior to each and
every invocation). The test should be:-

if(document.layers){
. . . // use the layers collection, it exists!
}

It seems to me both from this and from the other David's answer to my
OP that you can test for a method's existence in an object (or for the
document.layers["content" + active].visibility = "hide";
document.layers["content" + now].visibility = "show";
}
else
{
var current = document.all("content" + active).style;

IE browsers are very tolerant of errors, second guessing the author and
letting them fall into bad habits that they will have to unlearn when
exposed to any other browser. One of those bad habits is using
parentheses to access object properties. The - document.all - collection
is an object (and it is supported on a very large number of current
browsers), so property access syntax is to use square brackets. Doing
that will make this code functional on any browser with a -
document.all - collection instead of just the ones that reproduce IE's
error correcting behaviour:-

var current = document.all["content" + active].style;

Really good to know.
O.T. but CSS property values that represent lengths/dimensions are
required to specify the unit (px, em, en, ex, etc.). It is always a good
idea to validate HTML and CSS as there are no standards for the handling
of invalid code so only valid code can reasonably be expected to produce
a consistent DOM for JavaScript manipulation.
OK.

<snip>

Onclick handlers are allowed to cancel the navigation specified in the
HREF attribute by returning false. If the intention of the onclick code
is only to execute a function then it should cancel the navigation (even
if it is only to the top of the current page as in "#").

Hey, great! I wondered how to avoid that '#' in the address line of
the browser after clicking the link.
For contrast this is an alternative version of your page. Note that the
browser detecting is gone, this page is not interested in the browser at
all only its features. It will also work with Mozilla based browsers
because it branches to use the W3C Core DOM Level 1 -
document.getelementById - method to look up the reference to the DIVs,
and uses that method in preference to all others because it is common to
the largest number of current browsers including IE 5.0+.

Yup, I got that working after the other David had answered my OP.

<snip example with document.getElementById>

Thank you for your answer.
 
R

Richard Cornford

I wasn't even able to find out that much. It may be me...

Mozilla.org has fairly good DOM documentation online. There are links to
various browser's DOM documentation in the group FAQ:-

<URL: http://jibbering.com/faq/ >

It would also be worth getting a copy of the PDF version of the 3rd
edition of the ECMA Script standard.

It seems to me both from this and from the other David's answer
to my OP that you can test for a method's existence in an object
(or for the class?) by getting the boolean value of
<objectname>.<methodname>. Am I right? If I am, does this
also work for data members in the object?
<snip>

"class" isn't a term that is generally meaningful in JavaScript (It can
reasonably be used to describe scripts that mimic, emulate or reproduce
the behaviour of Class in class based languages but doesn't apply to
JavaScript objects in general.) so if you want to use the term you will
have to qualify the context to which you are applying it.

The ECMA Script standard (262) describes two types of property accessor

the dot notation:

MemberExpression.Identifier
CallExpression.Identifier

or the bracket notation:

MemberExpression[ Expression ]
CallExpression[ Expression ]

They are equivalent (except the bracket notation is resolved very
fractionally slower) and are used to refer to the properties of an
object. Those properties may be:-

A reference to an object.
A reference to a function (JavaScript functions are objects).
null.
boolean.
string.
number.
- or -
undefined.

But JavaScript is a loosely typed language so its operators are willing
to (internally) type-convert their operands into a type appropriate to
resolve the expression as required. It is this type converting that is
exploited for much object/feature detecting.

A browser either implements documents.getElementById or it doesn't so
the property accessor will resolve to a reference to a function (a
method of the document object) or it will resolve to undefined. When the
property accessor is provided as the expression for an - if - statement
it must be type-converted to boolean and the ECMA script type converting
rules require that object and functions convert to boolean true and
undefined converts to boolean false. And that allows the test to know
whether the property accessor refers to a function/object that exists
(true result) or is just an undefined property (false result).

Testing the primitive values string, number and boolean is not so easy.
All non-empty strings convert to true, while - '' - converts to false.
The number 0 (+0 and -0, (and NaN to the best of my recollection))
convert to false and other numbers convert to true. So using property
accessors that refer to primitive values in - if - statements will tell
you something about those values but not whether they exist or not.

The best alternative is the use of the - typeof - operator. It returns a
string that is supposed to reflect the type of a something that its
operand refers to. For primitive values it works well and it also
returns the string 'undefined' if the reference is undefined. With DOM
objects and functions it is less useful as implementations are all over
the place in deciding whether various browser features are objects or
functions. That problem is usually handled with tests such as:-

if(typeof document.getElementById != 'undefined'){
... // the function exists!
}

Testing that the object is not undefined instead of trying to find out
if it is an object or a function.

Another problem is that - typeof null == 'object' -.

So, to see if a browser supports the global innerHeight property, which
is numeric and so will type convert to false if it happens to be zero at
the time of the test (not impossible in a web browser):-

if(typeof innerHeight == 'number'){
... //this browser supports innerHeight
}

An appropriate combination of type converted property accessors and -
typeof - tests will tell you 99% of what you need to know about which
features are supported in the browser environment. The rest requires
some inventive thinking. For example, among the various browser versions
support for the - String.replace - method varies. The newer versions
will accept a very useful function reference as their second argument,
the older versions will only accept a string as the second argument.
Fortunately the versions that are expecting a string only do a
type-conversion on the function if one is passed as the second argument
and that can be exploited to verify the level of browser support:-

if("a".replace(/a/, function(){return '';}).length == 0){
... // replace accepts function references
// as its second argument.
}
- if the function argument is not recognised the function, type
converted to a string, is used to replace the "a" in the original string
so the length of the resulting string is non-zero. If the function is
used it replaces the "a" with an empty string, the length is zero.

The important thing is to test for support of the features that you are
going to use before using them and to never make assumptions. The result
is scripts that are in a position to exploit the browser up to its
capabilities and fall-back and cleanly degrade under control on browsers
that do not support their specific requirements. Cleanly degrading to a
workable UI and accessible content is a requirement for all Internet
JavaScript as not all browsers can execute JavaScript and people often
disable it to rid themselves of some of the more annoying things that
JavaScript authors get up to.
Hey, great! I wondered how to avoid that '#' in the address
line of the browser after clicking the link.
<snip>

Do bear in mind what David Dorward said. This is on of the "cleanly
degrading" issues, what will a user without JavaScript make of a link
that navigate to the top of the page when its text is promising some
sort of action? Should it be a link, or maybe a button? Should it be
inserted in the page using a document.write statement as the page loads
so that it is just not there if JavaScript is unavailable (or the
browser does not support the features that the activated function
requires)?

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,777
Messages
2,569,604
Members
45,227
Latest member
Daniella65

Latest Threads

Top