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

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

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

336

C H A P T E R 8 B A C K - E N D I N T E R A C T I O N W I T H A J A X

You then take the link inside the trigger and remove anything after and including the question mark. This means that if the user clicks the link, it’ll turn off both the Ajax and the dynamic menu functionality. You also change the link text to the label text for the basic navigation.

XHRSiteNav.js (continued)

var triggerlink = xhrsitenav.trigger.getElementsByTagName( a')[0]; triggerlink.href = triggerlink.href.replace( /\?.*/, '' ); triggerlink.innerHTML = xhrsitenav.downLabel;

},

The xhr() method needs to get the current link via getTarget() and ensure the event target is a link by comparing it with the right nodeName.

XHRSiteNav.js (continued)

xhr : function( e ){

var t = DOMhelp.getTarget( e );

while( t.nodeName.toLowerCase() != 'a' ) { t = t.parentNode;

}

It uses parentNode to retrieve the list item the link resides in and checks whether the item contains a STRONG element. If there is a STRONG element, xhr() highlights the current section via the parameters defined in the dynamic menu script. It calls removeOldHighlight() to undo any other highlights and retrieve the url to load into the content container element.

XHRSiteNav.js (continued)

var parentLI = t.parentNode;

if( t.parentNode.getElementsByTagName('ul').length > 0 ) {

var firstList = t.parentNode.getElementsByTagName( 'ul' )[0]; DOMhelp.cssjs( 'add', firstList, sn.showClass )

DOMhelp.cssjs( 'swap', parentLI, sn.openClass, sn.parentClass ); parentLI.getElementsByTagName( 'a' )[0].innerHTML = sn.openIndicator;

}

var url = xhrsitenav.removeOldHighlight( t );

The remainder of xhr()and its helper methods, retrieved() and failed(), are unchanged from the other examples in this chapter.

C H A P T E R 8 B A C K - E N D I N T E R A C T I O N W I T H A J A X

337

XHRSiteNav.js (continued)

var request; try {

request = new XMLHttpRequest();

}catch(error) { try {

request = new ActiveXObject('Microsoft.XMLHTTP');

}catch(error) { return true;

}

}

request.open( 'get', url, true ); request.onreadystatechange = function() {

if( request.readyState == 1 ){ xhrsitenav.outputContainer.innerHTML = xhrsitenav.loadingMessage;

}

if( request.readyState == 4 ) {

if( request.status && /200|304/.test( request.status ) ) { xhrsitenav.retrieved( request );

}else {

xhrsitenav.failed( request );

}

}

}

request.setRequestHeader( 'If-Modified-Since', 'Wed, 05 Apr 2006 00:00:00 GMT');

request.send( null ); DOMhelp.cancelClick( e ); return false;

},

retrieved : function( requester, e ) { var data = requester.responseText;

xhrsitenav.outputContainer.innerHTML = data; DOMhelp.cancelClick( e );

return false;

},

failed : function( requester ) {

alert( 'The XMLHttpRequest failed. Status: ' + requester.status ); return true;

},

338

C H A P T E R 8 B A C K - E N D I N T E R A C T I O N W I T H A J A X

The createTrigger() method checks whether there is already a trigger defined and creates a new one if necessary. The trigger is the list item containing the link that allows the user to switch between the different navigation states. There shouldn’t be any surprises in this method—it could have been part of the init() method, after all. It might be a good idea to keep functionality like this in own methods, should other scripts need to add the trigger once more.

XHRSiteNav.js (continued)

createTrigger : function() { if( !xhrsitenav.trigger ) {

xhrsitenav.trigger = document.createElement( 'li' ); xhrsitenav.trigger.id = xhrsitenav.triggerID;

var loc = xhrsitenav.shorturl( window.location.href ); var newlink = DOMhelp.createLink( loc + '?ajax=1', xhrsitenav.triggerLabel ); xhrsitenav.trigger.appendChild( newlink ); xhrsitenav.nav.appendChild( xhrsitenav.trigger );

}

},

The removeOldHighlight() method is called by the xhr() method. It replaces the current STRONG element inside the navigation with a link and vice versa. For the STRONG element that gets replaced by a link, the method sets the href attribute to the STRONG element’s class name suffixed with “.php” and attaches the event handler to call xhr() when the user clicks the link.

XHRSiteNav.js (continued)

removeOldHighlight : function( o ) {

var highlight = xhrsitenav.nav.getElementsByTagName('strong')[0]; var current = highlight.className + '.php';

var newlink = document.createElement( 'a' ); newlink.appendChild( document.createTextNode ( highlight.innerHTML ) ); newlink.setAttribute( 'href', current );

DOMhelp.addEvent( newlink, 'click', xhrsitenav.xhr, false ); newlink.onclick = DOMhelp.safariClickFix; highlight.parentNode.replaceChild( newlink, highlight );

For the link retrieved as the parameter o, the method calls a helper method named shorturl() that cleans out excess data from the link’s href (you only need the file name, not the whole path that href returns). It then creates a new STRONG element, removes the .php file extension, and stores the resulting string in the STRONG element’s className property. It prefixes the url with the name of the directory where the content pages are stored, and returns the complete url to xhr() in order to load the correct content.

C H A P T E R 8 B A C K - E N D I N T E R A C T I O N W I T H A J A X

339

XHRSiteNav.js (continued)

var shorturl = xhrsitenav.shorturl( o.getAttribute( 'href' ) ); var st = document.createElement( 'strong' );

st.className = shorturl.replace( '.php', '' ); st.innerHTML = o.innerHTML; o.parentNode.replaceChild( st, o );

var url = 'content/' + shorturl; return url;

},

