reptile7's JavaScript blog
Wednesday, June 17, 2009
 
A Quick One, While the W3C's Away
Blog Entry #148

Today we begin a tour of HTML Goodies' "Opening New Windows With JavaScript" series of tutorials.

I've still got some homework to do for the "New Window: No Title Bar" tutorial, so in this post we will check over the "Quick Window" tutorial. "Quick Window" presents a script that pops up a new window and document in response to a mouseover event. The "Quick Window" script is reproduced in the div below:

<script type="text/javascript">
<!-- vor alten Browsern verstecken
/* Copyright Arnold Schiller
http://homepages.muenchen.org/bm596269 (not a functional link) */

function msgopen( ) {
var fenster = window.open("", "Welcome", "scrollbar=yes,width=400,height=200");
fenster.document.open( );
with (fenster.document) {
write("<html><base target='Frame 0' /><body onblur='window.close( );'>");
/* Frame0 is the name of the display - change it if necessary */
write("Hi There! 
");
write(" Here's a quick way to get another window up here.<br />");
write("<a href='http://www.htmlgoodies.com/'>http://www.htmlgoodies.com</a><br />");
write("<p>Close the window to grab the script.<br />");
write("</body></html>");
}
fenster.document.close( );
} 

// -->

</script>

<!-- Joe's triggering code: -->

<a onmouseover="msgopen( );" href="http://www.htmlgoodies.com">Open the message window onMouseOver.</a>

As it appears on the quickwindowcode.html page, the "Quick Window" script contains a mistake (not present in the "Quick Window" tutorial source) that would prevent it from running:

write("Hi There!
");
// One more time, folks: JavaScript strings cannot contain line breaks.


should actually be

write("Hi There! <br>");

Even without this mistake, Joe's Open the message window onMouseOver. link demo will probably not work for you if your browser is set to block pop-up windows - more on this in the "Triggering msgopen( )" section below.

Joe provides no deconstruction at all for the "Quick Window" tutorial, and thus it is up to us to heroically rise to the task...

The new window

The tutorial script mostly consists of a msgopen( ) function that opens a new window and then creates a document contained by that window - cf. HTML Goodies' JavaScript Primers #12, which discusses a similar script. The msgopen( ) command that opens the window is:

var fenster = window.open("", "Welcome", "scrollbar=yes,width=400,height=200");

We went over the basics of the open( ) method of the window object in Blog Entry #25, but allow me to take the opportunity to provide you with up-to-date references in this regard:
(1) The window.open( ) page of Mozilla's Gecko DOM Reference
(2) The MSDN Library's window.open( ) page
(The W3C's Window Object 1.0 Specification seems to be stuck in neutral, I'm sorry to report.)

The new window's object reference will be fenster. The first window.open( ) argument is an empty string, meaning that fenster will not load an external resource; rather, fenster's document will be coded by msgopen( )'s subsequent commands. The second window.open( ) argument assigns Welcome to the value of fenster's name property - no targeting use is made of this name, so we could use an empty string here too if we wanted to.

Regarding the third window.open( ) argument, the "scrollbar" feature should actually be scrollbars: this feature would equip fenster with a vertical/right scrollbar if the height of fenster's document exceeded fenster's height. With respect to the original "Quick Window" code, fenster is taller than its document and thus the scrollbars feature has no effect, or at least that's what I observe with the browsers on my computer. The width=400 and height=100 fenster features are self-explanatory.

The new document

The "Quick Window" script uses document.open( ) and document.close( ) commands to respectively "open" and "close" the fenster document:

fenster.document.open( );
...fenster.document.write( ) commands...
fenster.document.close( );


Although the open( ) and close( ) methods of the document object were implemented in JavaScript 1.0, the first version of JavaScript, this is our first brush with these methods. Quoting Mozilla, [t]he document.open( ) method opens a document for writing, whereas [t]he document.close( ) method finishes writing to a document [that was] opened with document.open( ). The document.open( ), document.write( ), and document.close( ) methods all appear in the DOM Level 2 HTML Specification, and the W3C insinuates that a document.write( ) command is necessarily preceded by a document.open( ) command, but in practice this is not true - Joe did not use document.open( ) and document.close( ) commands in Primer #12, for example. We can in fact comment out the above fenster.document.open( ) and fenster.document.close( ) commands without any problems, but their use here is consonant with the design of the script, which does indeed create the fenster document from scratch, so let's just leave them in place, shall we?

Perhaps you are wondering, "What good are document.open( ) and document.close( ), anyway?" Mozilla notes that these methods can be used to clear and overwrite a document on the fly, if for some reason you wanted to do that.

Moving on...sandwiched between the fenster.document.open( ) and fenster.document.close( ) commands is a with package of six fenster.document.write( ) commands that writes the fenster document:

with (fenster.document) {
write("<html><base target='Frame 0' /><body onblur='window.close( );'>");
/* Frame0 is the name of the display - change it if necessary */
write("Hi There! <br />");
write(" Here's a quick way to get another window up here.<br />");
write("<a href='http://www.htmlgoodies.com/'>http://www.htmlgoodies.com</a><br />");
write("<p>Close the window to grab the script.<br />");
write("</body></html>"); }


This is our first encounter with the with statement, which establishes the default object for a set of statements, again quoting Mozilla. By placing the fenster.document object reference in the parentheses following the with keyword, we can subsequently truncate fenster.document.write( ) to write( ) in the with statement body - cool, huh? And yes, the fenster.document.open( )/fenster.document.close( ) commands could have been included in the with block.

Anything interesting in those write( ) commands? write( ) commands #2-6 are unremarkable, but write( ) command #1 raises a couple of red flags:

(1) The fenster document head contains a <base target='Frame 0' /> base element, of which no use is made and which could easily be deleted. Of course, there's nothing stopping us from making use of it, and we'll do so later in the post.

(2) The fenster document's body element is equipped with an onblur='window.close( );' attribute that closes the fenster window when it loses focus, e.g., when the user clicks outside of the window or types Command-` to 'cycle' to the opener window. This code works with all of the browsers on my computer but would be W3C-invalid in a non-script HTML context; according to the W3C, onblur is legit for the anchor, area, label, input, select, textarea, and button elements but not for the body element. Alternatively, the onblur action can be achieved in a purely programmatic (non-HTML) way with the following line of code, which can be placed before or after the with block in the msgopen( ) function:

fenster.onblur = closeMe; function closeMe( ) { fenster.close( ); }

(FWIW: Netscape says it's OK to use onblur with the body element but Microsoft doesn't, and yet in Joe's demo fenster is indeed sent packing when I blur it when using MSIE 5.2.3 for Mac OS X.)

Triggering msgopen( )

As shown in the div at the beginning of the post, the code that triggers the msgopen( ) function is:

<a onmouseover="msgopen( );" href="http://www.htmlgoodies.com">Open the message window onMouseOver.</a>

We could of course pair onmouseover with a variety of elements - a button element, an img element, a span element, etc. - but because msgopen( ) does access a new resource, i.e., the fenster document, I would say that the use of an anchor element is appropriate in this case. But at the risk of nixing the "Quick Window" tutorial's raison d'être, onmouseover is not the best choice of event handlers here.

Modern browsers are typically set to block pop-up windows by default - at least this is true for Firefox, Opera*, and Safari on my computer. In practice, browsers vary in their pop-up window blocking behavior: a given browser will allow some events to pop up new windows but not others, whereas the specific events that are able to override pop-up window blocking vary from browser to browser.* For example, I find that I can trigger msgopen( ) with keypress events when using Safari but not when using Firefox. Firefox, Opera, and Safari all prevent a mouseover event from popping up a new window but they all allow a click event to do so, and thus we are better off triggering msgopen( ) with an onclick event handler instead.

*For Opera, the default Block unwanted pop-ups setting gives the behavior described above; Opera also has a Block all pop-ups setting that chokes off all pop-up windows, including those that would be generated by click events.

A complication arises in switching from onmouseover to onclick: besides calling msgopen( ) and opening fenster, clicking the Link text also loads the href destination document, http://www.htmlgoodies.com in the preceding code, into the opener window. In this situation, Mozilla recommends that we append to the onclick event handler a return false statement that will cancel the link's default href action for JavaScript-enabled browsers but will preserve the href capability for browsers that do not enable or support JavaScript. Using

<a onclick="msgopen( ); return false;" href="http://www.google.com">Click here to open the message window.</a>

as a test element, I can confirm that this return false business works as advertised for all of the browsers on my computer.

If you would rather zero out the href action altogether, you could, I suppose, in time-(dis)honored manner, set the href attribute to # or to an empty string (it's not invalid to do this, but it's poor design), although I myself would go with a push button as the 'user interface' in that case.

Demo

Let's put this off until next time.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)