CD-172 Part VI ✦ Appendixes Listing 15-19b (continued) <INPUT TYPE=”button” VALUE=”Switch On Behavior” onClick=”turnOn()”> Choose a ‘hot’ color: <SELECT NAME=”colorChoice” onChange=”setColor(this, this.value)”> <OPTION VALUE=”red”>red <OPTION VALUE=”blue”>blue <OPTION VALUE=”cyan”>cyan </SELECT><BR> <INPUT TYPE=”button” VALUE=”Switch Off Behavior” onClick=”turnOff()”> <P><INPUT TYPE=”button” VALUE=”Count the URNs” onClick=”showBehaviorCount()”></P> </BODY> </HTML> To turn off the behavior, the removeBehavior() method is invoked. Notice that the removeBehavior() method is associated with the myP object, and the parameter is the ID of the behavior added earlier. If you associate multiple behaviors with an object, you can remove one without disturbing the others because each has its own unique ID. addEventListener(“eventType”, listenerFunc, useCapture) removeEventListener(“eventType”, listenerFunc, useCapture) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓ Example Listing 15-20 provides a compact workbench to explore and experiment with the basic W3C DOM event model. When the page loads, no event listeners are regis- tered with the browser (except for the control buttons, of course). But you can add an event listener for a click event in bubble and/or capture mode to the BODY ele- ment or the P element that surrounds the SPAN holding the line of text. If you add an event listener and click the text, you see a readout of the element processing the event and information indicating whether the event phase is bubbling (3) or cap- ture (1). With all event listeners engaged, notice the sequence of events being pro- cessed. Remove listeners one at a time to see the effect on event processing. elementObject.addEventListener() CD-173 Appendix F ✦ Examples from Parts III and IV Listing 15-20 includes code for event capture that does not operate in NN6. Event capture facilities should work in a future version of the browser. Listing 15-20: W3C Event Lab <HTML> <HEAD> <TITLE>W3C Event Model Lab</TITLE> <STYLE TYPE=”text/css”> TD {text-align:center} </STYLE> <SCRIPT LANGUAGE=”JavaScript”> // add event listeners function addBubbleListener(elemID) { document.getElementById(elemID).addEventListener(“click”, reportEvent, false) } function addCaptureListener(elemID) { document.getElementById(elemID).addEventListener(“click”, reportEvent, true) } // remove event listeners function removeBubbleListener(elemID) { document.getElementById(elemID).removeEventListener(“click”, reportEvent, false) } function removeCaptureListener(elemID) { document.getElementById(elemID).removeEventListener(“click”, reportEvent, true) } // display details about any event heard function reportEvent(evt) { if (evt.target.parentNode.id == “mySPAN”) { var msg = “Event processed at “ + evt.currentTarget.tagName + “ element (event phase = “ + evt.eventPhase + “).\n” document.controls.output.value += msg } } // clear the details textarea function clearTextArea() { document.controls.output.value = “” } </SCRIPT> </HEAD> <BODY ID=”myBODY”> <H1>W3C Event Model Lab</H1> <HR> <P ID=”myP”><SPAN ID=”mySPAN”>This paragraph (a SPAN element nested inside a P element) can be set to listen for “click” events.</SPAN></P> <HR> <TABLE CELLPADDING=5 BORDER=1> <CAPTION STYLE=”font-weight:bold”>Control Panel</CAPTION> Continued Note elementObject.addEventListener() CD-174 Part VI ✦ Appendixes Listing 15-20 (continued) <FORM NAME=”controls”> <TR STYLE=”background-color:#ffff99”><TD ROWSPAN=2>”Bubble”-type click listener: <TD><INPUT TYPE=”button” VALUE=”Add to BODY” onClick=”addBubbleListener(‘myBODY’)”> <TD><INPUT TYPE=”button” VALUE=”Remove from BODY” onClick=”removeBubbleListener(‘myBODY’)”> </TR> <TR STYLE=”background-color:#ffff99”> <TD><INPUT TYPE=”button” VALUE=”Add to P” onClick=”addBubbleListener(‘myP’)”> <TD><INPUT TYPE=”button” VALUE=”Remove from P” onClick=”removeBubbleListener(‘myP’)”> </TR> <TR STYLE=”background-color:#ff9999”><TD ROWSPAN=2>”Capture”-type click listener: <TD><INPUT TYPE=”button” VALUE=”Add to BODY” onClick=”addCaptureListener(‘myBODY’)”> <TD><INPUT TYPE=”button” VALUE=”Remove from BODY” onClick=”removeCaptureListener(‘myBODY’)”> </TR> <TR STYLE=”background-color:#ff9999”> <TD><INPUT TYPE=”button” VALUE=”Add to P” onClick=”addCaptureListener(‘myP’)”> <TD><INPUT TYPE=”button” VALUE=”Remove from P” onClick=”removeCaptureListener(‘myP’)”> </TR> <P>Examine click event characteristics: <INPUT TYPE=”button” VALUE=”Clear” onClick=”clearTextArea()”><BR> <TEXTAREA NAME=”output” COLS=”80” ROWS=”6” WRAP=”virtual”></TEXTAREA> </FORM> </TABLE> </BODY> </HTML> appendChild(elementObject) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓✓ elementObject.appendChild() CD-175 Appendix F ✦ Examples from Parts III and IV Example Scripts in Listing 15-21 demonstrate how the three major child-related methods work in IE5+ and NN6. The page includes a simple, two-item list. A form enables you to add items to the end of the list or replace the last item with a different entry. The append() function creates a new LI element and then uses the appendChild() method to attach the text box text as the displayed text for the item. The nested expression, document.createTextNode(form.input.value), evaluates to a legit- imate node that is appended to the new LI item. All of this occurs before the new LI item is added to the document. In the final statement of the function, appendChild() is invoked from the vantage point of the UL element — thus adding the LI element as a child node of the UL element. Invoking the replaceChild() method in the replace() function utilizes some of the same code. The main difference is that the replaceChild() method requires a second parameter: a reference to the child element to be replaced. This demonstra- tion replaces the final child node of the UL list, so the function takes advantage of the lastChild property of all elements to get a reference to that final nested child. That reference becomes the second parameter to replaceChild(). Listing 15-21: Various Child Methods <HTML> <HEAD> <TITLE>appendChild(), removeChild(), and replaceChild() Methods</TITLE> <SCRIPT LANGUAGE=”JavaScript”> function append(form) { if (form.input.value) { var newItem = document.createElement(“LI”) newItem.appendChild(document.createTextNode(form.input.value)) document.getElementById(“myUL”).appendChild(newItem) } } function replace(form) { if (form.input.value) { var newItem = document.createElement(“LI”) var lastChild = document.getElementById(“myUL”).lastChild newItem.appendChild(document.createTextNode(form.input.value)) document.getElementById(“myUL”).replaceChild(newItem, lastChild) } } function restore() { var oneChild var mainObj = document.getElementById(“myUL”) Continued elementObject.appendChild() CD-176 Part VI ✦ Appendixes Listing 15-21 (continued) while (mainObj.childNodes.length > 2) { oneChild = mainObj.lastChild mainObj.removeChild(oneChild) } } </SCRIPT> </HEAD> <BODY> <H1>Child Methods</H1> <HR> Here is a list of items: <UL ID=”myUL”><LI>First Item <LI>Second Item </UL> <FORM> Enter some text to add/replace in the list: <INPUT TYPE=”text” NAME=”input” SIZE=30><BR> <INPUT TYPE=”button” VALUE=”Append to List” onClick=”append(this.form)”> <INPUT TYPE=”button” VALUE=”Replace Final Item” onClick=”replace(this.form)”> <INPUT TYPE=”button” VALUE=”Restore List” onClick=”restore()”> </BODY> </HTML> The final part of the demonstration uses the removeChild() method to peel away all children of the UL element until just the two original items are left standing. Again, the lastChild property comes in handy as the restore() function keeps removing the last child until only two remain. Upon restoring the list, IE5/Mac fails to render the list bullets; but in the browser’s object model, the UL element still exists. applyElement(elementObject[, type]) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓ Example To help you visualize the impact of the applyElement() method with its different parameter settings, Listing 15-22 enables you to apply a new element (an EM ele- ment) to a SPAN element inside a paragraph. At any time, you can view the HTML of the entire P element to see where the EM element is applied as well as its impact on the element containment hierarchy for the paragraph. elementObject.applyElement() CD-177 Appendix F ✦ Examples from Parts III and IV After you load the page, inspect the HTML for the paragraph before doing anything else. Notice the SPAN element and its nested FONT element, both of which sur- round the one-word content. If you apply the EM element inside the SPAN element (click the middle button), the SPAN element’s first (and only) child element becomes the EM element; the FONT element is now a child of the new EM element. Listing 15-22: Using the applyElement() Method <HTML> <HEAD> <TITLE>applyElement() Method</TITLE> <SCRIPT LANGUAGE=”JavaScript”> function applyOutside() { var newItem = document.createElement(“EM”) newItem.id = newItem.uniqueID document.all.mySpan.applyElement(newItem) } function applyInside() { var newItem = document.createElement(“EM”) newItem.id = newItem.uniqueID document.all.mySpan.applyElement(newItem, “inside”) } function showHTML() { alert(document.all.myP.outerHTML) } </SCRIPT> </HEAD> <BODY> <H1>applyElement() Method</H1> <HR> <P ID=”myP”>A simple paragraph with a <SPAN ID=”mySpan”> <FONT SIZE=+1>special</FONT></SPAN> word in it.</P> <FORM> <INPUT TYPE=”button” VALUE=”Apply <EM> Outside” onClick=”applyOutside()”> <INPUT TYPE=”button” VALUE=”Apply <EM> Inside” onClick=”applyInside()”> <INPUT TYPE=”button” VALUE=”Show <P> HTML ” onClick=”showHTML()”><BR> <INPUT TYPE=”button” VALUE=”Restore Paragraph” onClick=”location.reload()”> </BODY> </HTML> The visible results of applying the EM element inside and outside the SPAN element in this case are the same. But you can see from the HTML results that each element impacts the element hierarchy quite differently. elementObject.applyElement() CD-178 Part VI ✦ Appendixes attachEvent(“eventName“, functionRef) detachEvent(“eventName“, functionRef) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓ Example Use The Evaluator (Chapter 13) to create an anonymous function that is called in response to an onmousedown event of the first paragraph on the page. Begin by assigning the anonymous function to global variable a (already initialized in The Evaluator) in the upper text box: a = new Function(“alert(‘Function created at “ + (new Date()) + “‘)”) The quote marks and parentheses can get jumbled easily, so enter this expression carefully. When you enter the expression successfully, the Results box shows the function’s text. Now assign this function to the onmousedown event of the myP ele- ment by entering the following statement into the upper text box: document.all.myP.attachEvent(“onmousedown”, a) The Results box displays true when successful. If you mouse down on the first paragraph, an alert box displays the date and time that the anonymous function was created (when the new Date() expression was evaluated). Now, disconnect the event relationship from the object by entering the following statement into the upper text box: document.all.myP.detachEvent(“onmousedown”, a) blur() focus() NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓✓ ✓ ✓ ✓✓✓✓ elementObject.blur() CD-179 Appendix F ✦ Examples from Parts III and IV Example To show how both the window.focus() method and its opposite (window.blur()) operate, Listing 15-23 for NN3+ and IE4+ creates a two-window environment. From each window, you can bring the other window to the front. The main window uses the object returned by window.open() to assemble the reference to the new win- dow. In the subwindow (whose content is created entirely on the fly by JavaScript), self.opener is summoned to refer to the original window, while self.blur() operates on the subwindow itself (except for the buggy behavior of NN6 noted ear- lier). Blurring one window and focusing on another window yields the same result of sending the window to the back of the pile. Listing 15-23: The window.focus() and window.blur() Methods <HTML> <HEAD> <TITLE>Window Focus() and Blur()</TITLE> <SCRIPT LANGUAGE=”JavaScript1.1”> // declare global variable name var newWindow = null function makeNewWindow() { // check if window already exists if (!newWindow || newWindow.closed) { // store new window object in global variable newWindow = window.open(“”,””,”width=250,height=250”) // pause briefly to let IE3 window finish opening setTimeout(“fillWindow()”,100) } else { // window already exists, so bring it forward newWindow.focus() } } // assemble new content and write to subwindow function fillWindow() { var newContent = “<HTML><HEAD><TITLE>Another Subwindow</TITLE></HEAD>” newContent += “<BODY bgColor=’salmon’>” newContent += “<H1>A Salmon-Colored Subwindow.</H1>” newContent += “<FORM><INPUT TYPE=’button’ VALUE=’Bring Main to Front’ onClick=’self.opener.focus()’>” // the following button doesn’t work in NN6 newContent += “<FORM><INPUT TYPE=’button’ VALUE=’Put Me in Back’ onClick=’self.blur()’>” newContent += “</FORM></BODY></HTML>” // write HTML to new window document Continued elementObject.blur() CD-180 Part VI ✦ Appendixes Listing 15-23 (continued) newWindow.document.write(newContent) newWindow.document.close() } </SCRIPT> </HEAD> <BODY> <H1>Window focus() and blur() Methods</H1> <HR> <FORM> <INPUT TYPE=”button” NAME=”newOne” VALUE=”Show New Window” onClick=”makeNewWindow()”> </FORM> </BODY> </HTML> A key ingredient to the success of the makeNewWindow() function in Listing 15-23 is the first conditional expression. Because newWind is initialized as a null value when the page loads, that is its value the first time through the function. But after you open the subwindow the first time, newWind is assigned a value (the subwin- dow object) that remains intact even if the user closes the window. Thus, the value doesn’t revert to null by itself. To catch the possibility that the user has closed the window, the conditional expression also sees if the window is closed. If it is, a new subwindow is generated, and that new window’s reference value is reassigned to the newWind variable. On the other hand, if the window reference exists and the window is not closed, the focus() method brings that subwindow to the front. You can see the focus() method for a text object in action in Chapter 25’s descrip- tion of the select() method for text objects. clearAttributes() NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓ Example Use The Evaluator (Chapter 13) to examine the attributes of an element before and after you apply clearAttributes(). To begin, display the HTML for the table ele- ment on the page by entering the following statement into the upper text field: elementObject.clearAttributes() CD-181 Appendix F ✦ Examples from Parts III and IV myTable.outerHTML Notice the attributes associated with the <TABLE> tag. Look at the rendered table to see how attributes such as BORDER and WIDTH affect the display of the table. Now, enter the following statement in the top text box to remove all removable attributes from this element: myTable.clearAttributes() First, look at the table. The border is gone, and the table is rendered only as wide as is necessary to display the content with no cell padding. Lastly, view the results of the clearAttributes() method in the outerHTML of the table again: myTable.outerHTML The source code file has not changed, but the object model in the browser’s mem- ory reflects the changes you made. click() NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓✓ ✓ ✓ ✓✓✓✓ Example Use The Evaluator (Chapter 13) to experiment with the click() method. The page includes various types of buttons at the bottom. You can “click” the checkbox, for example, by entering the following statement in the topmost text field: document.myForm2.myCheckbox.click() If you use a recent browser version, you most likely can see the checkbox change states between checked and unchecked each time you execute the statement. cloneNode(deepBoolean) NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5 Compatibility ✓✓✓ elementObject.cloneNode() . LANGUAGE= JavaScript > function append(form) { if (form.input.value) { var newItem = document.createElement(“LI”) newItem.appendChild(document.createTextNode(form.input.value)) document.getElementById(“myUL”).appendChild(newItem) } } function. (form.input.value) { var newItem = document.createElement(“LI”) var lastChild = document.getElementById(“myUL”).lastChild newItem.appendChild(document.createTextNode(form.input.value)) document.getElementById(“myUL”).replaceChild(newItem,. write HTML to new window document Continued elementObject.blur() CD-180 Part VI ✦ Appendixes Listing 15-23 (continued) newWindow.document.write(newContent) newWindow.document.close() } </SCRIPT> </HEAD> <BODY> <H1>Window