The shorturl() helper method removes anything before the last slash from the string it got as a parameter and returns the result.

XHRSiteNav.js (continued)

shorturl : function( url ) {

return url.replace( /.*\//g, '' );

}

}

DOMhelp.addEvent(window, 'load', xhrsitenav.init, false );

If the user chooses the enhanced navigation, he’ll get a tree menu that loads the content in the page without reloading the whole document as shown in Figure 8-10.

Figure 8-10. The enhanced XHR navigation

340

C H A P T E R 8 B A C K - E N D I N T E R A C T I O N W I T H A J A X

This is an example of how you can make high-end JavaScript functionality optional instead of hoping that visitors can deal with it. It is not a very common approach, as it adds an extra level of complexity to the interface; but depending on the audience of your product, it might give a good impression and also tells visitors that once they have chosen the advanced navigation, they cannot expect it to offer the same experience as a static one does—for example, Back button functionality and bookmarking.

Summary

I hope this has given you an insight into what can be done with JavaScript and XMLHttpRequest to create dynamic connections between the back end and the browser without reloading the page.

As cool as Ajax is, there are some things to keep in mind:

Primarily, Ajax was invented as a methodology to develop web applications, and not web sites. It might be overkill to “Ajax-ify” every small form and menu.

Ajax is a connector between client-side scripting and the back end; it is only as powerful as the back-end script or the information is.

Ajax is confined to scripts and data sources on the same server as the script using it, unless you use a pass-through script on the server or you have a third-party service that offers data in JSON format, such as http://del.icio.us does.

It is very tempting and easy to create an Ajax application that looks impressive but is very obtrusive—relying on the mouse and on JavaScript being available. Creating an Ajax interface that is accessible is a much harder task.

Ajax is currently “hot,” and a lot of very gifted developers are working on frameworks and libraries that can help you to create Ajax applications quickly without having to know all the ins and outs of it—using them may even prevent you from repeating mistakes these developers have made themselves in the past. The number of libraries available is staggering, and it can be hard to tell which one is the right one for the task at hand.

Leland Scott has done an amazing job researching dozens of different Ajax libraries on the Web and comparing them in terms of cross-browser and cross-platform compatibility: http:/ /www.musingsfrommars.org/2006/03/ajax-dhtml-library-scorecard.html.

Here is a sampling of the best-known and most popular libraries with some information as to their capabilities and goals:

