JavaScript & DHTML Cookbook (1st Edition) Support Center


Be kind to your carpal tunnels: Download the examples files from the O'Reilly site. If your text editor doesn't like the (Mac/Unix) text file format of that collection, you can download a pure MS-DOS text file set.

Bonus Recipes

You can find three all-new recipes at the O'Reilly Network site:

Corrections & Updates

  • Page 3 (Introduction). The second syntax example line for creating a regular expression object has an extra space between the 'g' and close double quote. That parameter should be "g".
  • Page 40 (Recipe 2.7). The first script statement in the Solution section is missing a closing parenthesis before the semicolon. The correct statement is:
       var result = Math.floor(Math.random() * (n + 1));
  • Page 66 (Recipe 3.8). The second sentence of the third paragraph (the one following the top code example block) should read:
    If the first value evaluates to a boolean false (e.g., null, undefined, zero, an empty string, and so on), the second value is assigned to the property.
    The distinction is that because a value of zero evaluates to false in a comparison operation, the example constructor function shown in the book would not, for example, allow you to pass a zero as the age parameter and expect some other default value to be assigned if the parameter were empty; passing a zero would cause the other default value to be assigned to the age property. (Despite the unlikely event in the example's context that a co-worker would have an age of zero. And I don't mean the doofus in the next cubicle.)
  • Page 243 (Recipe 9.8). Be sure to heed the instructions to check Recipe 8.11, where I show that the event handler assignment in a text input field calls the keyboard event processing function with a return statement (e.g., <input type="text" onkeypress="return numberOnly(event)" />). When the event handler evaluates to return false (as it does when typing rejected characters), the default action of the field does not occur.
  • Page 294 (Recipe 10.9). The logic of the for loop at the end of the makeTrailMenu() function can insert an extra </a> tag after some entries. The loop should be as follows:
       for (var i = parseStart; i < parseEnd; i++) {
          if (i == parseStart) {
             trail += "/" + leaves[i] + volDelim;
             output += "<a href='" + trail + "' style='" + linkStyle + "'>";
             output += "Home" + "</a>" + separator;
          } else if (i == parseEnd - 1) {
             output += document.title;
          } else {
             trail += leaves[i] + "/";
             output += "<a href='" + trail + "' style='" + linkStyle + "'>";
             output += trailMenu[leaves[i]] + "</a>" + separator;
  • Page 297 (Recipe 10.10). The selector for the first rule of the style sheet code should be .OLRow. Code for this in the downloadable files is correct. But a reader pointed out that if you set some or all of the outline to be expanded as the initial setting, the code provided doesn't set the correct icons for expanded items. An earlier revision I posted here took care of the initial expansion setting, but did not fully handle the icon issue if you invoke expandAll() or collapseAll() functions. Well, I finally got around to fixing that, too. All corrections for both issues are confined to the expandAll(), collapseAll(), and drawOutline() functions of the expandableMenu.js library. You can save/download the newly revised library file.
  • Page 311. An editing mistake in trying to cram a 10-pound statement into a 5-pound space caused a code fragment to be duplicated erroneously. It's all in the second conditional expression within the for loop. The extra fragment is shown below with strikethrough styling:
       if (ol.childNodes[i].childNodes.length > 0 &&
          ol.childNodes[i].childNodes[ol.childNodes[i].childNodes.length - 1].nodeType
          childNodes[i].childNodes.length - 1].nodeType == 3) {

    The code example in the downloadable file is correct.
  • Page 357 (Recipe 12.8). In recent Mozilla releases, the Mozilla proprietary -moz-opacity style property accepts only values between 0 and 1 (inclusive), and no longer percentages. The third code example in the Solution section should be:
       #watermark {-moz-opacity:0.25}
  • Page 394 (Recipe 13.11). The second assignment statement in the setSelectedElem() function of Example 13-4 has a phrase incorrectly duplicated. The statement should simply be:
       var divID = ( && target.src) ? + "Wrap" : "";
  • Page 396 (Recipe 13.11). Due to the way the rest of this recipe is constructed, the initDrag() function of Example 13-4 should not include the branch that invokes the addEventListener() method (in fact, due to the wrong operator being used in the listing's else if branch, the branch never executes anyway). In a more object-oriented embodiment, the addEventListener() method would be applied directly to draggable elements for browsers that support the W3C DOM Event Model (with further adaptation for the IE Event Model). The version shown in the recipe, however, is an easy-to-understand implementation that handles the job well across all DHTML-capable browsers.
  • Page 404ff (Recipe 13.13). The scroll thumb acts weird if the height of text in the scrollable section is less than the height of the viewable area. You can download a revised scrollBars.js file. Corrections are noted by "***" at the end of relevant comments.
  • Page 429. The call to setTimeout() in the bottom code section needs a parameter of the ID of the tbody element being drawn. For the example shown in this recipe, therefore, the statement should be:
       setTimeout("drawTable('matchData')", 1000);
  • Page 434 (Recipe 14.7). The first line of the alternate code example should read:
       txt = document.createTextNode(jsData[i].year);
  • Page 487 (Recipe 15.9). In the large code block of the Discussion section, the name and id of the second <input> element should be date The downloadable files have the right stuff.


  • Recipe 1.7. Reader Nick Fitzsimons from the U.K. provides a compact, non-regular-expression search and replace string function that you can assign to the String object's prototype, thus making it available to all strings. Execute the following statement while the page loads:

       String.prototype.substitute = function(was, becomes) {
          return this.split(was).join(becomes);

    Then, anytime you need to perform a global search-and-replace operation within a string, invoke it via the substitute() method of the string. For example:

       someString.substitute(" is ", " was ");

    This construction is compatible back to Netscape 3 and Internet Explorer 4.

  • Recipe 2.11. The code in Example 2-2 assumes that the dates supplied as arguments to the daysBetween() function come from user-supplied date entries of some kind. But you may want to use the current date as one of the end points of the date range, using the new Date() constructor without any parameters. For the date comparisons to work correctly in this case, the milliseconds value of the two date objects must also be set to zero. The convenient way to accomplish this is to use the optional second parameter to the setSeconds() methods in the daysBetween() function, as in date1.setSeconds(0,0).
  • Recipe 6.8 -- showModalDialog() Issues. Reader Steinar Overbeck Cook from Norway has been kind enough to share his ingenious solutions to some inherent problems in the IE showModalDialog() window with respect to form submission and cookies. These pseudo-windows don't obey all of the rules that regular windows do. Therefore, if you submit a form from a dialog window, the page returned from a server opens a new browser window -- unless you use Steinar's technique. The other problem is that cookies from the main window do not carry over to the dialog window, even when both windows originate from the same domain and server. Once again, Steinar has the solution. Read the details in his JavaScript modalWindow.js library. And many thanks to Steinar for his excellent detective work!
  • Recipe 10.11. As further explanation, the OPML <expansionState> element can contain a comma-delimited list of line numbers of the outline that are to be expanded when the outline initially displays. For example, if you change the line in the head section to read:


    then the first and third nodes of the outline are expanded when the outline first appears.