Previous Page TOC Next Page See Page



- 19 -
A Search Engine Interface with JavaScript


When JavaScript first became available with beta versions of Navigator 2, some of the earliest applications developed using HTML and JavaScript included search engine front-end pages. These would provide a single form that could be used to select multiple search engines for a single query.

The results would usually be presented in multiple frames in the same window. All the processing to handle the calls to the various search engines was executed at the client end.

This chapter walks you through the development of just such an interface to multiple search engines. This application highlights several techniques, including the following:


The Search Engine Interface Requirements


The search engine interface you are developing has several basic requirements:

In addition, to keep the queries simple, especially in light of the fact that each search engine has its own way of encoding URLs for Boolean queries, the searches will be restricted to single term keyword searches.

Source Code for the Search Engine Interface


The source code for this application is divided into two files: the main search form document and a small HTML file. The HTML file provides a control on the search results page, enabling easy access back to the main search form.

The source code for the main search form document is:

<HEAD>
<TITLE>JavaScript Web Search Tool</TITLE>
<SCRIPT LANGUAGE="JavaScript">
var url = new Array(4);
url[0] = new urlObj("http://www.altavista.digital.com/cgi-bin/query?pg=q&what=web&fmt=.&q=","AltaVista");
url[1] = new urlObj("http://www.hotbot.com/search.html?_v=1.0&OP=0&SM=MC&SW=&MOD=0&date=WH&DR=newer&DM=1&DD=1&DY=96&DV=10&DU=years&smiley=&RD=AN&RG=NA&domain=&DC=10&FJS=off&FJA=off&FRA=off&FAC=off&FSW=off&FVR=off&FSU=off&FSM=off&OP=0&MOD=0&search.x=55&search.y=16&MT=","HotBot");
url[2] = new urlObj("http://www.lycos.com/cgi-bin/pursuit?query=","Lycos");
url[3] = new urlObj("http://guide-p.infoseek.com//Titles?col=WW&sv=IS&lk=noframes&qt=","InfoSeek");
function urlObj(url,title) {
    this.url = url;
    this.title = title;
}
function changeNumber(number) {
    var toSelect;
    for (i = 1; i <= number; i++) {
        toSelect = (document.search.elements[i].options[0].text == 'Unavailable') ? i - 1 : document.search.elements[i].selectedIndex;
        for (j = 0; j < url.length; j++) {
            document.search.elements[i].options[j].text = url[j].title;
        }
        document.search.elements[i].options[toSelect].selected = true;
    }
    for (i = number + 1; i <= url.length; i++) {
        for (j = 0; j < url.length; j++) {
            document.search.elements[i].options[j].text = 'Unavailable';
        }
    }
}
function doSearch(number) {
    var frameSize = Math.floor(85 / number);
    var searchWin = window.open("","searchWindow");
    searchWin.document.open("text/html");
    searchWin.document.write('<FRAMESET ROWS="15%,*');
    for (i = 1; i < number; i++) {
        searchWin.document.write(',' + frameSize + '%');
    }
    searchWin.document.writeln('">');
    searchWin.document.writeln('<FRAME SRC="control.html">');
    for (i = 0; i < number; i++) {
        searchWin.document.write('<FRAME SRC="' + url[i].url + document.search.term.value + '">');
    }
    searchWin.document.writeln("</FRAMESET>");
    searchWin.document.close();
    searchWin.focus();
}
function displayMenus() {
    document.write('<TABLE>');
    document.write('<TR>');
    document.write('<TD>');
    document.write('Number of Search Engines:');
    document.write('</TD>');
    document.write('<TD>');
    document.write('<SELECT NAME="number" onChange="changeNumber(this.selectedIndex + 1)">');
    for (i = 1; i < url.length; i++) {
        document.write('<OPTION>' + i);
    }
    document.write('<OPTION SELECTED>' + url.length);
    document.write('</SELECT>');
    document.write('</TD>');
    document.write('</TR>');
    for (i = 1; i <= url.length; i++) {
        document.write('<TR>');
        document.write('<TD>');
        document.write('Search Engine ' + i + ':');
        document.write('</TD>');
        document.write('<TD>');
        document.write('<SELECT NAME="engine' + i + '">');
        for (j = 0; j < url.length; j++) {
            document.write('<OPTION VALUE="' + url[j].url + '"');
            document.write((j == i - 1) ? ' SELECTED>' : '>');
            document.write(url[j].title);
        }
        document.write('</SELECT>');
        document.write('</TD>');
        document.write('</TR>');
    }
    document.write('<TR>');
    document.write('<TD>');
    document.write('Search for the term:');
    document.write('</TD>');
    document.write('<TD>');
    document.write('<INPUT TYPE=text NAME="term" SIZE=20>');
    document.write('</TD>');
    document.write('</TR>');
    document.write('</TABLE>');
    document.write('<HR>');
    document.write('<INPUT TYPE=button NAME="search" VALUE="Start Search" onClick="doSearch(this.form.number.selectedIndex + 1)">');
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="cornsilk" TEXT="#020A33">
<DIV ALIGN=CENTER>
<FORM NAME="search">
<H1>Search the Web</H1>
<HR>
<SCRIPT LANGUAGE="JavaScript">
displayMenus();
</SCRIPT>
</FORM>
</BODY>

The source code for the control button document is as follows:

<HEAD>
<TITLE>JavaScript Search Engine</TITLE>
</HEAD>
<BODY BGCOLOR=black TEXT=white>
<FORM NAME="controls">
<DIV ALIGN=CENTER>
<INPUT TYPE=button VALUE="New Search" onClick="parent.opener.focus()">
</DIV>
</FORM>
</BODY>

The Interface form


The first piece of the script to examine is the form providing the user interface.

The form's main controls are drop-down select lists, defined using the <SELECT> and <OPTION> tags, plus a text field for the search term and a button to execute the search.

The menu itself is built by calling displayMenus(), which produces results similar to those shown in Figure 19.1. This function is discussed later in this chapter.

Figure 19.1. The main menu of the application.

Two event handlers provide the menu's interactivity. The onChange event handler in the first menu (Number of Search Engines), adjusts the other menus according to the number selected by the user. The onClick event handler for the button calls the doSearch() function to execute the search.

Configuring the Search Engines


The first part of the script is where the number, names, and URLs of the search engines to use are configured. The process is simple—an array called url needs to be created. Each entry in the array is an instance of the urlObj object defined by the function of the same name. Each of these objects has two properties: url, which indicates how to call the search engine, and title, which provides the name to display for the given search engine in the menus.

Each of the provided URLs should be coded so that simply concatenating a single search term to the end of the URL creates a valid URL for the given search engine.

The property url.length is used throughout the script when the number of search engines is required for processing.

The displayMenus() Function


This function displays the search form based on the number of entries in the url array.

First, a select menu from which the user can choose the number of search engines to search is built by including one <OPTION> tag for the total number of entries in url. This is done by a for loop iterating from zero to the value of url.length.

Next, a separate select menu is built for each entry in the url array. That is, if url contains four entries, then you want to build four select menus.

Each menu displays the titles of all the search engines specified in the url array. Each menu, however, has a different search engine selected by default.

This is done using a conditional operator to ensure that in the first menu, the first search engine is selected, while in the second menu the second entry is selected ,and so on.

Finally, a text field and a button are output by the function, completing the form.

The changeNumber() Function


The changeNumber() function is called when the user changes the number of search engines selected in the first drop-down select menu.

The function is called by the onChange event handler of the menu and takes one argument: one greater than the index number of the entry selected in the menu. A value one greater than the index is passed because if the user chooses three search engines, then the index is two because the indexes start at zero.

The function itself has two roles: It has to correctly display the number of search engine menus specified by the user's choice and then it has to clear the remaining menus to an unavailable state, like the one shown in Figure 19.2.

Figure 19.2. When a menu is not available, all its entries are changed to unavailable.

The first step involves a for loop that iterates from one to the number selected by the user. For each of these iterations, the appropriate menu in the form is redefined to display all the URLs in the url array. The only caveat is that if the menu was not unavailable before calling changeNumber (in other words, it was an active menu), then the user's previous selection should not be removed. If the menu was previously unavailable then the default selection is displayed.

The actual process is accomplished by assigning the titles of the URLs to each of the options in the selection list. To do this, the URLs are assigned to the text properties of these options. The selected property of the appropriate option is set to true to force it to be the default selection.

Next, another for loop iterates from the next menu to the last—those that should be unavailable—and sets all the options of each menu to an unavailable state by assigning "Unavailable" to the text properties of those options.

The doSearch() Function


This function is called when the user clicks on the "Start Search" button in the main search form. It takes one argument: one greater than the index of the number of search engine selected by the user in the first drop-down menu.

The function opens a new window and opens a frameset in it with one frame for each of the search engines, plus an extra frame for a control button.

The frames are in rows, with the top frame taking 15 percent of the available window space and holding the control button. The search engines evenly share the remaining 85 percent of the window space. So, the first step is to define the frame size for each of the search engine frames by dividing 85 by the number of search engines being used and dropping the values after the decimal point using Math.floor().

After this step, a window is opened, and the frameset is defined with the correct number of rows using a for loop to ensure the correct number of entries appear in the value of the ROWS attribute.

Next, the file control.html, which contains the control button, is assigned to the first frame and a for loop is used to assign the correct search engine URL to each of the subsequent frames.

This is accomplished by getting the index number of the selected entry in each of the active menus and combining the URL at that index in the url array with the user's search term.

Finally, after the frameset has been built and the document stream is closed, focus is given to the window by calling the window's focus() method to ensure the window is at the front.

This produces results like those shown in Figure 19.3.

Figure 19.3. The search results window.

The Control Button


The control button provided in the search results page offers a one-click way to bring the main search form window to the front.

This is accomplished by an event handler for the button that calls the focus() method of the window object specified by parent.opener. The opener property is the object for the window containing the script that opened the current window (in this case, the main search form window).

Summary


In this chapter you learned how to implement a simpler application than those introduced in the two previous chapters.

Still, this simple application demonstrates how a small script, effectively used, can provide a useful and functional application.

In this case, three simple functions and two HTML files created a multi-window interface to any number of search engines. After all, there's no reason why the url array can't be defined to include 10 or even 20 search engines rather than the four used throughout this chapter.

In the next chapter we will look at our fourth application. We will develop a client-server application using server JavaScript running on a LiveWire-based system.

This chapter will use server-JavaScript to enable a user to create a personalized home page which the user can configure and persists between sessions.

Previous Page Page Top TOC Next Page See Page