DOJO (http://www.dojotoolkit.org/) is one of the most mature and most popular DHTML/Ajax toolkits now available. The only issue is that there is not a huge examples section.

prototype (http://prototype.conio.net/) is a very powerful and much appreciated framework; however, it comes with neither documentation nor examples, which is why several prototype spin-offs are more likely to be usable for you as follows:

script.aculo.us (http://script.aculo.us/) is probably the best-documented library available. Dozens of examples and explanations help you find your way around the library quite quickly.

C H A P T E R 8 B A C K - E N D I N T E R A C T I O N W I T H A J A X

341

moofx (http://moofx.mad4milk.net/) was especially developed with size in mind. The entire library is only 3KB and offers lots of visual tricks and effects, along with a basic Ajax engine.

Rico (http://openrico.org/rico/home.page) was developed with web applications in mind and features a panel bar, a data grid, and some effects, as well as an Ajax engine of its own.

S@rdalya (http://www.sarmal.com/sardalya/Default.aspx) is a newer library that is very modular. It is constantly being updated. S@dalya’s developer is also very active on evolt’s thelist mailing list (http://lists.evolt.org/).

The Yahoo User Interface library (http://developer.yahoo.com/yui/index.html), created and maintained by Yahoo, provides good documentation and examples, making it easy to take your first steps with Ajax. You’ll find a support mailing list at http:// groups.yahoo.com/group/ydn-javascript/.

Sarissa (http://sarissa.sourceforge.net/doc/) helps when you need to work with XML; it allows you to convert XML to strings easily, and from one XML document to another, using XSLT.

In the next chapter, we will finally take a closer look at regular expressions and how to use them to validate data. You will learn how to create a contact form as an example application and maybe reuse some of the XHR functionality achieved here to make it slicker than your usual run-of-the-mill contact form.

C H A P T E R 9

■ ■ ■

Data Validation Techniques

In this chapter, you will learn about using JavaScript to validate data entered by the user or coming from other systems. You already heard a lot about this in Chapter 2, which dealt with decisions involving data, and we will use some of that knowledge and extend it here.

I’ll start with a quick introduction of the pros and cons of JavaScript validation and go on to explaining different techniques, starting with string and mathematical validation techniques and building up gradually to the developer’s Swiss Army Knife: pattern matching with regular expressions.

You will then get to know different means of spotting what parts of a form need validating, how to ease the maintenance of form validation, and how to display validation output. We’ll finish with an Ajax example of how to suggest possible values.

Historically, JavaScript books for beginners will tell you about all the ins and outs of clientside validation and what you can do to validate data before it is sent to the server. I deliberately kept this to the bare minimum. The reason is that it simply is not safe to rely on JavaScript validation (as you’ll see in the upcoming section), and you can spend hours writing functions to validate when you really should rely on the server-side component of your web site to do the validation and use JavaScript as a first sanity check of the data coming from the user. You will learn about techniques to use server-side component validation rules in JavaScript though.

Pros and Cons of Client-Side JavaScript

Validation

Validating user entries via JavaScript is great for several reasons:

It saves the user a page reload when he enters incorrect data; and you can save the state of the variables, so the user does not have to enter all the data again, just the incorrect data.

It cuts down on server traffic, as there is no round-trip to the back end in case of an error.

It makes the interface more responsive, as it gives the user immediate feedback.

343

344

C H A P T E R 9 D A T A V A L I D A T I O N T E C H N I Q U E S

On the other hand, validating with JavaScript has several issues:

It cannot be trusted as the one and only means of validation (JavaScript could not be available or could even be deliberately turned off to circumvent your validation measures).

It promotes the notion that validating input is an easy process—it isn’t, yet it is very crucial to the security and usability of your product. A lot of web forms are no fun to use because the usability aspect of validation has not been taken care of. Entering data is hard enough, so don’t make it harder for the user than necessary by expecting the data in formats that are not easily understandable or by using methods of error reporting that are in the user’s way (for example, alert messages and client-side validation that makes it impossible to send the form without JavaScript) rather than preventing him from making mistakes.

It could happen that the user agent does not notify the user of dynamic changes to the document—this is the case with very old screen readers for users with visual impairments.

Unless you share validation rules on the client and server side (you’ll get an example of how to do that during the course of the chapter), it means twice the maintenance should a validation rule change.

If you don’t want to make your validation rules visible—say to prevent spam or for authentication purposes—there is no way to do that in JavaScript.

A Quick Reminder About Protecting Content with JavaScript

Validation is one thing, protecting content with a password or obfuscating it via encryption is another. If you look around the web, you will find a lot of examples that promise that you can protect a web page from being available with a JavaScript password. Normally these scripts are something like this:

examplePassword.html

var pw = prompt( 'Enter Password', '' ); if( pw != 'password123' ) {

alert( 'Wrong password' ); window.location = 'boo.html' ;

} else {

window.location = 'creditCardNumbers.html';

}

C H A P T E R 9 D A T A V A L I D A T I O N T E C H N I Q U E S

345

The one and only cracking skill needed to work around this protection is to look at the page source, or—if the protection is in its own JavaScript file—open that in a browser or text editor. In some cases, where there is no redirection to the correct page, but only to the wrong one, simply turning off JavaScript will get you through.

There are seemingly more clever protection methods that use the password as a part of the file name:

var pw = prompt( 'Enter Password' , '' ); window.location = 'page' + pw + '.html';

These can be cracked by finding out which files are available on the server—because either the directory listing hasn’t been turned off (which is amazingly often the case—for proof just perform a Google search on “index of /mp3”—including the quotation marks) or the page can be found in counter statistics or in the cache of either the browser or Google.

The same applies to obfuscating (making something unreadable by encrypting or replacing words) content and scripts. Anything that was protected by JavaScript can be cracked with it—given enough time and determination. Just don’t waste your time with it.

Note JavaScript is a language that is executed on the client computer most of the time, which makes it far too easy for a malicious attacker to work around your protection methods. In the case of right-click prevention scripts to protect images and text from being copied, you will most likely alienate normal visitors and get nothing but a dry chuckle out of real attackers.

Packing JavaScript with something like Dean Edward’s packer (http://dean.edwards. name/packer/) to make really heavy scripts shorter is another issue though, and might be a good idea at times—for example, if you want to use a large library script on a high-traffic site.

The One-Size-Fits-All Validation Myth

Validation of user entry can be pretty straightforward—for example, ensuring that a field in a form has some data in it, a select box option has been chosen, or a check box was ticked. However, when it comes to more complex forms of data like dates and times, there is just no catch-all validation approach. A lot of ready-made scripts are available on the Web, and every development framework or IDE comes with out-of-the-box generic form validation solutions that promise to solve any problem for you.

The sad fact is that most of them are rather convoluted or just don’t hold up to their promise. Good web forms are as much a user interface and usability matter as they are a technical issue. Knowing your audience and their environment is very important. This is why I don’t give you a lot of “silver bullet” examples of validation here, but explain which tools to use to write your own validation scripts.