Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning JavaScript With DOM Scripting And Ajax - From Novice To Professional (2006)

.pdf
Скачиваний:
82
Добавлен:
17.08.2013
Размер:
17.27 Mб
Скачать

446

C H A P T E R 1 1 U S I N G T H I R D - P A R T Y J A V A S C R I P T

Let’s take both library components and some DOM trickery to simulate a browser pop-up window that resides in the same document, loads and displays a document via Ajax, and allows the user to move it around and close it. Figure 11-8 shows the result.

Figure 11-8. Simulating a pop-up window with YUI library components

As this is a rather top-of-the-difficulty-stage exercise, you need to include almost all components of the library in the HTML document:

examplePopUpReplace.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html dir="ltr" lang="en"> <head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>Example: Using YUI to replace pop-up windows</title> <script type="text/javascript" src="yahoo-min.js"></script> <script type="text/javascript" src="event-min.js"></script> <script type="text/javascript" src="dom-min.js"></script> <script type="text/javascript" src="dragdrop-min.js"></script> <script type="text/javascript" src="container-min.js"></script> <script type="text/javascript" src="connection-min.js"></script> <script type="text/javascript" src="animation-min.js"></script> <script type="text/javascript" src="popUpReplace.js"></script> <style type="text/css">

@import 'reset-min.css'; @import 'fonts-min.css'; @import 'popUpReplace.css';

</style>

</head>

C H A P T E R 1 1 U S I N G T H I R D - P A R T Y J A V A S C R I P T

447

<body>

<a href="demotext.html"

onclick="makeRequest(this);return false">Load Demo Text</a> <div id="win">

<div class="hd"></div> <div class="bd"></div>

</div>

</body>

</html>

Notice that this example is not really unobtrusive: you are using an inline onclick handler and creating HTML that is scripting dependent—the <div> with the ID of win will become your simulated pop-up. You could create these easily via the DOM and the Event library components, but let’s concentrate on using Connection Manager and Container now. The onclick handler sends the link as a parameter to the function makeRequest(), which reads out the link’s href attribute and starts a new Ajax request with the handleSuccess() and handleFailure() functions as event handlers.

examplePopUpReplace.js

function makeRequest( o ) { var sUrl = o.href;

var request = YAHOO.util.Connect.asyncRequest( 'GET', sUrl,

{

success : handleSuccess, failure : handleFailure

}

);

}

The handleSuccess() method retrieves the content of the linked document and checks whether the responseText is not undefined before creating the simulated pop-up with a new instance of the YAHOO.widget.Panel() constructor method. This method takes two parameters: the ID of the element that should be turned into a panel, and the panel attributes as a JSON object. The ID of the panel is win in this case.

examplePopUpReplace.js (continued)

function handleSuccess( o ) {

if( o.responseText !== undefined ) { panel = new YAHOO.widget.Panel (

"win",

There is an amazing number of properties a panel can have, and they are all listed in the documentation at http://developer.yahoo.com/yui/container/panel/#config. In this example, let’s choose an effect to fade the panel in and out smoothly and set the effect duration to half a second. The constraintoviewport property defines whether the user should be allowed

448

C H A P T E R 1 1 U S I N G T H I R D - P A R T Y J A V A S C R I P T

to drag the panel outside the currently visible browser section or not. Setting it to true ensures that there won’t be any ugly scrollbars when the user drags the panel too far to the right or down. The Panel() method automatically allows the user to drag the panel around when you set draggable to true and creates a link to hide the panel when you set close to true. As you’ll be changing the content of the panel, it is a good idea to hide it by setting the visible property to false. When you defined all the parameters, you can invoke the render() method of the new panel to create all the necessary HTML elements and apply all the event handlers.

examplePopUpReplace.js (continued)

{

effect : {

effect : YAHOO.widget.ContainerEffect.FADE, duration : 0.5

},

constraintoviewport : true, close : true,

visible : false, draggable : true

}

);

panel.render();

The parameter o that the function handleSuccess() retrieved from the Ajax call contains all the connection data, and you can retrieve the text content of the document that was loaded via o.responseText. Before you can use this data to populate the simulated pop-up panel, you need to clean it out, as you only need the title information for the panel’s title bar and the body content for the content. Everything else, from DOCTYPE to styles and script blocks, has to go. You could use regular expressions for that, but there is another way. First of all, you need to replace the BODY element in the text with a <div> with an ID of popupbody. This is necessary because setting the data as it is as innerHTML to an element would remove the BODY element—since there can be only one BODY in a browser window. To replace the BODY element with the <div>, you use regular expressions.

examplePopUpReplace.js (continued)

var content = o.responseText;

content = content.replace( /<body>/, '<div id="popupbody">' );

content = content.replace( /<\/body>/, '</div>' );

You next retrieve the second <div> inside the element with an ID of win (which is the panel body) and set its innerHTML property to the changed content. Then you can easily retrieve the title via getElementsByTagName() and the body content via getElementById().

examplePopUpReplace.js (continued)

var win = document.getElementById('win');

var windowbody = win.getElementsByTagName('div')[1];

C H A P T E R 1 1 U S I N G T H I R D - P A R T Y J A V A S C R I P T

449

windowbody.innerHTML=content;

var title = win.getElementsByTagName( 'title' )[0].innerHTML; var body = document.getElementById( 'popupbody' ).innerHTML;

You set the panel’s body and header content using the setBody() and setHeader() methods (the former conveniently overrides the rest of the content you don’t need) and show the panel by invoking the show() method.

examplePopUpReplace.js (continued)

panel.setBody( body ); panel.setHeader( title ); panel.show();

}

}

