Categories
Technology

A story of Cane and Able and the browser that rode a chariot

Back in the early days of the web, there were two browsers. For the sake of our story, we’ll call them “Cane” and “Able”.

Cane and Able could do many of the same things: serve web pages, run scripts, display pictures, and provide for interaction among the Small Beings who became dependent on them. However, Cane did something that Able couldn’t: it rode a mighty chariot and because of this, could replicate itself at will and did so, willy nilly, until one couldn’t go to the marketplace without Cane appearing in front of you. Able, though a solid performer, didn’t have this ability, and over time it fell further and further back into the shadows cast by Cane’s light.

Eventually, Cane grew arrogant with its power, and begin to do things that Able couldn’t, or wouldn’t, do. It demanded that the world change to suit it, rather than it having to suit the world. It broke laws, and then laughed with impunity at the Small Beings who protested. It’s ways played havoc and soon the world fell into a chaos of incompatibility–with little buttons appearing on web pages, each announcing the page’s allegiance: either to Able, or to Cane.

Web page developers wailed and gnashed their teeth at Cane’s cruelty; forced to don sack cloth and smear themselves with ashes as they took up the weight of the cross-browser; herded into this burden by the demands of a world seemingly mesmerized by a spinning blue orb and people who jumped about like monkeys.

Cane was content, for a time, with this devotion–tossing a crumb now and again to the masses as reward; exciting them anew and pushing poor Able away until, finally, exhausted and depleted of resources, Able succumbed to its fates and entered a dark and vast void, to fade away until few remembered its name. Cane, then, was left alone–to stand on a hill and look around it and gloat in its power.

The world, also, was content with Cane’s dominance. Content, that is, until Cane, satiated by feeding on the souls of millions, fell into a somnolence; leaving the Small Beings to pick their way through, however they could, the debris of its passing.

Dark Things came out of the night and plagued the Small Beings. Things that tore at them and took from them and left them dressed in tattered rags. The Small Beings were sore afraid, and shivering in their nakedness, cried softly among themselves and wondered if there could be any to save them.

But all was not lost. Among the ashes of Able’s passing, a new hope was rising–the child of Able. This child was weak at first, as all children are. It moved slowly about gathering strength until finally, one day, the world became aware of its movements. As the child of Able grew, it cast light into the shadows on the land, and the people basked in its gentle warmth, smiled at is kindly tickling.

The Small Beings then turned an eye to the dark unmoving Mass that was Cane and cried out, “What have you done to us?” “Why have you forsaken us?” But Cane was too lost in sleep to waken, to indifferent to the puny cries of those whose only purpose was to service it, and the chariot it rode.

Able heard, though, and reached out to succor the people, to give them hope. Soon, many of the world were turned away from the spinning blue orb to feast on a new vista–one based on the fire of re-birth rather than the despair of old, cold greed.

This Small Being and that Small Being woke from their dreamless night and embraced the fire, and Able grew in numbers until one day, Cane was moved to awaken and when it looked about itself, grew alarmed at the loss of those who would worship it. “This will never do”, it thought to itself, and begin anew to weave a web to draw back in those who would drift away.

It appeared before the masses as a humbled shell of its former self, and begged forgiveness for past abuse. It promised to do better, to not break the laws, to bring about nothing but goodness. It even embraced this child of its own nemeses, this new Able, and promised to work as brethren rather than adversaries.

Still, the people were reluctant to embrace this, their old overlord. They remembered the too many years of darkness and confusion and were hesitant to believe in Cane’s newfound humility. Desperate to find a hook with which to lure the Small Beings back, Cane looked about and spotted a mob within the masses, a noisy mob that pretended to great power and felt a strange form of kinship with this mob. “These are as like to me as no other”, Cane thought. It also noticed that the mob waved a flag above its head, a flag that looked as follows:

“Aha!”, it thought to itself. “If I were to wave this flag, too, all my past ills will be forgotten and I will be as beloved as I once was before I abandoned these Small Beings to their fate.” So Cane grabbed the flag and waved it most strenuously and cried out its joy in the Cause and its promise of adherence to all that was righteous in the land. And many of the people looked on from their commune with 864 others of their kind and saw that this was good.

Times had changed, though, in the aeons since Cane slept. Though the new Cane was lithesome in many eyes, others noticed that it still rode a chariot where other browsers walked. More, this was a new chariot: one that was wider and taller and more massive and as such, could not reach into the places where once it had traveled. Because Cane rode this new chariot, many of its followers would be left in the dark when it finally arose into the sky.

Those that noticed this questioned why this was so and Cane, puzzled, could only reply that it had to ride this chariot in order to be safe. Many nodded, of course–Cane had to ride the chariot in order to be safe.

