- •preface
- •acknowledgments
- •about this book
- •Who should read this book?
- •Roadmap
- •Code conventions
- •Code downloads
- •Author Online
- •About the title
- •About the cover illustration
- •Rethinking the web application
- •A new design for the Web
- •1.1 Why Ajax rich clients?
- •1.1.1 Comparing the user experiences
- •1.1.2 Network latency
- •1.1.3 Asynchronous interactions
- •1.1.4 Sovereign and transient usage patterns
- •1.1.5 Unlearning the Web
- •1.2 The four defining principles of Ajax
- •1.2.1 The browser hosts an application, not content
- •1.2.2 The server delivers data, not content
- •1.2.3 User interaction with the application can be fluid and continuous
- •1.2.4 This is real coding and requires discipline
- •1.3 Ajax rich clients in the real world
- •1.3.1 Surveying the field
- •1.3.2 Google Maps
- •1.4 Alternatives to Ajax
- •1.4.2 Java Web Start and related technologies
- •1.5 Summary
- •1.6 Resources
- •First steps with Ajax
- •2.1 The key elements of Ajax
- •2.2 Orchestrating the user experience with JavaScript
- •2.3 Defining look and feel using CSS
- •2.3.1 CSS selectors
- •2.3.2 CSS style properties
- •2.3.3 A simple CSS example
- •2.4 Organizing the view using the DOM
- •2.4.1 Working with the DOM using JavaScript
- •2.4.2 Finding a DOM node
- •2.4.3 Creating a DOM node
- •2.4.4 Adding styles to your document
- •2.4.5 A shortcut: Using the innerHTML property
- •2.5 Loading data asynchronously using XML technologies
- •2.5.1 IFrames
- •2.5.2 XmlDocument and XMLHttpRequest objects
- •2.5.3 Sending a request to the server
- •2.5.4 Using callback functions to monitor the request
- •2.5.5 The full lifecycle
- •2.6 What sets Ajax apart
- •2.7 Summary
- •2.8 Resources
- •Introducing order to Ajax
- •3.1 Order out of chaos
- •3.1.1 Patterns: creating a common vocabulary
- •3.1.2 Refactoring and Ajax
- •3.1.3 Keeping a sense of proportion
- •3.1.4 Refactoring in action
- •3.2 Some small refactoring case studies
- •3.2.2 Managing event handlers: Observer pattern
- •3.2.3 Reusing user action handlers: Command pattern
- •3.2.4 Keeping only one reference to a resource: Singleton pattern
- •3.3 Model-View-Controller
- •3.4 Web server MVC
- •3.4.1 The Ajax web server tier without patterns
- •3.4.2 Refactoring the domain model
- •3.4.3 Separating content from presentation
- •3.5 Third-party libraries and frameworks
- •3.5.2 Widgets and widget suites
- •3.5.3 Application frameworks
- •3.6 Summary
- •3.7 Resources
- •Core techniques
- •The page as an application
- •4.1 A different kind of MVC
- •4.1.1 Repeating the pattern at different scales
- •4.1.2 Applying MVC in the browser
- •4.2 The View in an Ajax application
- •4.2.1 Keeping the logic out of the View
- •4.2.2 Keeping the View out of the logic
- •4.3 The Controller in an Ajax application
- •4.3.1 Classic JavaScript event handlers
- •4.3.2 The W3C event model
- •4.3.3 Implementing a flexible event model in JavaScript
- •4.4 Models in an Ajax application
- •4.4.1 Using JavaScript to model the business domain
- •4.4.2 Interacting with the server
- •4.5 Generating the View from the Model
- •4.5.1 Reflecting on a JavaScript object
- •4.5.2 Dealing with arrays and objects
- •4.5.3 Adding a Controller
- •4.6 Summary
- •4.7 Resources
- •The role of the server
- •5.1 Working with the server side
- •5.2 Coding the server side
- •5.2.1 Popular implementation languages
- •5.3 The big picture: common server-side designs
- •5.3.1 Naive web server coding without a framework
- •5.3.2 Working with Model2 workflow frameworks
- •5.4 The details: exchanging data
- •5.4.2 Introducing the planet browser example
- •5.5 Writing to the server
- •5.5.1 Using HTML forms
- •5.5.2 Using the XMLHttpRequest object
- •5.5.3 Managing user updates effectively
- •5.6 Summary
- •5.7 Resources
- •Professional Ajax
- •The user experience
- •6.1 Getting it right: building a quality application
- •6.1.1 Responsiveness
- •6.1.2 Robustness
- •6.1.3 Consistency
- •6.1.4 Simplicity
- •6.1.5 Making it work
- •6.2 Keeping the user informed
- •6.2.1 Handling responses to our own requests
- •6.2.2 Handling updates from other users
- •6.3 Designing a notification system for Ajax
- •6.3.1 Modeling notifications
- •6.3.2 Defining user interface requirements
- •6.4 Implementing a notification framework
- •6.4.1 Rendering status bar icons
- •6.4.2 Rendering detailed notifications
- •6.4.3 Putting the pieces together
- •6.5 Using the framework with network requests
- •6.6 Indicating freshness of data
- •6.6.1 Defining a simple highlighting style
- •6.6.2 Highlighting with the Scriptaculous Effects library
- •6.7 Summary
- •6.8 Resources
- •Security and Ajax
- •7.1 JavaScript and browser security
- •7.1.1 Introducing the “server of origin” policy
- •7.1.2 Considerations for Ajax
- •7.1.3 Problems with subdomains
- •7.2 Communicating with remote services
- •7.2.1 Proxying remote services
- •7.2.2 Working with web services
- •7.3 Protecting confidential data
- •7.3.1 The man in the middle
- •7.3.2 Using secure HTTP
- •7.3.3 Encrypting data over plain HTTP using JavaScript
- •7.4 Policing access to Ajax data streams
- •7.4.1 Designing a secure web tier
- •7.4.2 Restricting access to web data
- •7.5 Summary
- •7.6 Resources
- •Performance
- •8.1 What is performance?
- •8.2 JavaScript execution speed
- •8.2.1 Timing your application the hard way
- •8.2.2 Using the Venkman profiler
- •8.2.3 Optimizing execution speed for Ajax
- •8.3 JavaScript memory footprint
- •8.3.1 Avoiding memory leaks
- •8.3.2 Special considerations for Ajax
- •8.4 Designing for performance
- •8.4.1 Measuring memory footprint
- •8.4.2 A simple example
- •8.5 Summary
- •8.6 Resources
- •Ajax by example
- •Dynamic double combo
- •9.1 A double-combo script
- •9.2 The client-side architecture
- •9.2.1 Designing the form
- •9.2.2 Designing the client/server interactions
- •9.3 Implementing the server: VB .NET
- •9.3.1 Defining the XML response format
- •9.4 Presenting the results
- •9.4.1 Navigating the XML document
- •9.4.2 Applying Cascading Style Sheets
- •9.5 Advanced issues
- •9.5.2 Moving from a double combo to a triple combo
- •9.6 Refactoring
- •9.6.1 New and improved net.ContentLoader
- •9.7 Summary
- •Type-ahead suggest
- •10.1 Examining type-ahead applications
- •10.1.2 Google Suggest
- •10.2.1 The server and the database
- •10.3 The client-side framework
- •10.3.1 The HTML
- •10.3.2 The JavaScript
- •10.3.3 Accessing the server
- •10.5 Refactoring
- •10.5.1 Day 1: developing the TextSuggest component game plan
- •10.5.3 Day 3: Ajax enabled
- •10.5.4 Day 4: handling events
- •10.5.6 Refactor debriefing
- •10.6 Summary
- •11.1 The evolving portal
- •11.1.1 The classic portal
- •11.1.2 The rich user interface portal
- •11.2 The Ajax portal architecture using Java
- •11.3 The Ajax login
- •11.3.1 The user table
- •11.4 Implementing DHTML windows
- •11.4.1 The portal windows database
- •11.4.3 Adding the JS external library
- •11.5 Adding Ajax autosave functionality
- •11.5.1 Adapting the library
- •11.5.2 Autosaving the information to the database
- •11.6 Refactoring
- •11.6.1 Defining the constructor
- •11.6.2 Adapting the AjaxWindows.js library
- •11.6.3 Specifying the portal commands
- •11.6.4 Performing the Ajax processing
- •11.6.5 Refactoring debrief
- •11.7 Summary
- •Live search using XSLT
- •12.1 Understanding the search techniques
- •12.1.1 Looking at the classic search
- •12.1.3 Examining a live search with Ajax and XSLT
- •12.1.4 Sending the results back to the client
- •12.2 The client-side code
- •12.2.1 Setting up the client
- •12.2.2 Initiating the process
- •12.3 The server-side code: PHP
- •12.3.1 Building the XML document
- •12.3.2 Building the XSLT document
- •12.4 Combining the XSLT and XML documents
- •12.4.1 Working with Microsoft Internet Explorer
- •12.4.2 Working with Mozilla
- •12.5 Completing the search
- •12.5.1 Applying a Cascading Style Sheet
- •12.5.2 Improving the search
- •12.5.3 Deciding to use XSLT
- •12.5.4 Overcoming the Ajax bookmark pitfall
- •12.6 Refactoring
- •12.6.1 An XSLTHelper
- •12.6.2 A live search component
- •12.6.3 Refactoring debriefing
- •12.7 Summary
- •Building stand-alone applications with Ajax
- •13.1 Reading information from the outside world
- •13.1.1 Discovering XML feeds
- •13.1.2 Examining the RSS structure
- •13.2 Creating the rich user interface
- •13.2.1 The process
- •13.2.3 Compliant CSS formatting
- •13.3 Loading the RSS feeds
- •13.3.1 Global scope
- •13.3.2 Ajax preloading functionality
- •13.4 Adding a rich transition effect
- •13.4.2 Implementing the fading transition
- •13.4.3 Integrating JavaScript timers
- •13.5 Additional functionality
- •13.5.1 Inserting additional feeds
- •13.5.2 Integrating the skipping and pausing functionality
- •13.6 Avoiding the project’s restrictions
- •13.6.1 Overcoming Mozilla’s security restriction
- •13.6.2 Changing the application scope
- •13.7 Refactoring
- •13.7.1 RSS reader Model
- •13.7.2 RSS reader view
- •13.7.3 RSS reader Controller
- •13.7.4 Refactoring debrief
- •13.8 Summary
- •The Ajax craftsperson’s toolkit
- •A.1 Working smarter with the right toolset
- •A.1.1 Acquiring tools that fit
- •A.1.2 Building your own tools
- •A.1.3 Maintaining your toolkit
- •A.2 Editors and IDEs
- •A.2.1 What to look for in a code editor
- •A.2.2 Current offerings
- •A.3 Debuggers
- •A.3.1 Why we use a debugger
- •A.3.2 JavaScript debuggers
- •A.3.3 HTTP debuggers
- •A.3.4 Building your own cross-browser output console
- •A.4 DOM inspectors
- •A.4.1 Using the Mozilla DOM Inspector
- •A.4.2 DOM inspectors for Internet Explorer
- •A.4.3 The Safari DOM Inspector for Mac OS X
- •A.5 Installing Firefox extensions
- •A.6 Resources
- •JavaScript for object-oriented programmers
- •B.1 JavaScript is not Java
- •B.2 Objects in JavaScript
- •B.2.1 Building ad hoc objects
- •B.2.2 Constructor functions, classes, and prototypes
- •B.2.3 Extending built-in classes
- •B.2.4 Inheritance of prototypes
- •B.2.5 Reflecting on JavaScript objects
- •B.2.6 Interfaces and duck typing
- •B.3 Methods and functions
- •B.3.1 Functions as first-class citizens
- •B.3.2 Attaching functions to objects
- •B.3.3 Borrowing functions from other objects
- •B.3.4 Ajax event handling and function contexts
- •B.3.5 Closures in JavaScript
- •B.4 Conclusions
- •B.5 Resources
- •Ajax frameworks and libraries
- •Accesskey Underlining Library
- •ActiveWidgets
- •Ajax JavaServer Faces Framework
- •Ajax JSP Tag Library
- •Ajax.NET
- •AjaxAC
- •AjaxAspects
- •AjaxCaller
- •AjaxFaces
- •BackBase
- •Behaviour
- •Bindows
- •BlueShoes
- •CakePHP
- •CL-Ajax
- •ComfortASP.NET
- •Coolest DHTML Calendar
- •Dojo
- •DWR (Direct Web Remoting)
- •Echo 2
- •FCKEditor
- •Flash JavaScript Integration Kit
- •Google AjaxSLT
- •Guise
- •HTMLHttpRequest
- •Interactive Website Framework
- •Jackbe
- •JPSpan
- •jsolait
- •JSON
- •JSRS (JavaScript Remote Scripting)
- •LibXMLHttpRequest
- •Mochikit
- •netWindows
- •Oddpost
- •OpenRico
- •Pragmatic Objects
- •Prototype
- •Qooxdoo
- •RSLite
- •Ruby on Rails
- •Sack
- •SAJAX
- •Sarissa
- •Scriptaculous
- •SWATO…
- •Tibet
- •TinyMCE
- •TrimPath Templates
- •Walter Zorn’s DHTML Libraries
- •WebORB for .NET
- •WebORB for Java
- •XAJAX
- •x-Desktop
- •XHConn
- •index
- •Symbols
- •Numerics
Completing the search |
485 |
|
|
Figure 12.4
The search results are displayed from the Ajax live search.
page. Finally, we take the result we obtained from the transformToFragment() method and append it to the element. The newly formatted search results are now displayed to the user.
This code introduced some new concepts to us, including the XSLTProcessor object, which allows us to combine arbitrary XML and XSLT files. The Mozilla and Firefox browsers require us to use more DOM methods to combine the two documents. Internet Explorer, on the other hand, required only a single line of code to transform the XML document. The overall end result is exactly the same: they both show our results formatted according to the XSLT file.
Now that the client-side code is finished, we can save our documents and run a test of our live search. Enter some text into the textbox, and click the search button. The results should appear in the table format shown in figure 12.4.
As you can see, we have finished building our XSLT document and were able to run a successful search. The table displayed in figure 12.4 is rather dull since it has no formatting. That means the only thing that we have left to do is style our results table to make it more visually appealing. To do that, we need to use Cascading Style Sheets (CSS).
12.5 Completing the search
Now that we have combined our XML and XSLT documents to get our results, we need to enhance the style of the search results by applying CSS to our elements. Styling the elements will make it easier for the users to read the results. The first step in improving the user experience is to apply our CSS rules to the HTML elements.
12.5.1Applying a Cascading Style Sheet
We introduced Cascading Style Sheets in chapter 2. A Cascading Style Sheet will make the results look professional with a minimum amount of effort on our part, separating the presentation of the results from the document structure and from the transformation logic. Along the way, if the manager or client hates the colors, we can make the changes quickly and easily. If we’re on a large project with
486CHAPTER 12
Live search using XSLT
separate design and coding teams, CSS helps to keep them from treading on each other’s toes. We can either include the stylesheet as an external file on our search page or embed the code into the search page. Using an external CSS file is preferable since it is cached by the browser and decreases the page-loading time in the future. The stylesheet rules are shown in listing 12.9.
Listing 12.9 Cascading Style Sheet
table{
border: 1px solid black; border-collapse: collapse; width: 50%;
}
th, td{
border: 1px solid black; padding: 3px;
width: 25%;
}
th{
background-color: #A0A0A0;
}
b |
Style the |
|
table |
c Style the
table cells
d Style the
header cells
The first CSS rule we are applying is to the table tag b. In this case, we want to make the border a solid-black line one pixel wide. We set the table’s
property to collapse. The collapse CSS model basically allows the properties of the table to be uniform. The borders become even thicknesses, with adjacent cells sharing borders rather than accumulating to double or triple thicknesses. The final step for the table tag is to set the table width property. In this case, we are setting the width of the table to 50% of the div that it is contained in since we are not returning a large number of columns. Each of our columns will contain only a small amount of data, so the table does not need wide spacing.
After styling the table element, our next step is to format the table’s body and header cells c. Just as we did for the table, we are setting the border to be a solidblack one-pixel line. We insert padding into the cells so that the text is not sitting directly on the cell borders. We also set the width property of the cells to 25% of the width of the table so that all four columns are uniform in size.
The final step to apply CSS to our table is to change the properties of the header cell so it stands out from the body cell. We reference the header cell d and change the background-color of the cell to a shade of gray. We can change other properties here, such as font-weight, color, and so on. After we finish
Completing the search |
487 |
|
|
Figure 12.5
The search results are displayed from the Ajax live search with CSS applied to the elements.
applying the stylesheet properties, we save our document and run the same search again. Our new formatted table is shown in figure 12.5.
As you can see, the table has a structured format that was easily created by applying CSS properties to our table elements. If we wanted to add more functionality to our stylesheet, we could add class references to the XSLT file to make it even more flexible. CSS lets us customize the table any way we want, but we may want to improve the search in other areas as well.
12.5.2Improving the search
One of the benefits of Ajax is that it’s easy to pass information back to the server. This project was a simple exercise for creating a search utilizing Ajax and XSLT to display a formatted results table with a minimum amount of effort. We can make the live search as sophisticated as we want. Let’s look at some ways to improve it.
Including new features
The search form we created uses a single textbox and a single submit button to perform the search. We can easily adapt this search to use multiple parameters, such as additional search parameters with the contact name or country. All we have to do is send the additional parameters back to the server and have the server-side code check for them. That means the users can have additional ways to look for information, making the form more useful.
We could add other Ajax features to this script, such as the double combination script, as we did in chapter 9. This would help reduce the possibilities from which the user can choose. We can implement techniques from chapter 10 with the type-ahead suggest, too.
Supporting Opera and Safari
If you recall, we have a problem with Opera and Safari not supporting either the transformNode() method or the XSLTProcessor object. We have two options for supporting Opera and Safari. The first one is to use Ajax to send the files to a server-side page for processing. The server-side code can combine the XML and
488CHAPTER 12
Live search using XSLT
XSLT documents. We would then fetch the result of the transformation using a single ContentLoader object, rather than fetching the XML data and the XSLT stylesheet independently. This is not the best solution since we have to use two round-trips to perform the transformation.
Our second option is to submit the entire page back to the server without the use of Ajax. The server in this case would handle the submission and combine the XML and XSLT documents on the server as we would do traditionally. This approach is better because it lets all users use the search. If a person is using an early version of a browser that does not support the XMLHttpRequest object, then that user can use the form. If we used the Ajax-only technique, the people without the ability to use Ajax would not be able to retrieve the two files for processing. Our second approach gives them the ability to use the form since Ajax is not required. In order to add this functionality, we need to make two changes to the LoadXMLXSLTDoc() function, as shown in listing 12.10. We must alter the first if statement to include a check for the XSLT processor. Then we must add an else statement to force the submit back to the server.
Listing 12.10 Altering LoadXMLXSLTDoc to support Opera and Safari
function LoadXMLXSLTDoc(urlXML,urlXSL,elementID){ var reqXML;
var reqXSL;
if (window.XMLHttpRequest && window.XSLTProcessor){ //...do Mozilla client XSLT
}else if (window.ActiveXObject){ //...do Internet Explorer client XSLT
}else{
document.Form1.onsubmit = function(){return true;} document.Form1.submit();
}
}
In listing 12.10, we remove the onsubmit event handler inside the else branch of the conditional check so that we submit the form to the server. Without removing the onsubmit handler, the form would not submit back to the server.
The server-side page then has to do all of the processing and put the element on the form. In return, we get a fast response for those users who can combine XSLT with JavaScript, and we do not alienate the users who do not support Ajax or the XSLTProcessor. Remember that Ajax is giving us the benefit of not having to re-render the entire page, which can lose the current state of the page. We do not have to worry about the scroll position, form values, and so on. Since