JavaScript Bible (3rd Edition) Support Center

Corrections & Updates

  • CD-ROM: The index.htm page that provides a collapsible outline-style table of contents for the CD-ROM listings requires that cookies be enabled in your browser. The code for the outliner is explained in Chapter 50, which is entirely on the CD-ROM (the publisher ran out of trees).
  • Page 3: "URL" is the acronym for "Uniform Resource Locator".
  • Page 59: The second sentence of the last paragraph should begin: Do not type a carriage return after the "=" sign....
  • Page 65: Instructions in the sidebar about testing evaluations in the JavaScript type-in page need slight modification to work with the new JavaScript Console window that appears in Navigator 4.07 and later. If you declare a variable in the type-in field, it seems to disappear from memory after the first time it is used in a subsequent statement. This is too bad, because the old way was much handier.

    In any case, you can still test simple evaluations here. To follow the same sequence of thought in the example at the bottom of the sidebar, you have to declare the variables twice. Thus, enter the following statements one at a time and watch for results in the upper frame:

    var myAge = 45
    var yourAge = myAge - 15
    myAge - yourAge

    var myAge = 45
    var yourAge = myAge - 15
    myAge > yourAge

  • Page 68: The last word of the first sentence should be "number".
  • Page 78: A </HEAD> tag is missing from Listing 7-2 right after the script.
  • Page 95: The first sentence of the second paragraph should read: "A button in the page invokes the subWrite() function."
  • Page 100: The code excerpt in the lower half of the page is missing an equal sign (=) in the third line. The conditional expression requires the equality comparison operator (==), not the equal operator (=) as shown:
      if (form.elements[i].type == "text") {
  • Page 105: In the first paragraph of the Select Object section, the reference to Figure 9-1 should read Figure 8-1
  • Page 106: The third OPTION element value in Listing 9-4 should be "policies.html" if it is going to navigate anywhere.
  • Page 116: In the discussion of the indexOf() method, I must have experienced a mental lapse. A statement in the second full paragraph is wrong, as is the code example that supports it. The paragraph and example should read:
    Two strings are involved with this method, the shorter one and the longer one. The longer string is the one that appears in the reference to the left of the method name; the shorter string is inserted as a parameter to the indexOf() method. To demonstrate the method in action, the following fragment looks to see if the user is running Windows:

    var isWindows = false
    if (navigator.userAgent.indexOf("Win") != -1) {
       isWindows = true
    }

  • Page 117: An extra left parenthesis graces the second statement of the script fragment in the middle of the page. The statement should be:
       var excerpt = stringA.substring(stringA.indexOf(" ") + 1, stringA.length)
  • Page 118: The statement about raising numbers to a power of 10 would be better served with the following example:
       var result = Math.pow(value1, 10)
    The second parameter of the Math.pow() method is the power to which you want to raise the value of the first parameter.
  • Page 118: As reader Paul Rubin points out, the script fragments on this page and on page 576 about random numbers give less than random results. The fix is simple, however:
       newDieValue = Math.floor(Math.random() * 6) + 1
  • Page 122: The listing in question #3 is missing the </FORM> tag right before the </BODY> tag.
  • Page 129: In Listing 11-1, the first statement of the goNext() function should be the same as the first statement of the goPrev() function below it: var currOffset = parseInt(parent.currTitle). And for sake of consistent style, there should be a space between the < symbol and the 5.
  • Page 130: In Listing 11-2, the second <FORM> tag should obviously be </FORM>.
  • Page 131: The </BODY> tag is missing from Listing 11-3.
  • Page 131: In the code listing at the beginning of the Exercises, the SRC attribute value has two periods where only one belongs.
  • Page 136: See extensive notes below about Listing 12-2.
  • Page 157: The URLs in Listing 13-2 don't match the text. The listing file on the CD-ROM does match. See also Listing 13-2 below.
  • Page 162: The deeply nested statement in the second SCRIPT tag of Listing 13-5 has an extra space between forms[0]. and janeButton. In a lot of places, JavaScript doesn't care about extra spaces, but dot-delimited references cannot have any blank spaces in them.
  • Page 169: In the middle of the page is an incorrect pointer to a figure. The clause should read: "..., just like the model shown in Figure 14-1."
  • Page 173: The javascript: pseudo-URL at the end of Listing 14-2 should not have quotes around the expression:
       "javascript:parent.blank()"
  • Page 187: The compatibility chart at the top of the page should show only one checkmark:for Navigator 4.
  • Page 191-2: For the content of the textarea element to be included in the mail message, you must assign a value to the textarea's NAME attribute, as shown in the code for the following item.
  • Page 191-2: Unlike Navigator 3/4, Internet Explorer 4 doesn't let you turn off script error dialog boxes by setting window.onerror to null. You can accomplish the same behavior with the following statements:

    window.onerror = doNothing
    function doNothing() {return true}

    If you are toggling between error messages on and off (as in Listing 14-9), you can build the above into the whole listing, as follows:

    
    <HTML>
    <TITLE>Error Dialog Control</TITLE>
    <SCRIPT LANGUAGE="JavaScript1.1">
    // function with invalid variable value
    function goWrong() {
       var x = fred
    }
    // turn off error dialogs
    function errOff() {
       window.onerror = doNothing
    }
    // turn on error dialogs with hard reload
    function errOn() {
       window.onerror = handleError
    }
    
    // assign default error handler
    window.onerror = handleError
    
    // error handler when errors are turned off...prevents error dialog
    function doNothing() {return true}
    
    function handleError(msg, URL, lineNum) {
       var errWind = window.open("","errors","HEIGHT=270,WIDTH=400")
       var wintxt = "<HTML><BODY BGCOLOR=RED>"
       wintxt += "<B>An error has occurred on this page.  Please report it to Tech Support.</B>"
       wintxt += "<FORM METHOD=POST ACTION=mailTo:support3@dannyg.com ENCTYPE='text/plain'>"
       wintxt += "<TEXTAREA NAME='errMsg' COLS=45 ROWS=8 WRAP=VIRTUAL>"
       wintxt += "Error: " + msg + "\n"
       wintxt += "URL: " + URL + "\n"
       wintxt += "Line: " + lineNum + "\n"
       wintxt += "Client: " + navigator.userAgent + "\n"
       wintxt += "-----------------------------------------\n"
       wintxt += "Please describe what you were doing when the error occurred:"
       wintxt += "</TEXTAREA><P>"
       wintxt += "<INPUT TYPE=SUBMIT VALUE='Send Error Report'>"
       wintxt += "<INPUT TYPE=button VALUE='Close' onClick='self.close()'>"
       wintxt += "</FORM></BODY></HTML>"
       errWind.document.write(wintxt)
       errWind.document.close()
       return true
    }
    </SCRIPT>
    </HEAD>
    <BODY>
    <FORM NAME="myform">
    <INPUT TYPE="button" VALUE="Cause an Error" onClick="goWrong()"><P>
    <INPUT TYPE="button" VALUE="Turn Off Error Dialogs" onClick="errOff()">
    <INPUT TYPE="button" VALUE="Turn On Error Dialogs" onClick="errOn()">
    </FORM>	
    </BODY>
    </HTML>
    
    

    The changes to Listing 14-9 are:

    1. Assign a value to the NAME attribute of the TEXTAREA element
    2. Change the name of the main error handling function (to handleError)
    3. Manually assign that function to window.onerror in the code as the page loads
    4. When turning errors off, assign the doNothing function to errors
    5. Instead of reloading the page (which would still work), reassign the first function to the onerror event
  • Page 203ff: Adjusting the window.status property by event handlers in AREA elements in IE5/Windows does not appear to be working. Bummer.
  • Page 212: The listing pointer at the end of the blur() description should be to Listing 14-29.
  • Page 216: The continued listing bar at the top of the page should refer to Listing 14-23.
  • Page 231: The moveBy() method of a window object is supported in IE4.
  • Page 234: Table 14-1 is not correct about the description of the height and width attributes of the window.open() method. Both values control the dimensions of the content region of the window.

    If you are trying to open a new window that appears maximized, you have to take different approaches for Navigator 4 and Internet Explorer 4+. For one thing, not mentioned in that table are the top and left attributes that work in both NN4 and IE4+ (to position the window at 0,0). But you might be better off by opening the window to its default size/position, and then use window object methods to move the window and size it accordingly.
    For IE4+:

    newWind.moveTo(0,0)
    newWind.resizeTo(screen.availWidth, screen.availHeight)

    For NN4+:

    newWind.moveTo(0,0)
    newWind.outerWidth = screen.availWidth
    newWind.outerHeight = screen.availHeight
  • Page 242: Contrary to some statements about the print() method, Navigator 4 for Win32 does not let you print all frames of a frameset in one command. But you can script the printing of all frames in succession, provided you give the browser enough time to spool each frame's content. The following script prints all frames of a frameset in five-second intervals when the function is initially invoked as printFrames(0):

    function printFrames(n) { parent.frames[n++].print() if (n < parent.frames.length) { setTimeout("printFrames(" + n + ")",5000) } }

    But this also brings up an important question: Can you get IE4 to print from script control? The answer is "Yes" for the Win32 versions only. Embed the following <OBJECT> tag exactly as shown:

    <OBJECT ID="IEControl" WIDTH=0 HEIGHT=0 CLASSID="clsid:8856F961-340A-11D0-A96B-00C04FD705A2"> </OBJECT> You can then command this ActiveX control to print whatever window/frame has current focus with the following statement:
    IEControl.ExecWB(6, 1) This command produces the print dialog, just as window.print() does in Navigator. But canceling the print dialog causes a script error (don't ask me why). If you substitute a 2 for the second parameter, the printing takes place without the print dialog. This is smoother for you, but not so great for the user, IMHO. You can also hide the error dialog by assigning a dummy function to window.onerror and let the function return true.

    MSIE 5 observes the window.print() method.

  • Page 258: In the example code about 2/3 of the way down the page, the first parameter of the setTimeout() is missing its parentheses. It should read:
    t = setTimeout("autoReport()",500)
  • Page 265: In the discussion of the onResize event handler, the second sentence code portion should read: window.onresize = handleResizes.
    Also, be aware that the IE event object does not contain properties for the height and width of the resized window/frame.
  • Page 302: In the fourth line up from the bottom of the page (Listing 16-1), the text of the link needs an escaped apostrophe to work properly from within this nested string assembly. The script line should begin:

    thePage += "HREF='http://www.nowhere.com'>here\'s a link</A> ...
  • Page 311: The getCookieData() function shown at the top of the page was extracted and adapted from the cookie function I use in the Outline-Style Table of Contents (Chapter 50 on the CD-ROM). That application assigns both the label name and the label's "=" sign as the label. If you use the getCookieData() function as shown on page 311, and your intention is to pass just the label name (without the = symbol), then the return statement should be: return unescape(document.cookie.substring(j+1, cEnd)) to take this offset into account.
  • Pages 320/321: Pointers to Chapter 29 and the Date object should be to Chapter 28.
  • Page 321: The value of the layers property is an array of LAYER element objects.
  • Page 336: The chapter cross-reference in the next-to-last paragraph is incorrect. The String object is covered in Chapter 26, not Chapter 27 as shown.
  • Page 347: The paragraph after the end of Listing 17-1 doesn't belong there...or anywhere. Ignore it and its reference to a verifyMove() function.
  •  
  • Page 348: A reader correctly points out that while Listing 17-2 does all the image rollover stuff properly, the links associated with the images do not navigate anywhere, even if you set a valid URL for the HREF attributes. Here's why and what you can do about it.

    It turns out that because they evaluate to 'return false', the onMouseDown and onMouseUp event handlers prevent the necessary click from ever reaching the element for the HREF setting to take effect. The onMouseDown event must evaluate to 'return false' (as shown in the listing) to prevent the popup context menu from appearing on the Mac when someone holds the mouse button down on the link for more than about a second. Therefore, no matter what you assign to the HREF attribute of these links, they won't navigate to those pages.

    But, there is an easy way to work around this and still maintain the proper context menu blocking. In the onMouseUp event handler, set the location.href property to the desired page, and _then_ do the image swap:

    <A HREF="javascript:void(0)" onMouseOver="return setImage('Right','Up')" onMouseDown="return setImage('Right','Down')" onMouseUp="location.href='nextPage.html'; return setImage('Right','Up')" onMouseOut="return setImage('Right','Norm')">

    In practice, you may not even need the setImage() call in the onMouseUp event handler, because the swap back to the 'up' position image will be visible for a fraction of a second at best as the new page starts loading in.

    See also a note about this listing at the bottom of this page.

  • Page 355: The onMouseOut event handler at the bottom of the page has a couple of typos. The correct statement (with changes in red) is:
    onMouseOut="document.ToHome.src = normalButton.src; return true"
  • Page 367: The list of methods for the Navigator 4 Layer Object is missing the four event-related methods that are also available to the window and document objects:
    captureEvents()
    handleEvent()
    releaseEvents()
    routeEvent()

    These four methods work the same way for layers as they do for the document object. Navigator events trickle downward from window to document to layer if the event was intended for a form element located inside the layer object.
  • Page 368: The syntax listing for the LAYER element indicates that the ILAYER has the same event handlers. That's not entirely true. The onMouseOver and onMouseOut event handlers are missing from the ILAYER. Of course, from a scripting standpoint, the ILAYER object is practically worthless, since it rarely behaves the way you want it.
  • Page 373: The last sentence of the first paragraph should read: Attempts to get properties of a nonexistent layer result in runtime scripting errors indicating that the object does not have properties (of course not - an object must exist before it can have properties).
  • Page 405: Near the middle of the page is a reference to the layer.reload() method. This should be layer.load(), as correctly shown in Listing 19-12 on the following page. There is no reload() method of the layer object.
  • Page 445: The onSelect event handler does not work in Windows versions of Navigator. It's OK in Mac versions, however.
  • Page 450: For IE4 on the Mac, the script in Listing 22-7 causes quote marks to appear in the text box, rather than the typed characters. If you change the final statement of the checkIt() function to just return insead of return true, the problem disappears and doesn't interfere with operation on other OS platforms.
  • Page 499: The first paragraph of the example incorrectly reports the value of selectedIndex when you choose the 'Green' option. Because the 'Green' option is the second option, its index value is 1. The reference to the second option's text is form.colorsList.options[1].text.
  • Page 546: In Listing 26-2, the showProps() function is not invoked by anything on the page. I had used it for debugging, as you have seen elsewhere in the book.
  • Page 552: I should have explained something about Listing 26-4 that could cause some head scratching. Notice that the default regular expression is \B't. The \B means a word nonboundary (see Table 30-1 on page 622), yet when you run it against the large string that contains the text Whether 'tis, the 't is replaced with the supplied replacement string. How, you may ask, can 'tis preceded by an apparent space have a word nonboundary in front of it?

    Perhaps it would have been clearer if I had formatted the large text properly, which would have included an escape character before the apostrophe of 'tis, since it is a single nested quote inside an explicit string. But even though I left out the escape character, the browser managed to insert it internally. Therefore, to the regular expression matching algorithms, the escape character (a backward slash) creates the word nonboundary in front of 'tis.

  • Page 576: See Page 118.
  • Page 587: In Listing 28-1, a statement in the customDateString() function needs some updating to reflect changes to the Date.getYear() method that took place back in Navigator 3. In the "old days", the getYear() method always returned a two-digit year. But in more recent browsers, the method returns a four-digit year for 2000 and thereafter. Thus, adding 1900 to the value, as shown in the function, doesn't do the job as expected. To fix the problem, modify the statement as shown below, and add one more statement to fix the two-digit problem only when it's needed:

       var theYear = oneDate.getYear() // add operation removed
       theYear += (theYear < 1900) ? 1900 : 0

    Of course, if your users all have NN4+ or IE4+, you can use the getFullYear() method in place of the original statement, and not worry about Y2K at all for this one.

  • Page 605: The bottom of the page incorrectly suggests that if you assign a custom method to Array.prototype, then you can invoke the method from a reference to an array element. The method would have to be invoked from a reference to the array, and not one of its elements. This also means that an array element is not passable as a parameter via the this keyword. Thus, with the following method invocation:

    CDCollection.showCover(this)

    the parameter passes a reference to the entire array. Of course the function could be written to accept a second parameter that is an index to the desired array item.

  • Page 606: The concat() method of the Array object returns an array, as the examples clearly show.
  • Page 607, 609: The example, Listing 29-6, and its screen shot (Figure 29-2) need a minor correction. The label for the last text field on the page should make a reference to arrayThree[5]. The script code reads the correct data, but the label is misleading.
  • Page 615: Just below the middle of the page is a parenthetical statement that should read: "(that is, position a at a higher value index position than b)". Use Table 29-1 as your guide.
  • Page 619ff: (Updated) It appears that I gave Microsoft's earlier JScript docs a bit more credit than they deserved regarding support for regular expressions in IE4's JavaScript 1.2 support. Their recent docs and my experience reveals a lack of some fine points. The stuff that bit me one day was that the RegExp object in IE4 does not support the lastParen, leftContext, multiline, rightContext, or lastMatch properties.
  • Pages 626-629: Several tables in the text refer to a RexExp object -- typos for RegExp. D'oh.
  • Page 630: The text just above Listing 30-1 says it demonstrates both the test() and search() methods, but the listing demonstrates only the search() method. Here is a rendition of the findIt() function that uses test() instead of search():

    function findIt(form) {
       var re = new RegExp(form.regexp.value)
       var input = form.main.value
       if (re.test(input)) {
          form.output[0].checked = true
       } else {
          form.output[1].checked = true
       }
    }

  • Page 663: The second sentence of the first paragraph incorrectly says that switch statement labels should not be quoted. The example listing 31-6 shows the correct way, which is, in fact, to quote label values if they are strings. If the parameter of the switch() statement evaluates to a number, then you can use numeric values or strings as label values.
  • Page 671: The group of five examples near the middle of the page is missing a right parenthesis in the fourth example. It should be:

    -(x + y)

  • Pages 672, 677, and 683-4: These errors affect you only if you use bitwise operators. Somewhere along the book production cycles, a greater-than symbol was lopped off the Right Shift and Zero Fill operators (and their "by Value" assignment partners) wherever they appear in tables: Table 32-5, 32-9, and 32-10. The operators are as follows:

    OperatorDescription
    >>Right Shift
    >>>Zero Fill
    >>=Right Shift by Value
    >>>=Zero Fill by Value
  • Page 677: For some reason, the checkmark for IE4 in the Bitwise Operators compabitility listing is missing. These operators are, of course, supported in IE4.
  • Page 701: To clarify the first sentence of the first full paragraph: the function returns a Boolean value of true if the parameters are smaller than the local variables.
  • Page 704: In line 9 of Listing 34-1, the expression hansel.x could also be just x, since the two expressions evaluate to the x parameter of the function. But it is also helpful to know that a function's parameter is also one of the function's properties.
  • Page 706: To get the desired results for Listing 34-2 in most browsers, you have to modify the last() function slightly. The issue is that references to the caller property requires a reference to the function that owns the property. Here is the repaired script (with changes in red):

    function last(firstMsg, secondMsg) {
       var thirdMsg = "Var in 3rd Function"
       var form = document.output
       form.lastFuncArgs.value = showProps("last.arguments", last.arguments)
       form.midFuncArgs.value = showProps("last.caller.arguments", last.caller.arguments)
       form.firstFuncArgs.value = showProps("last.caller.caller.arguments", last.caller.caller.arguments)
    }
  • Page 714ff.: The discussion about custom objects fails to mention that you can reference a property of a custom object by a string version of the property name via array syntax. Following the example of Listing 34-7, you could reference the Mercury.diameter property also as Mercury["diameter"]. This format can come in handy in other scripts where property names arrive at a function in string form (e.g., from a SELECT element value).
  • Page 735: The third paragraph, third line should read: ends with an asterisk and forward slash(*/).
  • Page 766: In the second paragraph, the phrase "assuming two-digit entries for month and year" should read "assuming two-digit entries for month and date".
  • Page 792: As a reader pointed out, the mainwin.call() statement in the toggleColor() function of Listing 38-6 should be surrounded by a Java try...catch construction to take care of potential exceptions thrown by the call() method.
  • Page 802: In the next-to-last paragraph, the reference to Appendix B should be to Appendix A.
  • Page 837: The Java applet associated with Listing 40-3 no longer works in Navigator 4 for the Mac. Something must be afoot with the Java VM situation with more recent versions of Navigator 4 and the Mac, but so far I haven't gotten to the bottom of the problem.
  • Page 867: The engage() function needs a little tweaking to work correctly in IE4+ for the Mac. I've added a short routine that backs out the body scroll offset for non-Windows versions of IE, as follows:

    function engage(e) {
       getSelectedMap(e)
       if (selectedObj) {
          if (isNav4) {
             offsetX = e.pageX - selectedObj.left
             offsetY = e.pageY - selectedObj.top
          } else {
             offsetX = window.event.offsetX - document.body.scrollLeft
             offsetY = window.event.offsetY - document.body.scrollTop
             if (navigator.userAgent.indexOf("Win") == -1) {
                offsetX += document.body.scrollLeft
                offsetY += document.body.scrollTop
             }

          }
          setBGColor(selectedStateLabel,"yellow")
       }
    }

    The same goes for the IE-only version on page 903.

  • Page 878: The first word of the third line of paragraph 1 should be: inset.
  • Page 903: See Page 867, above.
  • Pages 934-5: After the book went to press, Acadia Software and its Infuse 2.0 authoring tool were acquired by NetObjects. The product has a new name: ScriptBuilder. Check it out!
  • Page 959: The listing for 7-1, which ends at the top of this page, is missing the </FORM> tag. It should go right above the </BODY> tag.
  • Pages 964 (top): The answer supplied for question 2 (of Chapter 9's exercises) didn't listen to the question fully. While the answer assumes the submission of the form is to be triggered by a click of a regular button form element, the question asked to implement a link to do the submission.

    All that needs changing in the answer's HTML listing is to swap the <INPUT...> element at the bottom of the form with a link, as follows:

    <A HREF="javascript:void checkForm(document.forms[0])">Submit Form</A>

    This link does not have to be inside the <FORM>...</FORM> tag set, because a link is not a form element. That's why the more complete reference to the form (document.forms[0]) is passed as a paramter to the checkForm() function.

  • Page 964: To be in sync with Question 3, the function should be called format(txt).
  • Pages 964 (bottom): For the answer to question 4, the second line has an improper reference to the text field. The field's name should be acc1 in both statements. Only the reference to the form part of the reference is different between the two examples.
  • Pages 966: The answer to question 3 will always return zero because of a one-character flaw in the script. Notice that the string brought in from the text field is converted to upper case in the second statement of the function; but the for loop that inspects every character is looking for a lower case "e".

    To make this work the way it should, you can either convert the text string to all lower case (with the toLowerCase() method) or change the character being sought from "e" to "E". Just another lesson that "case matters" in JavaScript.

    Another error in the script is in the fifth line: the expression inputStr.charAt(i) should be inputString.charAt(i) because the variable holding the uppercased string is inputString. To recap, line 5 of the answer to question 3 should read:
    if (inputString.charAt(i) == "E") {
    Sorry for all the confusion.

Updated Listings

Notes