reptile7's JavaScript blog
Thursday, April 16, 2009
The Softly Spoken Magic Spells
Blog Entry #142

To Java or not to Java

If's zonenamesb3c96c19 image map seems out of order, an even stranger block of code sits at the beginning of the first script element in the document head:

<script language=JavaScript name="TimeHREF function def." cyberversion=N1.0><!--
/* We noted in Blog Entry #138 that name was never a valid attribute for the script element; cyberversion was never a valid attribute for the script element either. The source was generated by the Adobe GoLive HTML editor, which is appropriately savaged here by Gadgetopia. */

var JavaOK = 1;

if (navigator.userAgent && navigator.userAgent.indexOf("Mac") >= 0) {
if (navigator.appVersion.indexOf("2.") == -1 && navigator.appVersion.indexOf("3.") == -1 && navigator.javaEnabled( ))
JavaOK = 1; }

else if (navigator.appVersion && navigator.userAgent.indexOf("Win") >= 0 &&
((navigator.appVersion.indexOf("2.") == -1 && navigator.appVersion.indexOf("3.") == -1 && navigator.javaEnabled( )) ||
(navigator.appVersion.indexOf("3.") >= 0 && (navigator.userAgent.indexOf("MSIE") >= 0 || navigator.javaEnabled( )))))
JavaOK = 1;

else if (navigator.appVersion && navigator.userAgent.indexOf("X11") >= 0 &&
((navigator.appVersion.indexOf("2.") == -1 && navigator.appVersion.indexOf("3.") == -1 && navigator.javaEnabled( ))))
JavaOK = 1;

else if (((navigator.appVersion && navigator.userAgent.indexOf("Linux") >= 0) && navigator.javaEnabled( )))
JavaOK = 1;

else if (((navigator.appVersion && navigator.userAgent.indexOf("OS/2") >= 0) && navigator.javaEnabled( )))
JavaOK = 1;

JavaOK is a conceptually Boolean variable that is meant to indicate whether the user's browser is Java-enabled or not, as opposed to whether the user's browser supports Java in the first place or not or whether a suitable "Java Virtual Machine" (JVM) is installed on the user's computer or not. Specifically, JavaOK should have the value 1 if Java is switched on in the user's browser preferences
Opera 9.63 Preferences pane showing that Java is enabled
and should be 0 if Java is switched off. If JavaOK is 1, then clicking a usatimezonemap or zonenamesb3c96c19 area takes the user to a "The official U.S. time - clock" page at which a utcnist4.class Java applet produces a running time display.

The above code uses the navigator object's appVersion property, userAgent property, and javaEnabled( ) method to 'sniff' for various Java-enabled browsers, running through a series of if...else conditionals that attempt to flag Java-enabled browsers for Macintosh, Windows, Unix, Linux, and OS/2 operating systems, respectively.

The navigator object is a client-side object that should have been spun off to the DOM way back when, but as of this writing it remains a "DOM Level 0" object that receives no treatment in any of the W3C's DOM specifications - it's like the screen object in this respect. We introduced the navigator object and its appVersion and userAgent properties in Blog Entry #12 and briefly discussed their use in a browser-detection script in Blog Entry #57. The Boolean javaEnabled( ) method is new to us: its terse description in the JavaScript 1.3 Client-Side Reference reads, javaEnabled( ) returns true if Java is enabled; otherwise, false. The user can enable or disable Java [by] through user preferences.

Is it worth it to go through this code in detail? Nope - even without any deconstruction, you can see for yourself that JavaOK is initialized with a value of 1 but is under no circumstances toggled to 0 by any of the subsequent if...else statements, which consequently serve no real purpose and could all be thrown out without affecting the script in any way. Assuming that we do actually want a Java-disabled browser to set JavaOK to 0, the Java browser sniffer could (for what it seeks to do) be written in two lines of code:

if (navigator.javaEnabled( )) JavaOK = 1;
else JavaOK = 0;

As intimated earlier, however, "Java-enabled" does not necessarily mean Java-capable. Mozilla's DOM window.navigator.javaEnabled page warns, The return value for [the javaEnabled( )] method indicates whether the preference that controls Java is on or off - not whether the browser offers Java support in general. In fact, Java is today a mature technology, and only the earliest browsers are not able to run a Java application. The HTML applet element was supported by Netscape as far back as Navigator 2.0; a corresponding client-side JavaScript applet object was implemented in JavaScript 1.1. As for the W3C's HTML specifications, the applet element did not appear in HTML 2.0, was added to HTML 3.2, and was deprecated by HTML 4 in favor of the object element. The MSDN Library's applet element/object page doesn't say which version of Internet Explorer first provided support for Java; reports it to be MSIE 4.

The Java browser sniffer was apparently written to weed out pre-'level 4' browsers that can't handle Java applets - forget for a moment that the usage share of these browsers has gotta be just about zero these days - but again, if JavaOK isn't switched to 0 for such browsers, then what is the point of testing for them?