All that is left to do is to define the handleFailure() method that tells the user when the linked document could not be loaded.

examplePopUpReplace.js (continued)

function handleFailure( o ){

if( o.responseText !== undefined ) {

alert( 'Couldn\'t load the content: ' + o.statusText );

}

}

Yahoo User Interface Library Summary

The YUI is a really interesting library to use, especially because it offers much more than just a lot of methods that make your life easier like other libraries do, as it tries to give a lot of documentation and examples and also CSS layout and typography resources to quickly put together a JavaScript-enhanced web site or web application that works with all modern browsers.

The number of people involved in the library and the discussions on the mailing list are sure to make the library even better over time and make testing new components a lot easier. Right now the library is still young, and the documentation is daunting at times, but it is pretty easy to ask a question on the mailing list, and many developers are eager to help you out—in more problematic cases or when you have a request or an idea to extend the library, you will also quite surely find a Yahoo web developer dealing with the library to answer you—probably in the future even me. In comparison with other libraries, especially jQuery, you need to produce a lot more code in YUI to achieve several effects; however, what YUI does is keep the syntax to JavaScript standards and does not change the way you do loops or iterations. At first sight, YUI-driven code can look very complex, and the number of YAHOO.something.somethingElse statements can be confusing. The longer you work with it, the easier it becomes on the eye, and you start appreciating the way methods and properties are named according to what they do or what part of the library they belong to.

450

C H A P T E R 1 1 U S I N G T H I R D - P A R T Y J A V A S C R I P T

Summary

I hope this chapter has given you a taste of what is out there at the moment, and I am sure that this is simply the beginning of a longer experience of shared content, information, and services. Many developers spend a lot of time creating wonderful code just to realize that there is already another product out there that does exactly the same, but better; however, that is not much of a problem—it is through communication and trial and error that we become better in what we do.

You can learn a lot and help the community a great deal by keeping your eyes open and looking at the services available out there, especially giving feedback from your point of view as to how easy some services or libraries are to use. It is far too tempting to consider one’s own code perfect, and it is sometimes not until someone else shows you how to break it that you realize it’s not. This works both ways. And you shouldn’t be put off by your shortcomings— keep at it, and you will get better. Don’t be shy—keep participating in the JavaScript community.

A P P E N D I X

■ ■ ■

Debugging JavaScript

In this appendix, I will introduce you to some tricks and tools to debug your JavaScript code. It is very important to get acquainted with debugging tools, as programming consists to a large extent of trying to find out what went wrong a particular time. Some browsers help you with this problem; others make it harder by having their debugging tools hidden away or returning cryptic error messages that confuse more than they help. Some of my favorites include philosophical works like “Undefined is not defined” or the MSIE standard “Object doesn’t support this property or method.”

Common JavaScript Mistakes

Let’s start with some common mistakes that probably every JavaScript developer has made during his career. Having these in the back of your head when you check a failing script might make it a lot quicker to spot the problem.

Misspellings and Case-Sensitivity Issues

The easiest mistakes to spot are misspellings of JavaScript method names or properties. Classics include getElementByTagName() instead of getElementsByTagName(), getElementByID() instead of getElementById() and node.style.colour (for the British English writers). A lot of times the problem could also be case sensitivity, for example, writing keywords in mixed case instead of lowercase.

If( elm.href ) {

var url = elm.href;

}

There is no keyword called If, but there is one called if. The same problem of case sensitivity applies to variable names:

var FamilyGuy = 'Peter'; var FamilyGuyWife = 'Lois'; alert( 'The Griffins:\n'+

familyGuy + ' and ' + FamilyGuyWife );

