Using Window s Objects
Window objects have been added to the HTML specification as part of HTML5. Before then, it was an informal standard. Each browser has implemented a set of essentially the same functionality and is usually consistent. In the HTML5 specification, Windows objects encapsulate functionality that is already a de facto standard and include some enhancements. The implementation of this object is not uniform, and different browsers follow it differently.
The Window object has become a dump-like place, stacking up many functions that are not suitable for other places. As we walk through the function of this object, you will understand what I mean.
Get Window Object
Window objects can be obtained in two ways. The normal HTML5 approach is to use the defaultview attribute on the Document object. Another is to use the global variable window, which is supported by all browsers. Code Listing 1 demonstrates both approaches.
Code Listing 1 Getting Window Objects
<!DOCTYPE HTML> <html> <head> <title>Obtain Widow object</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body id=""> <table> <tr><th>Outer Width:</th><td id="HZH_width"></td></tr> <tr><td>Outer height:</td><td id="HZH_height"></td></tr> </table> <script type="text/javascript"> document.getElementById("HZH_width").innerHTML = window.outerWidth; document.getElementById("HZH_height").innerHTML = document.defaultView.outerHeight; </script> </body> </html>
I use the Window object in my script to read the values of a pair of attributes, outerWidth and outerHeight.
Get window information
As the name implies, the basic function of a Window object involves the window displayed in the current document. The following table lists the attributes and methods that operate these functions. For HTML, a tab in a browser window is considered the window itself.
Window Related Members
Name | Explain | Return |
---|---|---|
innerHeight | Get the height of the window content area | numerical value |
innerWidth | Gets the width of the window content area | numerical value |
outerHeight | Get the height of the window, including borders, menu bars, etc. | numerical value |
outerWidth | Gets the width of the window, including borders, menu bars, etc. | numerical value |
pageXOffset | Gets the number of pixels the window scrolls horizontally from the top left corner | numerical value |
pageYOffset | Gets the number of pixels the window scrolls vertically from the top left corner | numerical value |
screen | Returns a Screen object describing the screen | Screen |
screenLeft,screenX | Gets the number of pixels from the left edge of the window to the left edge of the screen (not all browsers implement both attributes at the same time, or calculate this value the same way) | numerical value |
screenTop,screenY | Gets the number of pixels from the top edge of the window to the edge of the screen (not all browsers implement both attributes at the same time, or calculate this value the same way) | numerical value |
Code Listing 2 shows how to use these properties to get window information
Code Listing 2 Get Window Information
<!DOCTYPE HTML> <html> <head> <title>Get window information</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> table { border-collapse: collapse; border: thin solid black;} th, td {padding: 4px;} </style> </head> <body> <table border="1"> <tr> <th>Outer Width:</th><td id="HZH_ow"></td><th>Outer height:</th><td id="HZH_oh"></td> </tr> <tr> <th>Inner Width:</th><td id="HZH_iw"></td><th>Inner Width:</th><td id="HZH_ih"></td> </tr> <tr> <th>Screen width:</th><td id="HZH_sw"></td> <th>Screen height:</th><td id="HZH_sh"></td> </tr> </table> <script type="text/javascript"> document.getElementById("HZH_ow").innerHTML = window.outerWidth; document.getElementById("HZH_oh").innerHTML = window.outerHeight; document.getElementById("HZH_iw").innerHTML = window.innerHeight; document.getElementById("HZH_ih").innerHTML = window.innerHeight; document.getElementById("HZH_sw").innerHTML = window.screen.width; document.getElementById("HZH_sh").innerHTML = window.screen.height; </script> </body> </html>
The script in the example above shows the values of various Windows properties in a table. Notice that I used the screen property to get a Screen object. This object provides screen information to display this Window and defines the properties shown in the table below.
Properties of Screen Object
Name | Explain | Return |
---|---|---|
availHeight | The height of the part of the window that can be displayed on the screen (excluding toolbars, menu bars, etc.) | numerical value |
availWidth | Width of the part of the window on the screen that can be displayed (excluding toolbars and menu bars, etc.) | numerical value |
colorDepth | The color depth of the screen | numerical value |
height | Screen Height | numerical value |
width | Width of screen | numerical value |
Interact with windows
Window objects provide a set of methods for interacting with windows containing documents. The following table describes these methods.
Window s Interaction
Name | Explain | Return |
---|---|---|
blur() | Lose keyboard focus on Windows | void |
close() | Close the window (not all browsers allow a script to close the window) | void |
focus() | Keyboard focus for windows | void |
print() | Prompt user to print page | void |
scrollBy(<x>, <y>) | Scroll the document relative to its current location | void |
scrollTo(<x>, <y>) | Scroll to specified location | void |
stop() | Stop loading the document | void |
All these methods should be used with caution, as they can cause users to lose control of the browser window. Users have fairly fixed expectations about what the application should do, and windows that scroll, print, and close themselves are generally not welcome. If you have to use these methods, give the user control and provide a very clear visual cue to tell them what is going to happen.
Listing 3 shows the use of some window interaction methods.
Code List 3 Interacts with Window
<!DOCTYPE HTML> <html> <head> <title>Interact with windows</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> #HZH_EasonChan { width: 329px; height: 329px; } #HZH_SteveChou { width: 282px; height: 500px; } </style> </head> <body> <p> <button id="HZH_scroll">Huang Zihan makes it roll screen</button> <button id="HZH_print">Huang Zi Han Makes It Print</button> <button id="HZH_close">Huang Zi Han Makes It Close</button> </p> <p> White as white teeth Passion engulfed champagne volatilized thoroughly early <br> White moths sneak back into the world and overlook spiritual sites <br> But when love suddenly turns mustard into a mess, don't mention it <br> Silence with smile Rose with prick Only trust defence <br> <img id="HZH_EasonChan" src="http://120.77.46.246/src/img/EasonChan.jpeg "alt=" Chen Yixun "> <br> I am the locked window of my heart<br> Let the cold wind come and go<br> Wind and frost that can't be repaired these years<br> Looks particularly bleak<br> Past sadness stirred by the wind<br> Like a season-long cheap revelry<br> <img id="HZH_SteveChou" src="http://120.77.46.246/src/img/SteveChou.jpeg "alt=" Zhou Chuanxiong "> </p> <script> var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++) { buttons[i].onclick = handleButtonPress; } function handleButtonPress(e) { if (e.target.id == "HZH_print") { window.print(); } else if (e.target.id == "HZH_close") { window.close(); } else { window.scrollTo(0, 800); } } </script> </body> </html>
Prints, closes, and scrolls windows as feedback on the user pressing the button.
Prompt the user
The Window s object contains a set of methods that prompt users in different ways, as shown in the table below.
Prompt function
Name | Explain | Return |
---|---|---|
alert(<msg>) | Show the user a dialog window and wait for it to close | void |
confirm(<msg>) | Show a dialog window with confirmation and cancellation prompts | Boolean Value |
prompt(<msg>, <val>) | Displays a dialog prompting the user to enter a value | Character string |
showModalDialog(<url>) | Pop up a window showing the specified URL | void |
Each of these methods presents a distinct type of prompt. Code Listing 4 demonstrates how to use them.
Code Listing 4 prompts the user
<!DOCTYPE HTML> <html> <head> <title>Prompt the user</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> table { border-collapse: collapse; border: thin solid black;} th, td { padding: 4px;} </style> </head> <body> <button id="HZH_alert">Alert of Huang Zihan</button> <button id="HZH_confirm">Confirmation of Huangzi Implication</button> <button id="HZH_prompt">Tips of Huangzi Implication</button> <button id="HZH_modal">Dialogue Box of Huang Zihan</button> <script type="text/javascript"> var buttons = document.getElementsByTagName("button"); for(var i = 0 ; i < buttons.length; i++) { buttons[i].onclick = handleButtonPress; } function handleButtonPress(e) { if (e.target.id == "HZH_alert") { window.alert("This is a warning from Huang Zihan!"); } else if (e.target.id == "HZH_confirm") { var confirmed = window.confirm("This is the confirmation of Huang Zicon-Do you want to continue?"); alert("Confirmed? " + confirmed); } else if (e.target.id == "HZH_prompt") { var response = window.prompt("Huang Zihan, please enter a word", "Incandescent teenager"); alert("The word was " + response); } else if (e.target.id == "HZH_modal") { window.showModalDialog("http://120.77.46.246"); } } </script> </body> </html>
These features should be used with caution. Browsers handle prompts in different ways, which can give users different experiences.
Consider the example below that shows the different ways Chrome and Firefox browsers display alert prompts. The two tips may look similar, but the effect is very different. Chrome follows the specification literally, creating a modal dialog box. This means that the browser will do nothing but wait for the user to click the OK button to close the window. The user cannot switch tabs, close the current tab, or do anything else on the browser. Firefbx browsers take a more relaxed approach, limiting the scope of prompts to the current tab. This is a more reasonable approach, but it is a different one, and inconsistency is one that needs careful consideration when choosing functionality for Web applications.
[Click to see effect] Prompt users
The showModalDialog method creates a pop-up window (a feature that has been heavily abused by advertisers). In fact, it is so abused that all browsers restrict this functionality to only sites that users have previously approved. If you rely on pop-ups to provide users with critical information, you run the risk of not seeing it at all.
Tips
If you want to draw users'attention, consider using inline dialogs provided by JavaScript libraries such as jQuery. They are easy to use, less intrusive, and have consistent behavior and appearance across browsers.
Get basic information
Window objects allow you to access objects that return basic information, including details of the current address (that is, the source URL from which the document was loaded) and the user's browsing history. The following table describes these properties.
Object properties that provide information
Name | Explain | Return |
---|---|---|
document | Returns the Document object associated with this window | Document |
history | Provide access to browser history | History |
location | Provide details of the current document address | Location |
The Location object returned by the Window.location property is the same as that returned by the Document.location property. Let's take a look at how to use browser history.
Use browser history
The Window.history property returns a History object that you can use to perform some basic operations on browser history. The following table describes some properties and methods of the History object definition.
Properties and methods of the History object
Name | Explain | Return |
---|---|---|
back() | Step back in browsing history | void |
forward() | Take a step forward in browsing history | void |
go(<index>) | Go to a browsing history location relative to the current document. Positive is forward, negative is backward | void |
length | Returns the number of items in the browsing history | numerical value |
pushState(<state>, <title>, <url>) | Add an entry to browser history | void |
replaceState(<state>, <title>, <url>) | Replace the current entry in browser history | void |
state | Returns the status data in the browser history associated with the current document | object |
Navigate through browsing history
The three methods back, forward, and go tell the browser which URL in the browsing history it should navigate to. The effect of the back/forward method is consistent with the browser's back/forward button. The go method navigates to a browsing historical location relative to the current document. Positive values indicate that the browser should go forward in the browsing history, while negative values indicate that it should go back. The size of the value specifies the specific number of steps. For example, -2 tells the browser to navigate to the document before the most recent browsing history. Code Listing 5 demonstrates how to use these three methods.
Code Listing 5 navigates through browser history
<!DOCTYPE HTML> <html> <head> <title>Navigate through browser history</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <button id="HZH_back">Huang Zi Han Makes it Backward</button> <button id="HZH_forward">Huang Zihan makes it go forward</button> <button id="HZH_go">This seems to be invalid</button> <script type="text/javascript"> var buttons = document.getElementsByTagName("button"); for (var i = 0; i < buttons.length; i++) { buttons[i].onclick = handleButtonPress; } function handleButtonPress(e) { if (e.target.id == "HZH_back") { window.history.back(); } else if (e.target.id == "HZH_forward") { window.history.forward(); } else if (e.target.id == "HZH_go") { window.history.go("http://120.77.46.246"); } } </script> </body> </html>
Navigate through browser history
In addition to these basic functions, HTML5 supports modifying browser history under certain constraints. The best way to illustrate this is to show an example of a problem that can be solved by modifying the browsing history, as shown in Listing 6.
Code Listing 6 Handles Browser History
<!DOCTYPE HTML> <html> <head> <title>Processing browser history</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p id="HZH_msg"></p> <button id="HZH_CyndiWang">Wang Xinling</button> <button id="HZH_Beyond">Beyond</button> <script type="text/javascript"> var sel = "Huang Zihan reminds you! You haven't chosen yet!"; document.getElementById("HZH_msg").innerHTML = sel; var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++) { buttons[i].onclick = function(e) { document.getElementById("HZH_msg").innerHTML = e.target.innerHTML; }; } </script> </body> </html>
[Click to see effect] Processing browser history
This example contains a script that displays a corresponding message based on the button clicked by the user. It is very simple. The problem is that when the user leaves the sample document, the information about the clicked button is lost. You can see this below.
The sequence of events is as follows:
- (1) Navigate to the sample document and display the message No selection made;
- (2) Click the Banana button, and now the message is Banana;
- (3) Navigate to http://apress.com ;
- (4) Click the back button to return to the sample document.
At the end of this series of events, I go back to the sample document, but there are no previously selected records. This is the general behavior of browsers, which handle browsing history using URLs. When I click the Back button, the browser returns to the URL of the sample document, and I need to start over. This session history looks like this:
Insert an entry into the browsing history
The History.pushState method allows us to add a URL to browser history with some restrictions. The server name and port number of the URL must be the same as the current document. One way to add URLs is to use only the query string or anchor fragment attached to the current document, as shown in code listing 7.
Code Listing 7 adds an entry to browser history
<!DOCTYPE HTML> <html> <head> <title>Add an entry to browser history</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p id="HZH_msg"></p> <button id="HZH_jay_chou">Jay Chou</button> <button id="HZH_Jordanchan">Jordan Chan</button> <script type="text/javascript"> var sel = "Huang Zihan reminds you! You haven't chosen yet!"; if (window.location.search == "?HZH_jay_chou") { sel = "You chose Jay Chou"; } else if (window.location.search == "?HZH_Jordanchan") { sel = "You chose Chen Xiaochun"; } document.getElementById("HZH_msg").innerHTML = sel; var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++) { buttons[i].onclick = function(e) { document.getElementById("HZH_msg").innerHTML = e.target.innerHTML; window.history.pushState("", "", "?" + e.target.id); }; } </script> </body> </html>
The script in this example uses the pushState method to add an entry to the browser history. It adds the URL of the current document plus a query string identifying which button the user clicked. I also added some code to use the Location object to read the query string and the selected value. This script brings two changes that users can recognize. The first one appears when the user clicks on a button, as shown below.
Add an entry to the browser history
When the user clicks the Banana button, the URL that I push into the browser's history is displayed in the browser's navigation bar. The document has not been reloaded, only the browsing history and displayed URLs have changed. At this point, browser history looks like this:
When a user clicks a button, a new URL is added to the browsing history to create an entry to record the user's navigation path. The benefits of these additional entries are shown below when the user navigates elsewhere and returns to the document.
Add entries for different documents
When you add entries to browser history, you don't need to be limited to query strings or document fragments as URLs. You can specify any URL as long as it comes from the same source as the current document. However, there is one special point to note. Code Listing 8 demonstrates this.
Code Listing 8 uses different URL s in browsing history entries
<!DOCTYPE HTML> <html> <head> <title>Use different in browser entries URL</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p id="HZH_msg"></p> <button id="HZH_LowellLo">Luguanyan</button> <button id="HZH_AlanTam">Tan Yonglin</button> <script type="text/javascript"> var sel = "Huang Zihan reminds you! You haven't chosen yet!"; if (window.location.search == "?HZH_AlanTam") { sel = "You chose Tan Yonglin"; } else if (window.location.search == "?HZH_LowellLo") { sel = "You chose Luguanyan"; } document.getElementById("HZH_msg").innerHTML = sel; var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++) { buttons[i].onclick = function(e) { document.getElementById("HZH_msg").innerHTML = e.target.innerHTML; window.history.pushState("", "", "http://120.77.46.246/ZihanGroup/FBG/HTML_AG/chap27/code09.html?" + e.target.id); }; } </script> </body> </html>
[Click to see effect] Use different URL s in browser entries
This script has only one change: I set the URL parameter of the pushState method to otherpage.html. Code Listing 9 lists the contents of otherpage.html.
Content of code listing 9 otherpage.html
<!DOCTYPE HTML> <html> <head> <title>otherpage.html</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h1>Other Pages</h1> <p id="HZH_msg"></p> <script> var sel = "Huang Zihan reminds you! You haven't chosen yet!"; if (window.location.search == "?HZH_AlanTam") { sel = "You chose Tan Yonglin"; } else if (window.location.search == "?HZH_LowellLo") { sel = "You chose Luguanyan"; } document.getElementById("HZH_msg").innerHTML = sel; </script> </body> </html>
I still use the query string to save the user's choices, but the document itself has changed. What's special about it now is that. The results you will get when you run this example are shown below.
[Click to see effect] otherpage.html
As shown above, the navigation box shows the URL of another document, but the document itself has not changed. The trap is here: if the user navigates to another document and clicks the back button, the browser can choose whether to display the original document (example.html in this case) or the specified document (otherpage.html). You have no control over which browser it displays, and worse, different browsers handle it differently.
Save complex state in browsing history
Note that when I used the pushState method in the previous examples, I used an empty string (") for the first two parameters. This parameter is ignored by all major browsers, let alone mention it here. However, the first parameter may be useful because it allows you to associate URL s with a complex state object in browser history.
In the previous example, I used a query string to represent the user's selection. It's possible to use it for such a simple piece of data, but it won't help if you want to save more complex data. Code Listing 10 demonstrates how to save more complex data with the first parameter of pushState.
Code List 10 Save State Pair in Browser History
<!DOCTYPE HTML> <html> <head> <title>Save state objects in browser history</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> * { margin: 2px; padding: 4px; border-collapse: collapse;} </style> </head> <body> <table border="1"> <tr><th>Name:</th><td id="HZH_name"></td></tr> <tr><th>Height:</th><td id="HZH_height"></td></tr> <tr><th>Weight:</th><td id="HZH_weight"></td></tr> <tr><th>Status:</th><td id="HZH_state"></td></tr> <tr><th>Event:</th><td id="HZH_event"></td></tr> </table> <button id="HZH_PriscillaChan">Chen Huixian</button> <button id="HZH_AlexFong">Fang Lishen</button> <script type="text/javascript"> if (window.history.state) { displayState(window.history.state); document.getElementById("HZH_state").innerHTML = "Yes"; } else { document.getElementById("HZH_name").innerHTML = "Huang Zihan reminds you! You haven't chosen yet!"; } window.onpopstate = function(e) { displayState(e.state); document.getElementById("HZH_event").innerHTML = "Yes"; } var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++) { buttons[i].onclick = function(e) { var stateObj; if (e.target.id == "HZH_PriscillaChan") { stateObj = { HZH_name: "Chen Huixian", HZH_height: "158cm", HZH_weight: "42kg" } } else { stateObj = { HZH_name: "Fang Lishen", HZH_height: "175cm", HZH_weight: "68kg" } } window.history.pushState(stateObj, ""); displayState(stateObj); }; } function display(stateObj) { document.getElementById("HZH_name").innerHTML = stateObj.HZH_name; document.getElementById("HZH_height").innerHTML = stateObj.HZH_height; document.getElementById("HZH_weight").innerHTML = stateObj.HZH_weight; } </script> </body> </html>
In this example, I use an object to represent the user's choice. It has three attributes: the name, color and size of the fruit selected by the user, like this:
stateObj = { name: "apple", color: "red", size: "medium"}
When the user makes a choice, I create a new browsing history entry using the History.pushState method and associate it with the state object, like this:
window.history.pushState(stateObj, "");
I did not specify a URL in this example, which means the state object is related to the current document. (I did this to demonstrate possibilities. I could have specified a URL like the previous example.)
When the user returns to your document, there are two ways to retrieve the state object. The first is through the history.state property, like this:
... if (window.history.state) { displayState(window.history.state); ...
The problem you face at this point is that not all browsers support getting state objects through this property (as Chrome does not). To solve this problem, you must also listen for popstate events. This example is important for using the Browse History function. The following code listens for and responds to popstate events:
window.onpopstate = function(e) { displayState(e.state); document.getElementById("event").innerHTML = "Yes"; }
Notice that I display state information in a table element, adding details about whether the state object is retrieved through attributes or events. You can see it below, but the best way to understand this example is to experiment with it yourself.
Save state objects in browser history
warning
Attention must be taken to avoid the presence of dependent state information. Browser history is lost in many cases, including when the user intentionally deletes it.
Replace entries in browsing history
Previous examples have focused on adding entries to the browsing history of the current document, but you can also use the replaceState method to replace entries for the current document. Code Listing 11 demonstrates this.
Code Listing 11 replaces the current entry in browser history
<!DOCTYPE HTML> <html> <head> <title>Replace the current entry in browser history</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <P id="HZH_msg"></P> <button id="HZH_AndyLau">Lau Andy</button> <button id="HZH_StefanieSun">Sun Yanzi</button> <script type="text/javascript"> var sel = "Huang Zihan reminds you! You haven't chosen yet!"; if (window.location.search == "?HZH_AndyLau") { sel = "You chose Andy Lau."; } else if (window.location.search == "?HZH_StefanieSun") { sel = "You chose Sun Yanzi."; } document.getElementById("HZH_msg").innerHTML = sel; var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++) { buttons[i].onclick = function(e) { document.getElementById("HZH_msg").innerHTML = e.target.innerHTML; window.history.replaceState("", "", "otherpage?" + e.target.id); }; } </script> </body> </html>
Replace the current entry in browser history
Use cross-document messaging
The Window object also provides an entry for another new HTML5 feature called cross-document messaging. Typically, scripts from different sources (known as "origins") are not allowed to communicate, but the need for inter-script communication is so strong that numerous patches and workarounds have emerged to bypass the browser's security precautions.
Understanding the source of scripts
Browsers use the components of a URL to determine the source of a resource, such as a script. Interaction and communication constraints are imposed between scripts from different sources. If the protocol, host name, and port number of the two scripts are the same, they are considered to have the same source, even if the other parts of the URL are different. The following table gives some examples, each of which is http://titan.mydomain.com/example.html This URL is compared.
URL | junction fruit |
---|---|
http://titan.mydomain.com/apps/other.html | Same source |
https://titan.mydomain.com/apps/other.html | Different sources, inconsistent protocols |
http://titan:81.mydomain.com/apps/example.html | Different sources, inconsistent port numbers |
http://myserver.mydomain.com/doc.html | Different sources, different hosts |
Scripts can use the document.domain property to change their source, but they can only extend the coverage of the current URL. For example, from http://server1.domain.com and http://server2.domain.com Both scripts can set their domain property to domain.com to get the same source.
HTML5 provides a specification for this type of communication through methods in Window s, as shown in the table below.
Cross-document messaging methods
Name | Explain | Return |
---|---|---|
postMessage(<msg>, <origin>) | Send a specified message to another document | void |
As a scenario for setting up this capability, Code Listing 12 shows the problem I want to solve.
Code List 12 Cross-Document Issues
<!DOCTYPE HTML> <html> <head> <title>Cross-Document Issues</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p id="HZH_status">Get ready</p> <button id="HZH_send">Huang Zihan asks you to send a message</button> <p> <iframe name="HZH_nested" src="http://120.77.46.246/ZihanGroup/FBG/HTML_AG/chap27/code13.html" width="90%" height="75px"></iframe> </p> <script> document.getElementById("HZH_send").onclick = function() { document.getElementById("HZH_status").innerHTML = "Huang Zihan reminds you that the message has been sent"; } </script> </body> </html>
This document contains an iframe element to load a document from a different source. Scripts are from the same source only if they come from the same host and port. I load this document from port 80 on a server named titan, so another server on port 81 is considered a different source. Code Listing 13 shows the contents of the document otherdomain.html, which is loaded by iframe.
Code List 13 document otherdomain.html
<!DOCTYPE HTML> <html> <head> <title>File otherdomain.html</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h1 id="HZH_banner">Huang Zihan tells you this is a nested document</h1> <script> function displayMessage(HZH_msg) { document.getElementById("HZH_banner").innerHTML = HZH_msg; } </script> </body> </html>
[Click to see effect] document otherdomain.html
The goal of the main document example.html is to be able to call the displayMessage function defined by the script element embedded in the document otherdomain.html.
I'll use the postMessage method, but I need to call it on Windows that contains the target document. Fortunately, Windows objects provide the support needed to find embedded documents, as shown in the table below.
Find embedded windows
Name | Explain | Return |
---|---|---|
defaultview | Return Window of Active Document | Window |
frames | Returns an array of Window objects with an iframe element embedded in the document | Window[] |
opener | Return to the Window that opens the current browsing context | Window |
parent | Returns the parent Window of the current Window | Window |
self | Return the Window of the current document | Window |
top | Return to the top Window | Window |
length | Returns the number of iframe elements embedded in the document | numerical value |
[<index>] | Returns the Window of the embedded document at the specified index location | Window |
[<name>] | Returns the Window of the embedded document with the specified name | Window |
In this example, I'll use an array-style representation to locate the Window object I want so I can call the postMessage method. Code Listing 14 shows the code to be added to the document example.html.
Code Listing 14 Locates the Window object and calls the postMessage method
<!DOCTYPE HTML> <html> <head> <title>Location Window Object and call postMessage Method</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p id="HZH_status">Get ready</p> <button id="HZH_send">Huang Zihan asks you to send a message</button> <p> <iframe name="HZH_nested" src="http://120.77.46.246/ZihanGroup/FBG/HTML_AG/chap27/code13.html" width="90%" height="75px"></iframe> </p> <script> document.getElementById("HZH_send").onclick = function() { window["HZH_nested"].postMessage("Huang Zihan likes Xu Weizhou too", "http://120.77.46.246"); document.getElementById("HZH_status").innerHTML = "Huang Zihan reminds you that the message has been sent"; } </script> </body> </html>
[Click to see effect] Locate the Window object and call the postMessage method
Find the target Windows object (window["nested"]) that contains the script I want to send a message to, then call the postMessage method. Two of these parameters are the source of the message I want to send and the target script. The source in this example is http://titan:81 But if you are reproducing this example, it will vary depending on your environment.
warning
As a security measure, if the target source is wrong when calling the postMessage method, the browser discards the message.
In order to receive this message, I need to listen for the message event in another script. The browser passes a MessageEvent object with properties defined as shown in the table below.
Properties of MessageEvent
Name | Explain | Return |
---|---|---|
data | Return messages sent by other scripts | object |
origin | Return the source of the send message script | Character string |
source | Returns the window associated with the send message script | Window |
Code Listing 15 shows how to use message events to receive messages across documents.
Code List 15 listens for message events
<!DOCTYPE HTML> <html> <head> <title>Monitor message Event</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h1 id="HZH_banner">Huang Zihan tells you this is a nested document</h1> <script> window.addEventListener("message", receiveMessage, false); function receiveMessage(e) { if (e.origin == "http://120.77.46.246") { displayMessage("e.data"); } else { displayMessage("Information discarded"); } } function displayMessage(HZH_msg) { document.getElementById("HZH_banner").innerHTML = HZH_msg; } </script> </body> </html>
Note that when a message event is received, I check the origin property of the MessageEvent object to ensure that I can recognize and trust another script. This is an important precaution against manipulating messages from unknown and untrusted scripts. Now I have a simple mechanism to send messages from one script to another, even if they come from different sources. You can see this effect below.
[Click to see effect] Listen for message events
Use a timer
A useful feature provided by the Window object is the ability to set one-off and circular timers. These timers are used to execute a function after a preset period of time. The following table outlines how this functionality can be supported.
Timing method
Name | Explain | Return |
---|---|---|
clearInterval(<id>) | Undo an interval timer | void |
clearTimeout(<id>) | Undo a timeout timer | void |
setInterval(<function>, <time>) | Create a time r that calls the specified function every millisecond | integer |
setTimeout(<function>, <time>) | Create a timer that waits for timemilliseconds before calling the specified function | integer |
The setTimeout method creates a timer that executes the specified function only once, while the setInterval method creates a timer that executes a function repeatedly. These methods return a unique identifier that you can later undo as a parameter to the clearTimeout and clearInterval methods. Code Listing 16 shows how to use these timer methods.
Code Listing 16 uses the timer method
<!DOCTYPE HTML> <html> <head> <title>Use a timer</title> <link rel="shortcut icon" href="http://120.77.46.246/src/img/ba_favicon.ico" type="image/x-icon"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p id="HZH_msg"></p> <P> <button id="HZH_settime">Huang Zihan reminds you to set the time</button> <button id="HZH_cleartime">Huang Zihan reminds you the cleaning time</button> <button id="HZH_setinterval">Huang Zihan reminds you to set intervals</button> <button id="HZH_clearinterval">Huang Zihan reminds you to clear the interval</button> </P> <script> var HZH_buttons = document.getElementsByTagName("button"); for(var HZH_i = 0; HZH_i < HZH_buttons.length; HZH_i++) { HZH_buttons[HZH_i].onclick = handleButtonPress; } var HZH_timeID; var HZH_intervalID; var HZH_count = 0; function handleButtonPress(e) { if (e.target.id == "HZH_settime") { HZH_timeID = window.setTimeout(function() { displayMsg("Huang Zihan reminds you that the time-out has arrived"); }, 5000); displayMsg("Huang Zihan reminds you that the timeout has been set"); } else if (e.target.id == "HZH_cleartime") { window.clearTimeout(HZH_timeID); displayMsg("Huang Zihan reminds you that the time-out has been cleared"); } else if (e.target.id == "HZH_setinterval") { intervalID = window.setInterval(function() { displayMsg("Huang Zihan reminds you that the time interval has elapsed. Timer:" + HZH_count++); }, 2000); displayMsg("Huang Zihan reminds you to set a time interval"); } else if (e.target.id == "HZH_clearinterval") { window.clearInterval(HZH_intervalID); displayMsg("Huang Zihan reminds you that the time interval has been cleared"); } } function displayMsg(HZH_msg) { document.getElementById("HZH_msg").innerHTML = HZH_msg; } </script> </body> </html>
The script in this example sets and undoes timeout and interval timers that call the displayMsg function to set the content of a p element. The effect of the implementation can be seen below.
Timeouts and interval timers may be useful, but you should carefully consider how to use them. Users typically expect an application to remain in the same state unless they are directly interacting with it. If you're just using a timer to automatically change the state of your application, you should think about whether the result will be helpful or just annoying.