But, questioned those naysayers, those irritants, those not with the program: could not Cane learn to walk as other browser do? Walk and still be safe? Walk, like the child of Able can walk? Walk, like Able’s friends, the songster and the lion? Walk so that all may share it’s glory?

Cane just laughed, and the sound was as of a thousand coins of gold rained down from the heavens. Many heard the laughter, and felt comforted. Others, though, knew Cane for what it was: the same Cane as old, only polished, shiny and new.

Categories
JavaScript

Netscape Navigator’s JavaScript 1.1 vs Microsoft Internet Explorer’s JScript

Originally appeared in Digital Cats magazine. Found courtesy Wayback Machine.

Prior to Netscape implementing JavaScript in Netscape Navigator, web developers had few tools to create interactive content for their web pages. Now this scripting language gives developers the ability to do things such as check form contents, communicate with the user based on their actions, and modify the web page dynamically without the web page being re-loaded and without the use of Java, plug-ins or ActiveX controls.

Unfortunately, JavaScript was not usable by any other browser until Microsoft released Internet Explorer (IE) 3.0. With this release web developers could deliver interactive content that would at least work with the two most widely used browsers. Or could they?

On the surface, the JavaScript supported by both companies is identical. They both provide the same conditional control statements, have defined objects such as window or document,and can be used directly in HTML documents. They both support events based on user actions and support functions in a similar manner. However, this article will demonstrate that though the languages may look the same on the surface, there are differences that can trip the unwary developer.

JavaScript Objects

