Creating an Ajax Search Widget

WEBINAR:On-Demand

The most widely used function of the Web is searching. It's not even an option; if you want to find any information, the search engines of the Web are the places you have to go to.

With the ever-expanding technology of the Web, conventional search engines are opening the doors to more unconventional means to get you to the content you desire. The first to jump onto the scene was Yahoo! with their Y!Q service (http://yq.search.yahoo.com/publisher/index.html). This new service enables you to search from any web page, provided the page's author includes it in their web page. It is a service to provide related search results to the content at hand, giving readers more information at their fingertips without leaving your page.

The Yahoo! Y!Q service is a great idea, but it hasn't surfaced without criticism. The main argument? It requires the use of Yahoo!'s JavaScript and you have to add a <form/> element, meeting the Yahoo! requirements, to perform the search. For many web site authors, it takes too much effort to provide the service. And after all the work, the search results are presented in the Yahoo! style, breaking the look and feel of your web site.

Thankfully, Yahoo! isn't the only search engine breaking into this "provide search results from your web site" service. MSN Search (http://search.msn.com) provides a similar service, except it enables the web developer to control the look, feel, and implementation. This ability comes from MSN Search providing RSS versions of its search results, making it possible to subscribe to a particular search or add the results to your page using Ajax methods.

Google has yet to throw its hat into this new spin on "search from your site" technique, although, at the time of this writing, Google released Google BlogSearch Beta (http://blogsearch.google.com), which provides results returned in either RSS or Atom formats.

The Server-Side Component

Perform a search with MSN Search, and you'll see an orange XML image at the bottom of the results page. Clicking this image takes you to a new page, giving you the URL to subscribe to the search:

http://search.msn.com/results.aspx?q=[SEARCHTERM]&format=rss

With this knowledge, you can write the server-side code to retrieve the remote feed. For the widget, you will use PHP to retrieve the search feed. The URL to request information from the server application looks like this:

websearch.php?search=[SEARCHTERM]

There's only one variable in the query string: search. Therefore, the application should look for this query item. On the server, you'll need to create a page to pull this data:

The first two lines set the required headers so that the browser will handle the data correctly (as XML and without caching the results). The next line of code uses the isset() function to determine whether the search key is present in the query string.

The search term should go through a variety of functions in order to send a proper request to the remote host. First, it is passed to the stripslashes() function. If magic quotes are enabled in the PHP configuration (which is the default), any quote that reaches the PHP engine is automatically escaped with a slash: \"search query\". The stripslashes() function removes these escape sequence, leaving only "search query". After the slashes' removal, it then goes to the urlencode() function, which properly encodes characters to be used in a query string. Spaces, quotes, ampersands, and so on are all encoded.

If the search term does not go through these processes, the MSN server will return a code 400: Bad Request.

When the search term is ready for transmission, it is included into the URL and stored in the $url variable. Finally, the file_get_contents() function opens the remote file, reads the contents, and returns it as a string to the $xml variable, which is printed to the page using the echo command.

The Client-Side Component

The client-side code from this widget is based on a static object called msnWebSearch, which is defined as an object literal without any properties (for now):

var msnWebSearch = {};

This object is used in the onclick event of an HTMLElement in order to perform a search:

The msnWebSearch object exposes several methods to get the search results and to draw and position the HTML to contain the data. The first method is drawResultBox(), which draws the HTML. The HTML this method draws looks like this:

The result box is divided into two parts: a heading and a results pane (see Figure 1). The heading tells the user that this new box contains results from an MSN search. It also contains an X, which will close the box. The results pane contains block-style links, which opens a new window when clicked.

These first lines create the HTML elements via the createElement() method. After the elements have been created, you can begin to assign their properties. The first two elements to finalize are aCloseLink and divHeading:

The first four lines complete the link that closes the result box. A method, close(), becomes the handler for the link's onclick event. The next group of lines populate the heading <div/> with text and the closing link.

When this result box is drawn into the page, a response from the server application has not been received yet. To show the user that something is happening (other than a box popping out of nowhere), it would be nice for the user to see a message stating that data is loading (see Figure 2). To do this, create another element and append it to the divResultsPane element:

The way the msnWebSearch object is set up, divSearchBox must be returned to its caller for other operations. The position() method, as you may have guessed, positions the search box. It accepts two arguments: the event object passed to drawResultBox() and the divSearchBox element:

The first two lines get the left and top positions to place the search results box. Two pieces of information are required to perform this operation. First is the x and y coordinates of the mouse. This information is stored in the clientX and clientY properties.

These coordinates, however, are insufficient to properly position the results box because the clientX and clientY properties return the mouse position in relation to the client area in the browser window, not the actual coordinates in the page. To account for this, use the scrollLeft and scrollTop properties of the document element. With the final coordinates calculated, you can finally position the box where the user clicked the mouse.

Displaying the Results

The populateResults() method populates the result pane with the search results. It accepts two arguments: the element to contain the results and an XParser object (XParser is a JavaScript-based RSS reader freely available for download from www.wdonline.com/javascript/xparser/):

This method generates <a/> elements programmatically with DOM methods, so these elements will be appended to a document fragment created in the first line. The next line removes the loading <div/> element appended in drawResultBox().

Creating an Ajax Search Widget

WEBINAR:On-Demand

Closing the Results Box

To close the search results box, the msnWebSearch object provides the close() method. If you'll remember from the drawResultsBox() method, the close() method handles the onclick event of the link responsible for closing the box:

The search box isn't really closed; in fact, it is removed from the document. To do this, retrieve the divSearchBox element. The first line does this by retrieving the parent node of this element's parent. Because close() handles the onclick event, this references the link. The next line removes the divSearchBox element from the document. The last line, return false, forces the browser not to follow the default behavior of a link (going to the location noted in the href attribute).

Building the Search Interface

The last method of the msnWebSearch object is search(), which provides the interface to perform a search. You can call search() with the onclick event of an element. It accepts two methods, an event object and the search term:

The first line calls the drawResultBox() method and passes the event, e, to it. The next line encodes the URL for proper transmission. This URL is passed to the XParser constructor to create a new parser. The parser's onload event handler calls the populateResult() method when the search feed is finished loading to populate the search box with results.

Of course, one of the reasons for building this widget is to make it fit the look of your own site.

Customizing the Web Search Widget

Thanks to CSS, you can easily customize the widget for your existing site and any redesign you may have later down the road.

The first CSS class discussed is ajaxWebSearchBox, the class for the search box. Because the box is positioned, it must have a position of absolute:

The absolute position is the only requirement. All other properties are optional according to your tastes. In this example, the box has a darkish-blue background, a width of 500 pixels, and 1 pixel of padding on all four sides. This padding will give the box a 1-pixel border around the box's contents.

The next class is ajaxWebSearchHeading, which contains the box's heading text and the closing link. To position the closing link in the top-right corner, it is absolutely positioned. Because of this, it requires ajaxWebSearchHeading to have a position of relative:

Once again, the only required property is the position property. The remaining properties help to give the element a heading look. The background color is a lighter blue with white, bold text 14 pixels high and in the Tahoma font. The element's height is 21 pixels and is padded on the top and left edges.

The element is positioned 5 pixels from the right and 3 pixels from the top, placing the element in the top-right corner. This link does not have any text-decoration and is colored white. When the user hovers over the link, the text color turns red.

Notice that no visited or active pseudo classes are used. This is because the window always ignores the href attribute of this link (it has return false in its event handler). Therefore, the link is never truly active or visited.

Next, the ajaxWebSearchResults class styles the results pane:

.ajaxWebSearchResults
{
background-color: #d3e5fa;
padding: 5px;
}

There are no required CSS properties for this element. The existing properties are merely to define the results pane and make it relatively easy to read. The background color is a light blue, and 5 pixels of padding surround the edges. You can also style the loading message:

This element does not have a class name, but you can still style it by using the parent child notation shown in the preceding example. This example places the text in the center of the <div/> element and gives it a bold, blue font 14 pixels high.

The last elements you need to style are the result links. These have a class name of ajaxWebSearchLink:

The only required property is the display property, which is set to block. This gives every link its own line. The padding, two pixels worth, gives a bit of separation between the links, making them easier to read. The font-face is Tahoma and is 12 pixels high. Their color is a dark blue, giving a nice contrast to the light blue background of ajaxWebSearchResults.

When the user hovers over these links, the background color is set to blue, whereas the text color changes to white.

The visited pseudo class is set, in the last rule in the previous code. This is to provide users with user interface cues they are already used to. By having the visited pseudo class set to display a color of purple, users know they've already visited that link, which can save them time by not visiting a page they may not want to.

Now, let's take a look at how to implement the widget.

Creating an Ajax Search Widget

WEBINAR:On-Demand

Implementing the Web Search Widget

Implementing this widget is simple. First, you must upload the websearch.php file to your web server (of course, PHP must be installed, too). Next, you need an HTML document to reference all the components. The msnWebSearch object relies on the XParser class, which in turn depends on the zXml library (available at www.nczonline.net/downloads/). You must reference these files:

The first new link performs a search for the exact phrase Professional Ajax, whereas the second searches for all the words. Also note the return false in the onclick event. Once again, this forces the browser to ignore the href attribute and is required. Clicking these links will draw the search box at the mouse's cursor, and you'll have the search results just pixels away.

About the Author

Jeremy McPeak

Jeremy McPeak works in the IT department of a school district and has experience developing web solutions with JavaScript, PHP, and C#. He is co-author of Professional Ajax (Wrox, 2006, ISBN: 0-471-77778-1).

Advertiser Disclosure:
Some of the products that appear on this site are from companies from which QuinStreet receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. QuinStreet does not include all companies or all types of products available in the marketplace.

Thanks for your registration, follow us on our social networks to keep up-to-date