This will result in an error message stating “familyGuy is not defined”, as there is a variable called FamilyGuy but none called familyGuy.

451

452

A P P E N D I X D E B U G G I N G J A V A S C R I P T

Trying to Access Undefined Variables

We talked about it in the first chapter of the book—you define variables either by declaring them with or without an additional var keyword (the latter is necessary to define the scope of the variable).

Stewie = "Son of Peter and Lois";

var Chris = "Older Son of Peter and Lois";

If you try to access a variable that hasn’t been defined yet, you’ll get an error. The alert() in the following script throws an error as Meg is not defined yet.

Peter = "The Family Guy";

Lois = "The Family Guy's Wife"; Brian = "The Dog";

Stewie = "Son of Peter and Lois"; Chris = "Older Son of Peter and Lois"; alert( Meg );

Meg = "The Daughter of Peter and Lois";

This is easy when it is an obvious example like this one, but how about trying to guess where the bug in the following example is?

exampleFamilies.html

function getFamilyData( outptID, isTree, familyName ) { var father, mother, child;

switch( familyName ) { case 'Griffin':

father = "Peter"; mother = "Lois"; child = "Chris";

break;

case 'Flintstone': father = "Fred"; mother = "Wilma"; child = "Pebbles";

break;

}

var out = document.getElementById( outputID ); if( isTree ) {

var newUL = document.createElement( 'ul' ); newUL.appendChild( makeLI( father ) ); newUL.appendChild( makeLI( mother ) ); newUL.appendChild( makeLI( child ) ); out.appendChild( newUL );

A P P E N D I X D E B U G G I N G J A V A S C R I P T

453

}else {

var str = father + ' ' + mother + ' ' + child; out.appendChild( document.createTextNode( str ) );

}

}

getFamilyData( 'tree', true, 'Griffin' );

Microsoft Internet Explorer tells you that there is an error in line 23—“‘outputID’ is undefined,” as shown in Figure A-1.

Figure A-1. MSIE showing an error on line 23

However, if you look at the code in line 23 as shown in Figure A-2, nothing seems to be wrong.

Figure A-2. The code shown in UltraEdit with a highlight on line 23

The culprit is a typo in the function parameter, highlighted in Figure A-3, which means that outputID is not defined but outptID is.

454

A P P E N D I X D E B U G G I N G J A V A S C R I P T

Figure A-3. The misspelled function parameter that caused the error

Typos in parameters are a very confusing bug, as browsers tell you the error occurred in the line where the variable is used and not where you made the mistake.

Incorrect Number of Closing Braces and Parentheses

Another very common mistake is not closing curly braces or keeping an orphaned closing brace in the code when deleting some lines. Say, for example, you don’t need the isTree option any longer and you remove it from the code:

exampleCurly.html

function getFamilyData( outputID, familyName ) { var father, mother, child;

switch( familyName ) { case 'Griffin':

father = "Peter"; mother = "Lois"; child = "Chris";

break;

case 'Flintstone': father = "Fred"; mother = "Wilma"; child = "Pebbles";

break;

}

var out = document.getElementById( outputID ); var newUL = document.createElement( 'ul' ); newUL.appendChild( makeListElement( father ) ); newUL.appendChild( makeListElement( mother ) ); newUL.appendChild( makeListElement( child ) );

A P P E N D I X D E B U G G I N G J A V A S C R I P T

455

out.appendChild( newUL );

}

}

getFamilyData( 'tree', true, 'Griffin' );

The orphan closing brace shown in bold will cause a “syntax error in line 30.” The same problem occurs when you don’t close all the braces in a construct, a mistake that can easily happen when you don’t indent your code:

exampleMissingCurly.html

function testRange( x, start, end ) { if( x <= end && x >= start ) {

if( x == start ) {

alert( x + ' is the start of the range');

}

if( x == end ) {

alert(x + ' is the end of the range');

}

if( x! = start && x != end ) { alert(x + ' is in the range'); } else {

alert(x + ' is not in the range');

}

}

Running this example will cause an “expected ‘}’ in line 27” error, which is the last line of the script block. This means that somewhere inside the conditional construct we forgot to add a closing curly brace. Where the missing brace is supposed to be is rather hard to find, but a lot easier when the code is properly indented.

exampleMissingCurlyFixed.html

function testRange( x, start, end ) { if( x <= end && x >= start ) {

if( x == start ) {

alert(x + ' is the start of the range');

}

if( x == end ) {

alert(x + ' is the end of the range');

}

if( x != start && x != end ) { alert(x + ' is in the range');

}

}else {

alert( x + ' is not in the range' );

}

}