5.6 Detecting Object Support
NN 2, IE 3
5.6.1 Problem
You want scripts to run on all
browsers that support the objects that your scripts address, and to
degrade gracefully in other browsers.
5.6.2 Solution
Surround the script statements that reference potentially
incompatible objects with if statements that test
for the existence of the objects. The objects you test for can be
core JavaScript language objects, as well as DOM objects.
Facilitating this kind of condition testing is the fact that a
reference to a nonexistent object inside an
if condition evaluates to the equivalent of
false. A very common usage of object detection
from earlier scriptable browsers is in scripts that work with
img elements as objects for rollover image swaps
(covered in depth in Chapter 12). Support for the
img element object was very uneven until the
Version 4 browsers. Creating browser version filters for all the
possibilities would have been tedious at best. Instead, all script
statements that referenced img element objects
were wrapped inside an if construction that looks
for the presence of the
document.images array:
function rollover(imgName, imgSrc) {
if (document.images) {
document.images[imgName].src = imgSrc;
}
}
This function is invoked by an onmouseover event
handler associated with a link surrounding an image:
<a href="product.html"
onmouseover="rollover('products', 'images/products_on.gif'); return false"
onmouseout="rollover('products', 'images/products_off.gif'); return false">
<img src="images/products_off.gif" name="products" border="0" alt="Products Page">
</a>
The check for document.images works conveniently
because if a browser recognizes an img element as
a scriptable object, the document object always
has an images[ ] array associated with it. If
there are no images on the page, the array is empty—but it
still exists with length zero. If the browser has no
document.images array, however, the
if condition fails, and no internal statements of
the function execute. Browsers that would otherwise choke on the
invalid reference to the img element object glide
past the offensive statements.
5.6.3 Discussion
Object detection frees you from the tyranny of browser-version
sniffing, but you must also deploy this technique in such a way that
browsers not supporting your desired objects degrade gracefully. This
means that you must anticipate what will happen to a script that runs
in a browser that supports only some, but not all, desired objects.
For example, consider the scenario in which you have a complex
operation running under script control, and execution branches
periodically to other functions to retrieve a calculated value. If
one of those remote functions performs object detection, how well
does your main execution thread respond to the inability of one
remote function to return a suitable value?
The following two functions are written without the benefit of object
detection. After the main function invokes a subroutine function to
calculate the area of all images on the page, the main function
enters the values into a form field:
function getImgAreas( ) {
// initialize return value so we can add to it
var result = 0;
// loop through all img objects on the page
for (var i = 0; i < document.images.length; i++) {
// accumulate image areas
result += (document.images[i].width * document.images[i].height);
}
return result;
}
function reportImageArea( ) {
document.reportForm.imgData.value = getImgAreas( );
}
A browser that does not know about the img element
object would report a script error when executing the
getImgAreas( ) function. Even if the errors were
hidden from view (see Recipe 4.7), the user might expect some
information to appear in the text box, but none would come.
A smarter scripter would recognize that the preceding scripts might
fail in very old browsers, where script errors tend to be rather
invasive. To prevent such errors, the author makes two modifications.
First, the potentially offending script statements in the
getImgAreas( ) function wrap themselves in an
object detection block. Second, the main function intelligently
accommodates the possibility that the getImgAreas(
) function won't be doing any calculations
at all:
function getImgAreas( ) {
var result;
// make sure browser supports img element objects
if (document.images) {
// initialize return value so we can add to it
result = 0;
// loop through all img objects on the page
for (var i = 0; i < document.images.length; i++) {
// accumulate image areas
result += (document.images[i].width * document.images[i].height);
}
}
// returned value is either a number or null
return result;
}
function reportImageArea( ) {
// grab result so we can verify it
var imgArea = getImgAreas( );
var output;
if (imgArea = = null) {
// message for browsers not supporting img object
output = "Unknown";
} else {
output = imgArea;
}
document.reportForm.imgData.value = output;
}
Notice that the main function does not perform any object detection
for the form-related statement at the end. A knowledgeable scripter
(or one with a good DOM reference resource) knows that the syntax
used to reference the form's text field is
completely backward-compatible to the very earliest browsers.
Object detection alone is not always a savior, however. Sometimes you
must also employ property and method detection. For example, in the
preceding subroutine function, there was no compatibility problem
with accessing the height and
width properties of the img
element object, since these properties have been available for this
object since the first implementation of that object in the various
DOMs. But some other properties, such as the alt
property, are not supported in all browsers that support the
img object. If the subroutine function needed the
alt property, further object property detection,
as shown in Recipe 5.7, would be in order.
5.6.4 See Also
Recipe 5.7 to
test for the presence of an object property or method; Recipe 4.6 for special values you can use in condition statements
that evaluate to true and
false.
|