To understand the differences between the two implementations of JavaScript you must examine the objects both support. As an example, with Navigator 3.0 Netscape provides a new object image which is an array (defined as images that contains the images in the document currently loaded. This object allows the developer to change the images of a document without re-loading the document or using Java or other technique. With this capability the developer can write the following JavaScript code section without error:


sSelected = "http://www.some.com/some.gif"
document.images[iIndex].src = sSelected

This code will change the src property of the image that is contained in the array at the index given in the variable iIndex. If this variable contained the value 2, the 3rd image as loaded in the document (the array indices begin at 0) would be changed to the image located in the given URL. An example using images can be found here.

Running the same example with Internet Explorer will result in a alert message that states that “‘images’ is not an object”.

Other examples of objects that are defined for Netscape Navigator but not for Microsoft Internet Explorer are:

  • The Area object, which is an array of links for an image map that allows the developer to capture certain events for the image map that can be used to provide additional information to the user. With this, the developer can capture a mouseOver event to write out information about the link in the status bar.
  • The FileUpload object which provides a text like control and a button marked with “Browse” that will allow a reader to enter a file name. The JavaScript can then access the name of the file.
  • The Function object which allows the developer to define and assign a function to a variable which can then be assigned to an event.
  • The mimeTypes Array of supported MIME types.
  • The option object which is an array of the options implemented for SELECT and which allows the developer to change the text of the option at runtime
  • The applet object, which is an array of Applets in the document (read-only)
  • The plugin object, which is an array called embeds that contains the plug-ins contained in the document (read-only)
  • The plugins array, which is an array of plug-ins currently installed in the client browser

At this time there are no JavaScript or JScript objects defined for Internet Explorer that are also not defined for Netscape. However, as JScript is an implementation script for IE and Microsoft has defined their own IE scripting model, this could change in the future.

JavaScript Object Behavior and Ownership

Internet Explorer may not have additional objects but it has defined a different hierarchy and ownership for some of the objects that are used by both it and Navigator. All objects are contained within the window object in the IE scripting model, which can be viewed here, but not all objects are owned by window with the Navigator model, which can be viewed with the JavaScript Authoring Guide. The object Navigator, which is the object that stores information about the browser currently being used, is an example of an owned object by window in IE but not in Navigator.

This will not present an incompatibility problem between the two browsers as the developer will usually not preface the object with the term “window” as the following code demonstrates:


<FORM NAME="form1">
<input type=button value='press' onClick="alert(navigator.appName)">
</FORM>

The above code will work with both browsers.

The differences between the ownership can become a problem when an object is owned by different levels of objects. An example is the history object, which is owned by the window object in IE, but by the document object in Navigator. When used in the current window and document, the object will work the same as the following code will demonstrate:


<FORM NAME="form1">
<input type=button value='press' onClick="history.back()">
</FORM>
 

The reason the same code can work for both is that window is assumed for both IE and Netscape and document is assumed for Navigator, at least in this instance because history is also an object in its own right. In the case of a document being opened as part of a frame, the differences then become noticeable. The following code will work when the document is opened as a frame in IE, but will not work in Navigator:


<body>
<script>
function clicked() {
history.back()
}
</script>
<FORM NAME="form1">
<input type=button value='press' onClick="clicked()">
</FORM>
</body>

Clicking on the button from the code above will work for IE. The previous document in the History list will be opened, but the same code will not work for Navigator. Clicking on the button will result in neither a change of document nor an error. Prefacing the history object with parent will enable this code to work with both browsers.

JavaScript Properties

Even when IE and Navigator share a common object and a common object ownership, they can differ on the properties for an object. An example is the document object. The properties for both implementations are the same except for an URL property for the Navigator implementation and a location property for the IE implementation. However, if you examine both properties, they are identical! Both contain the URL of the document. Both are read-only. The following code will work with Navigator, but results in an empty Alert message box for IE:


<FORM NAME="form1">
<input type=button value='press' onClick="alert(document.URL)">
</FORM>

According to Microsoft documentation, the equivalent for IE would be to use document.location.href. However, though this does not result in an error, it also results in an empty alert box. The following code achieves the desired results and, happily, works in both browsers:


<FORM NAME="form1">
<input type=button value='press' onClick="alert(location.href)">
</FORM>

The above example does demonstrate another area of caution when using the JavaScript language: this language is unstable in both environments and is changing continuously. Don’t assume something will work because the documentation states it will, and don’t assume it will work the same on all operating systems. Both browsers can have different behaviors across different operating systems, sometimes because of operating system differences and sometimes because of bugs that were missed during testing on that specific OS.

JavaScript Methods and Events

A web developer can find ways of working around differences in objects and properties, but working around differences in methods may not be so easy. When we develop we expect a certain behavior to result when we call a specific function and pass to it certain parameters. With Microsoft Internet Explorer and Netscape Navigator, the best case scenario is that we can use a pre-defined object method with both browsers and have the same result. The worst case scenario is that the method works with both browsers, but the result is different.

An example of the best case scenario is to use JavaScript to validate form field contents which have changed or to use these contents to calculate a value used elsewhere. Calling a JavaScript function from the onChange event to process the changed contents as demonstrated below will work with both browsers:


<!--- Form fields
<p>Item Quantity: <INPUT TYPE="text" Name="qty">
Item Cost: <INPUT TYPE="text" Name="cost"
                onChange="NewCost()">
Total Cost: <INPUT TYPE="text" Name="total" Value=0>
…
<!--- Function
<SCRIPT LANGUAGE="javascript">
<!--- hide script from old browsers

// NewCost will
// calculate cost of qty and item
function NewCost() {
        var iCost = parseFloat(document.Item.cost.value)
        var iQty = parseInt(document.Item.qty.value)

        var iTotal = iCost * iQty
        document.Item.total.value = iTotal
        }

The above will work as expected with both IE and Navigator. When the user enters a quantity and a cost, the onChange event will fire for the cost field and a JavaScript function called NewCost() will be called. This function will call two built-in JavaScript functions, parseFloat() and parseInt(), to access and convert the form field values. These will then be used to compute a total which is placed in the total field.

So far so good. Another JavaScript function in the web page will be processed when the user presses the submit button. This pre-defined button style will normally submit the form. The developer can capture the submission and perform validation on the fields. Coding this for Navigator would look like the following:


<FORM NAME="Item"
        ACTION="some.cgi" onSubmit="return SendOrder()">
…
<!--- Function
// submit order
function SendOrder() {

        // validate data
        if (document.Item.Name.value == "") {
                alert("You must enter your name")
                return false
                }
        return true
        }

Capturing the onSubmit event will allow the developer to call a function to process the form fields. If they choose, they can perform validation in this function. If the validation fails, say the user did not provide a name, the function notifies the reader and returns false, preventing the form from being submitted. If the user did provide a name, the function would return true, and the form would be submitted.

Following the documentation that can be found at the Microsoft site, the developer would expect something like this to work for IE as well as Navigator. It does, to a point.

With IE the onSubmit event is captured and the SendOrder() function is called. If the user did not enter a name value, an alert would occur. The behavior is the same for both browsers at this point. However, if the user does provide a value, Navigator would then submit the form and a follow-up form would be displayed. This does NOT occur with IE IF you are testing the page locally, probably due to a bug missed during the testing. It does work if you run the web page documents through a web server.

However, without knowing that the difference between the two results was a matter of document location rather than document coding the web page developer could have spent considerable time trying to get the same behavior for both browsers.

Aside from the differences already noted, the browsers may process code in a funtionally identical manner and yet perform quite differently. This can be demonstrated with another popular use of JavaScript which is to open a secondary window for some purpose and to maintain communication between the two windows. This is widely used by Netscape for their tutorials.

Both browsers support a property for the window object called opener. This property can be used to contain a reference to the window that opened the secondary window.

The following code demonstrates using JavaScript to open a secondary window and to set the opener property to the original window:


<HTML>
<HEAD><TITLE> Original Window </TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!--- hide script from old browsers
// OpenSecondary will open a second window
//
function OpenSecond(iType, sMessage) {
        // open window
        newWindow=window.open("second.htm","",
                "toolbar=no,directories=no,width=500,height=300")
        // modify the new windows opener value to
        // point to this window
        if (newWindow != null && newWindow.opener == null)
                newWindow.opener=window

        }
// end hiding from old browsers -->
</SCRIPT>
</HEAD>
<BODY>
<H1> Open a new Window and get information</H1>

<FORM NAME="CallWindow">
<p>Click to open Window:
<p>
<INPUT TYPE="button" NAME="OpenWin" VALUE="Click Here"
        onClick="OpenSecond()">
<p>
</FORM>
</BODY>
</HTML>

The above HTML and JavaScript creates a simple document with one button. Pressing the button opens a new window (creates a new instance of the browser) that does not have a toolbar or directories and is set to a certain width and height. The HTML source document that is opened into this new window is “second.htm”.

The HTML and JavaScript in the secondary window is shown below:


<HTML>
<HEAD><TITLE> Information</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!--- hide script from old browsers
// SetInformation
// function will get input values
// and set to calling window
function SetInformation() {
        opener.document.open()
        opener.document.write("<BODY>")
        opener.document.write("<H1> Return from Secondary</h1>")
        opener.document.write("</BODY>")
        opener.document.close()
        opener.document.bgColor="#ff0000"
        window.close()
        }
// end hiding from old browsers -->
</SCRIPT>
</HEAD>
<BODY>
<p><form>
Click on the button:<p>
<INPUT type="button" Value="Click on Me"
     onClick="SetInformation()">
</CENTER>
</FORM>
</BODY>
</HTML>

This code will display a button labeled “Click on Me”. Pressing this button will result in the document page for the original window being modified to display the words “Return from Secondary”. The JavaScript will also change the background color of the original document and then will close the secondary window. When run in Navigator, the sample behaves as expected. Not so, however, with IE.

First, when you open the secondary window in IE you will notice that the document in the original window seems to blank out for a moment. In addition, the secondary window opens at the top left hand side of the desktop with IE but opens directly over the original window with Navigator, no matter where that original window is.

When you press the button that modifies the original document, IE does modify the document with the new header, as Navigator does, and the background on the original document will change briefly. However, when the secondary window is closed the background color of the original document returns to the original color!

What is worse is that running this sample for a few times with IE will cause the browser to crash! How soon it will crash seems to suggest that resources are not being freed, or are being freed incorrectly. Whatever the cause, this behavior should make a developer feel cautious about opening up a secondary window within IE.

Solutions to working with both Internet Explorer and Navigator

JavaScript is a useful tool for creating interactive content without using Java or some other technique. As we have seen, problems arise out of the incompatibility between Navigator and IE. What are ways to avoid these problems?

  • Code for one browser only. This is not really a viable solution. While Netscape Navigator is the most popular browser in use today, Microsoft Internet Explorer is gaining quite a following. Using Navigator-only JavaScript that will limit your web page’s audience.
  • Code only to the least common denominator. By limiting the JavaScript to that which works for both Navigator and IE, developers will have access to most of the functionality they need. However, with this approach developers will need to be aware of the gotchas that have been discussed in this article. In other words, the developer has to test with both browsers; the tests will have to occur via the web server as well as run locally; the tests should be repeated several times to ensure that no adverse effects show up over time; the code should be tested with all possible environments.
  • Code for each browser within the same page. This is actually my favorite approach though it will require more effort by the developer. Both browsers will process JavaScript labeled as <SCRIPT LANGUAGE=”javascript”>, however only Navigator will process script labeled as <SCRIPT LANGUAGE=”javascript1.1″>. With this approach, the developer can place JavaScript common to both browsers in a SCRIPT tag labeled with “javascript” and Navigator specific code in a SCRIPT tag labeled with “javascript1.1”. To add in IE specific code, the developer would probably want to use VBScript code or use the tag JScript whenever applicable. At this time, JScript is implemented for scripting with events only, not as a language specification for the SCRIPT tag.

Summary

JavaScript is a very effective tool, and a relatively simple method for adding interactive content to a web page. With version 3.0 of Internet Explorer, using JavaScript is viable for both of the most popular browsers in use. However, developersneeds to be aware of the differences between Netscape Navigator and Microsoft Internet Explorer and should test thoroughly with both before posting the page to their site.