CD-302 Part VI ✦ Appendixes Listing 16-35 (continued) <SCRIPT LANGUAGE=”JavaScript1.2”> function page(direction) { var pixFrame = parent.display var deltaY = (pixFrame.innerHeight) ? pixFrame.innerHeight : pixFrame.document.body.scrollHeight if (direction == “up”) { deltaY = -deltaY } parent.display.scrollBy(0, deltaY) } function customScroll(form) { parent.display.scrollBy(parseInt(form.x.value), parseInt(form.y.value)) } </SCRIPT> </HEAD> <BODY> <B>ScrollBy Controller</B> <FORM NAME=”custom”> Enter an Horizontal increment <INPUT TYPE=”text” NAME=”x” VALUE=”0” SIZE=4”> and Vertical <INPUT TYPE=”text” NAME=”y” VALUE=”0” SIZE=4”> value.<BR>Then <INPUT TYPE=”button” VALUE=”click to scrollBy()” onClick=”customScroll(this.form)”> <HR> <INPUT TYPE=”button” VALUE=”PageDown” onClick=”page(‘down’)”> <INPUT TYPE=”button” VALUE=”PageUp” onClick=”page(‘up’)”> </FORM> </BODY> </HTML> setCursor(“cursorType”) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓ windowObject.setCursor() CD-303 Appendix F ✦ Examples from Parts III and IV Example Use The Evaluator (Chapter 13) in NN6 to experiment with setting the cursor. After clicking the top text box in preparation for typing, roll the cursor to a location atop an empty spot on the page. Then enter the following statements one at a time into the top text box, and press Enter/Return: setCursor(“wait”) setCursor(“spinning” setCursor(“move”) After evaluating each statement, roll the cursor around the page, and notice where the cursor reverts to its normal appearance. setInterval(“expr”, msecDelay [, language]) setInterval(funcRef, msecDelay [, funcarg1, , funcargn]) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓ ✓✓✓ Example The demonstration of the setInterval() method entails a two-framed environ- ment. The framesetting document is shown in Listing 16-36. Listing 16-36: SetInterval() Demonstration Frameset <HTML> <HEAD> <TITLE>setInterval() Method</TITLE> </HEAD> <FRAMESET ROWS=”50%,50%”> <FRAME SRC=”lst16-37.htm” NAME=”control”> <FRAME SRC=”bofright.htm” NAME=”display”> </FRAMESET> </HTML> windowObject.setInterval() CD-304 Part VI ✦ Appendixes In the top frame is a control panel with several buttons that control the automatic scrolling of the Bill of Rights text document in the bottom frame. Listing 16-37 shows the control panel document. Many functions here control the interval, scrolling jump size, and direction, and they demonstrate several aspects of apply- ing setInterval(). Notice that in the beginning the script establishes a number of global variables. Three of them are parameters that control the scrolling; the last one is for the ID value returned by the setInterval() method. The script needs that value to be a global value so that a separate function can halt the scrolling with the clearInterval() method. All scrolling is performed by the autoScroll() function. For the sake of simplicity, all controlling parameters are global variables. In this application, placement of those values in global variables helps the page restart autoscrolling with the same parameters as it had when it last ran. Listing 16-37: setInterval() Control Panel <HTML> <HEAD> <TITLE>ScrollBy Controller</TITLE> <SCRIPT LANGUAGE=”JavaScript1.2”> var scrollSpeed = 500 var scrollJump = 1 var scrollDirection = “down” var intervalID function autoScroll() { if (scrollDirection == “down”) { scrollJump = Math.abs(scrollJump) } else if (scrollDirection == “up” && scrollJump > 0) { scrollJump = -scrollJump } parent.display.scrollBy(0, scrollJump) if (parent.display.pageYOffset <= 0) { clearInterval(intervalID) } } function reduceInterval() { stopScroll() scrollSpeed -= 200 startScroll() } function increaseInterval() { windowObject.setInterval() CD-305 Appendix F ✦ Examples from Parts III and IV stopScroll() scrollSpeed += 200 startScroll() } function reduceJump() { scrollJump -= 2 } function increaseJump() { scrollJump += 2 } function swapDirection() { scrollDirection = (scrollDirection == “down”) ? “up” : “down” } function startScroll() { parent.display.scrollBy(0, scrollJump) if (intervalID) { clearInterval(intervalID) } intervalID = setInterval(“autoScroll()”,scrollSpeed) } function stopScroll() { clearInterval(intervalID) } </SCRIPT> </HEAD> <BODY onLoad=”startScroll()”> <B>AutoScroll by setInterval() Controller</B> <FORM NAME=”custom”> <INPUT TYPE=”button” VALUE=”Start Scrolling” onClick=”startScroll()”> <INPUT TYPE=”button” VALUE=”Stop Scrolling” onClick=”stopScroll()”><P> <INPUT TYPE=”button” VALUE=”Shorter Time Interval” onClick=”reduceInterval()”> <INPUT TYPE=”button” VALUE=”Longer Time Interval” onClick=”increaseInterval()”><P> <INPUT TYPE=”button” VALUE=”Bigger Scroll Jumps” onClick=”increaseJump()”> <INPUT TYPE=”button” VALUE=”Smaller Scroll Jumps” onClick=”reduceJump()”><P> <INPUT TYPE=”button” VALUE=”Change Direction” onClick=”swapDirection()”> </FORM> </BODY> </HTML> The setInterval() method is invoked inside the startScroll() function. This function initially “burps” the page by one scrollJump interval so that the test in autoScroll() for the page being scrolled all the way to the top doesn’t halt a page from scrolling before it gets started. Notice, too, that the function checks for the existence of an interval ID. If one is there, it is cleared before the new one is set. This is crucial within the design of the example page, because repeated clicking of the Start Scrolling button triggers multiple interval timers inside the browser. Only windowObject.setInterval() CD-306 Part VI ✦ Appendixes the most recent one’s ID would be stored in intervalID, allowing no way to clear the older ones. But this little side trip makes sure that only one interval timer is running. One of the global variables, scrollSpeed, is used to fill the delay parame- ter for setInterval(). To change this value on the fly, the script must stop the current interval process, change the scrollSpeed value, and start a new process. The intensely repetitive nature of this application is nicely handled by the setInterval() method. setTimeout(“expr”, msecDelay [, language]) setTimeout(functionRef, msecDelay [, funcarg1, , funcargn]) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓✓ ✓ ✓ ✓✓✓✓ Example When you load the HTML page in Listing 16-38, it triggers the updateTime() func- tion, which displays the time (in hh:mm am/pm format) in the statusbar. Instead of showing the seconds incrementing one by one (which may be distracting to some- one trying to read the page), this function alternates the last character of the dis- play between an asterisk and nothing, like a visual “heartbeat.” Listing 16-38: Display the Current Time <HTML> <HEAD> <TITLE>Status Bar Clock</TITLE> <SCRIPT LANGUAGE=”JavaScript”> <! var flasher = false // calculate current time, determine flasher state, // and insert time into status bar every second function updateTime() { var now = new Date() var theHour = now.getHours() var theMin = now.getMinutes() var theTime = “” + ((theHour > 12) ? theHour - 12 : theHour) theTime += ((theMin < 10) ? “:0” : “:”) + theMin theTime += (theHour >= 12) ? “ pm” : “ am” theTime += ((flasher) ? “ “ : “*”) windowObject.setTimeout() CD-307 Appendix F ✦ Examples from Parts III and IV flasher = !flasher window.status = theTime // recursively call this function every second to keep timer going timerID = setTimeout(“updateTime()”,1000) } // > </SCRIPT> </HEAD> <BODY onLoad=”updateTime()”> </BODY> </HTML> In this function, the setTimeout() method works in the following way: Once the current time (including the flasher status) appears in the statusbar, the function waits approximately one second (1,000 milliseconds) before calling the same func- tion again. You don’t have to clear the timerID value in this application because JavaScript does it for you every time the 1,000 milliseconds elapse. A logical question to ask is whether this application should be using setInterval() instead of setTimeout(). This is a case in which either one does the job. To use setInterval() here would require that the interval process start outside of the updateTime() function, because you need only one process running that repeatedly calls updateTime(). It would be a cleaner implementation in that regard, instead of the tons of timeout processes spawned by Listing 16-38. On the other hand, the appli- cation would not run in any browsers before NN4 or IE4, as Listing 16-38 does. To demonstrate passing parameters, you can modify the updateTime() function to add the number of times it gets invoked to the display in the statusbar. For that to work, the function must have a parameter variable so that it can catch a new value each time it is invoked by setTimeout()’s expression. For all browsers, the func- tion would be modified as follows (unchanged lines are represented by the ellipsis): function updateTime(i) { window.status = theTime + “ (“ + i + “)” // pass updated counter value with next call to this function timerID = setTimeout(“updateTime(“ + i+1 + “)”,1000) } If you were running this exclusively in NN4+, you could use its more convenient way of passing parameters to the function: timerID = setTimeout(updateTime,1000, i+1) windowObject.setTimeout() CD-308 Part VI ✦ Appendixes In either case, the onLoad event handler would also have to be modified to get the ball rolling with an initial parameter: onLoad = “updateTime(0)” One warning about setTimeout() functions that dive into themselves as fre- quently as this one does: Each call eats up a bit more memory for the browser application in Navigator 2. If you let this clock run for a while, some browsers may encounter memory difficulties, depending on which operating system they’re using. But considering the amount of time the typical user spends on Web pages (even if only 10 or 15 minutes), the function shouldn’t present a problem. And any reloading invoked by the user (such as by resizing the window in Navigator 2) frees up memory once again. showModalDialog(“URL”[, arguments] [, features]) showModelessDialog(“URL”[, arguments] [, features]) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility (✓) ✓✓ Example To demonstrate the two styles of dialog boxes, I have implemented the same func- tionality (setting some session visual preferences) for both modal and modeless dialog boxes. This tactic shows you how to pass data back and forth between the main page and both styles of dialog box windows. The first example demonstrates how to use a modal dialog box. In the process, data is passed into the dialog box window and values are returned. Listing 16-39 is the HTML and scripting for the main page. A button’s onClick event handler invokes a function that opens the modal dialog box. The dialog box’s document (Listing 16-40) contains several form elements for entering a user name and selecting a few color styles for the main page. Data from the dialog is fashioned into an array to be sent back to the main window. That array is initially assigned to a local variable, prefs, as the dialog box closes. If the user cancels the dialog box, the returned value is an empty string, so nothing more in getPrefsData() executes. But when the user clicks OK, the array comes back. Each of the array items is read and assigned to its respective form value or style property. These values are also preserved in the global currPrefs array. This allows the settings to be sent to the modal dialog box (as the second parameter to showModalDialog()) the next time the dialog box is opened. Caution windowObject.showModalDialog() CD-309 Appendix F ✦ Examples from Parts III and IV Listing 16-39: Main Page for showModalDialog() <HTML> <HEAD> <TITLE>window.setModalDialog() Method</TITLE> <SCRIPT LANGUAGE=”JavaScript”> var currPrefs = new Array() function getPrefsData() { var prefs = showModalDialog(“lst16-40.htm”, currPrefs, “dialogWidth:400px; dialogHeight:300px”) if (prefs) { if (prefs[“name”]) { document.all.firstName.innerText = prefs[“name”] currPrefs[“name”] = prefs[“name”] } if (prefs[“bgColor”]) { document.body.style.backgroundColor = prefs[“bgColor”] currPrefs[“bgColor”] = prefs[“bgColor”] } if (prefs[“textColor”]) { document.body.style.color = prefs[“textColor”] currPrefs[“textColor”] = prefs[“textColor”] } if (prefs[“h1Size”]) { document.all.welcomeHeader.style.fontSize = prefs[“h1Size”] currPrefs[“h1Size”] = prefs[“h1Size”] } } } function init() { document.all.firstName.innerText = “friend” } </SCRIPT> </HEAD> <BODY BGCOLOR=”#eeeeee” STYLE=”margin:20px” onLoad=”init()”> <H1>window.setModalDialog() Method</H1> <HR> <H2 ID=”welcomeHeader”>Welcome, <SPAN ID=”firstName”> </SPAN>!</H2> <HR> <P>Use this button to set style preferences for this page: <BUTTON ID=”prefsButton” onClick=”getPrefsData()”> Preferences </BUTTON> </BODY> </HTML> windowObject.showModalDialog() CD-310 Part VI ✦ Appendixes The dialog box’s document, shown in Listing 16-40, is responsible for reading the incoming data (and setting the form elements accordingly) and assembling form data for return to the main window’s script. Notice when you load the example that the TITLE element of the dialog box’s document appears in the dialog box window’s title bar. When the page loads into the dialog box window, the init() function examines the window.dialogArguments property. If it has any data, the data is used to pre-set the form elements to mirror the current settings of the main page. A utility function, setSelected(), pre-selects the option of a SELECT element to match the current settings. Buttons at the bottom of the page are explicitly positioned to be at the lower-right corner of the window. Each button invokes a function to do what is needed to close the dialog box. In the case of the OK button, the handleOK() function sets the window.returnValue property to the data that come back from the getFormData() function. This latter function reads the form element values and packages them in an array using the form elements’ names as array indices. This helps keep everything straight back in the main window’s script, which uses the index names, and is there- fore not dependent upon the precise sequence of the form elements in the dialog box window. Listing 16-40: Document for the Modal Dialog <HTML> <HEAD> <TITLE>User Preferences</TITLE> <SCRIPT LANGUAGE=”JavaScript”> // Close the dialog function closeme() { window.close() } // Handle click of OK button function handleOK() { window.returnValue = getFormData() closeme() } // Handle click of Cancel button function handleCancel() { window.returnValue = “” closeme() } // Generic function converts form element name-value pairs // into an array windowObject.showModalDialog() CD-311 Appendix F ✦ Examples from Parts III and IV function getFormData() { var form = document.prefs var returnedData = new Array() // Harvest values for each type of form element for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].type == “text”) { returnedData[form.elements[i].name] = form.elements[i].value } else if (form.elements[i].type.indexOf(“select”) != -1) { returnedData[form.elements[i].name] = form.elements[i].options[form.elements[i].selectedIndex].value } else if (form.elements[i].type == “radio”) { returnedData[form.elements[i].name] = form.elements[i].value } else if (form.elements[i].type == “checkbox”) { returnedData[form.elements[i].name] = form.elements[i].value } else continue } return returnedData } // Initialize by setting form elements from passed data function init() { if (window.dialogArguments) { var args = window.dialogArguments var form = document.prefs if (args[“name”]) { form.name.value = args[“name”] } if (args[“bgColor”]) { setSelected(form.bgColor, args[“bgColor”]) } if (args[“textColor”]) { setSelected(form.textColor, args[“textColor”]) } if (args[“h1Size”]) { setSelected(form.h1Size, args[“h1Size”]) } } } // Utility function to set a SELECT element to one value function setSelected(select, value) { for (var i = 0; i < select.options.length; i++) { if (select.options[i].value == value) { select.selectedIndex = i break } } return } // Utility function to accept a press of the // Enter key in the text field as a click of OK Continued windowObject.showModalDialog() . CD-302 Part VI ✦ Appendixes Listing 16-35 (continued) <SCRIPT LANGUAGE= JavaScript1 .2”> function page(direction) { var pixFrame = parent.display var. Examples from Parts III and IV Listing 16-39: Main Page for showModalDialog() <HTML> <HEAD> <TITLE>window.setModalDialog() Method</TITLE> <SCRIPT LANGUAGE= JavaScript > var. SRC=”bofright.htm” NAME=”display”> </FRAMESET> </HTML> windowObject.setInterval() CD-304 Part VI ✦ Appendixes In the top frame is a control panel with several buttons that control the automatic scrolling