A Java-enabled browser is going to be a Java-capable browser; however, just because a browser can run a Java application doesn't mean that it will run a Java application in practice. Browser support for Java is not built-in as it is for JavaScript, i.e., browsers do not have 'Java engines' corresponding to their JavaScript engines: to execute Java code, separate software - typically a plug-in of some sort - is required. This raises the question: Can the navigator object's plugins[ ] property/collection (which we also covered in Blog Entry #12) be used to identify and test for a browser's Java software? Maybe in some cases - consider the brief script below:

for (i = 0; i < navigator.plugins.length; i++) {
document.write("(" + i + ") " + navigator.plugins[i].name + "<br />");
if (navigator.plugins[i].name.indexOf("Java") != -1) {
JavaOK = 1; break; } }
/* An analogous script based on the mimeTypes[ ] property/collection of the navigator object can be used to probe a browser's Java-capability. */

On my Intel Mac, this code catches a Java Embedding Plugin plug-in when using Firefox and a Java Plug-in for Cocoa plug-in when using Safari; however, there are a large number of Java-related files on my computer, and I can't say for certain that these plug-ins are the actual JVMs for their respective browsers. When using Opera, the script unearths plug-ins for Shockwave Flash, QuickTime, and RealPlayer, but not for Java; Opera evidently piggybacks onto OS X's native Java 'environment' for its Java-capability (Mozilla's "Using the Java plugin with Firefox" page suggests that Firefox does this as well).

There's a JavaVM executable in my hard disk's /System/Library/Frameworks/JavaVM.framework/Versions/A/ directory - could that be the JVM that OS X browsers use? I don't know.

"Hmph. So the browser doesn't actually execute the Java code. What does 'browser support for Java' really mean, then? Does the browser do anything other than call up the JVM and provide space for the applet?" Perhaps you could ask the people at Mozilla and Microsoft about that - these questions are above my pay grade.

Anyway, I'm unaware of any other JavaScript tools that we can sic on this problem (it would be great if there were a Boolean system.javavm.installed property that we could read, but alas, it is not to be ;-)). FYI, Sun Microsystems, the creator of Java, makes use of a Java applet and not JavaScript to test for Java on its "How do I test whether Java is working on my computer?" page.

So, in lieu of doing some Java programming ourselves, what should we do about testing for Java at the page? The if (navigator.javaEnabled( )) JavaOK = 1; else JavaOK = 0; snippet given earlier shouldn't produce any 'false negatives', i.e., javaEnabled( ) returns false but the browser will render Java, but could definitely produce 'false positives', i.e., javaEnabled( ) returns true but the browser won't render Java; for dealing with the latter cases, perhaps we could query the user directly about Java support: if the snippet determines that JavaOK is 1, then have the page print out a "We detect that your browser can render Java content; if for whatever reason this is not true, then..." message and provide a button that when clicked toggles JavaOK to 0.

You're just an object

If you look over the W3C's client-side image map examples, you'll notice that most of those examples employ object elements and not img elements. "Introduced" by HTML 4 (but priorly supported by both Netscape and Internet Explorer), the HTML object element, quoting Section 13.1 ("Introduction to objects, images, and applets") of the HTML 4.01 Specification, offers an all-purpose solution to generic object inclusion...the term 'object' is used to describe the things that people want to place in HTML documents, including images, programming applets, and other HTML documents. We can straightforwardly use an object element to place the map2.gif image on the page as follows:

Convert <img id="img3" src="/images/map2.gif" usemap="#usatimezonemap" alt="Select a time zone" /> to

<object id="img3" data="/images/map2.gif" type="image/gif" usemap="#usatimezonemap">Select a time zone</object>

Are there any advantages to doing this? Only one that I can think of: as the content of an object element, the map2.gif alternate text can now be reliably formatted. Recall from Blog Entry #139 that in the original source the 'img3' (document.images[3]) placeholder and its associated usatimezonemap map are surrounded by font and b elements:

<font face="Arial,Helvetica,Geneva,Swiss,SunSans-Regular" color="#3c3c98"><b> ... </b></font>

CSS-wise, here's what we can/should do with this markup (with the declarations below to be added to the img3 style rule set):
(1) Arial, Helvetica, and Geneva are all sans-serif fonts, so let's convert the font element's face attribute to a font-family:Arial, sans-serif; declaration. I'm not familiar with the Swiss and SunSans-Regular fonts and they don't appear in Wikipedia's List of typefaces (OK, Wikipedia does list a Swiss 721 font, but to assume that Swiss 721 = Swiss would just make know the rest).
(2) The font element's color attribute would map onto a color:#3c3c98; declaration, but #3c3c98 text doesn't show up very well on a #00695e background, so I recommend a color:white; declaration instead.
(3) The b element can be replaced by a font-weight:bold; declaration.

Are there any disadvantages to trading in map2.gif's img placeholder for an object element? Indeed there is: I find that Safari does not apply the usatimezonemap anchor/area data to map2.gif when held by an object element; for that matter, Safari does not render the Select a time zone text as object element content when map2.gif is not available. Neither of these problems occurs with Firefox or Opera.

One last point:
When using Firefox, the color:white; style declaration for the object element's alternate text adds a 2px solid white border to the map2.gif image; IMO this border looks nice, but you can ditch it if you don't like it by adding an object selector to the img { border:0px; } style rule:

img, object { border: 0px; }

And that concludes our discussion of the page and of image maps in general. At some point in the future, we may work through the updatexearthImage( ) function that lights the day/night world map on the "The official U.S. time - clock" page(s), but for the time being I would like to get back to our study of HTML Goodies' Beyond HTML : JavaScript sector, whose "Capturing a Key" tutorial we will dissect in the next entry.


Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)