Today part of the Web is driven by dynamically generated content. This content is primarily stored in databases, which is used by an application or middle layer to format the data to HTML. The web server then sends the content to the browser. The browser receives the web page as the end result and has no knowledge that the page was generated on the server -- just that it is a properly formatted HTML file. By using these same conventional principals, we can send generated or database-driven XUL, CSS, or JavaScript to Mozilla. Because XUL is a document that creates a UI, this widget drawing capability opens up a whole new world to web application development.
If you are a web developer creating database-driven applications, you will quickly see the limitations of using a simple markup like HTML -- for example, being constrained to the content area of a browser for which you cannot manage all of the application interface's "real estate." Using a browser window for your application is a common enough practice, but you still don't have the application-level widgets of most client-side applications when you use HTML. This section shows that using XUL files created by scripting languages allows you to create windows and applications that move out of the browser window and into the full-featured application space. Mozilla's origins, after all, are as a web browser and suite of Internet applications, and the latest technologies in the XPFE toolkit go that extra step to allow the presentation of UI information over the wire.
This section discusses the basic mechanics of server-generated content. In most cases, the actual content is static -- although the server application creates the page dynamically, the content itself is not input. It is also not created dynamically by other methods, such as using JavaScript to manipulate the client's document after it loads from the server.
To generate server-generated content, you need to use a scripting language. We explore the use of three different options: PHP, Perl, and Python. PHP is probably the most natural language for this application because it has its origins in serving up dynamic HTML, but you can play around with your favorite language and determine whether it has the appropriate capabilities for this environment. To use various scripting languages with Mozilla, you need a working knowledge of their capabilities; the scope of this book doesn't provide programming information for the selected scripting languages.
When users of your application may not have configured their browser to support the correct MIME type, you can use the PHP header function to send the browser the correct type.
Remember that when using XUL with PHP, you need to edit your php.ini file on the server and change the default configuration to:
short_open_tag = Off
By default, this configuration is set to "On." When "Off," this setting tells the PHP interpreter to parse only the files with escape tag identifiers, such as <?php ?> (and not <? ?>, which are used by XML). This process is separate from the XML parsing process that occurs when Mozilla receives and tries to render the generated content. If you don't change the .ini file, you will see an error like this:
Parse error: parse error in /usr/local/share/doc/apache/remote_xul.php on line 2
This error occurs when PHP sees your XUL syntax as invalid PHP code.
Once PHP is properly configured to handle XUL files, you're ready to go. To start out with something simple, use the code in Example 12-4 to produce a simple XUL window with the xFly logo by using PHP. Be sure to save the file with a .php extension.
Also remember that a space below the PHP tag results in a parse error in Mozilla. The next example shows the PHP header and the XML declaration at the start of the PHP file. The space between the two renders it invalid:
<?php header( "Content-type: application/vnd.mozilla.xul+xml" ); ?> <?xml version="1.0"?>
After PHP parses its content on the server, the rest of the document is sent to Mozilla on the client. Put this file (remote_xul.php) somewhere in your document root on the server with PHP installed and launch it from Mozilla like this:
./mozilla -chrome http://my.domain/remote_xul.php
The window defined in Example 12-4 now appears, displaying the image. You can take advantage of this relatively straightforward technique to serve up more feature-rich user interfaces, inclusive of buttons, menus, and any other pieces of XUL that are needed.
Although PHP is rising in popularity, Perl is still a very popular web-scripting language. Perl is often used to drive back end web applications with CGI scripts. To process Perl scripts, no extra configuration is needed once you have the Perl interpreter set up to run in a web server environment. If, for example, you're already using Perl to serve up dynamic HTML pages, you're all set. Otherwise, you should grab a distribution of Perl (http://perl.com/) and set up the paths to the binary files in your server scripts. This procedure is done by placing the path in the header, otherwise known as the shebang line. This script usually takes a form similar to #!/usr/local/bin/perl or #!/usr/bin/perl. You must also make sure that the server knows where the Perl executable is, which involves including the path to it in the systems PATH environment variable. Depending on the platform and the web server you use, other environments may need to be set.
Example 12-5 shows a simple CGI script that generates a minimal amount of XUL for display in the browser. Perl is useful for this task because you can set up several possible scripts and call selected ones, depending on what choices the user makes. You can even have different forks in the same script that displays different widgets or data. For example, imagine that your remote XUL application is an online travel planner. You would display maps, information, and links to resources based on the user's geographic location or preferences for destinations they entered earlier.
In Example 12-5, the MIME type must be specified as part of the first line in the CGI script after the shebang line, and rest of the script is the XUL code used by Mozilla. Although this example does not display real dynamic content (such as the kind you get from CGI forms or other user-supplied data), it shows how you can interpolate dynamic data into a simple CGI application model.
Like Perl, Python provides modules that make it easy to create CGI applications that generate content dynamically. Python is already an important language in the Mozilla environment because of the PyXPCOM bindings discussed in Chapter 8.
If Python is a language that you like to code in, using it in a remote XUL environment would also make sense. Python combines the features of a lower-level language like object-oriented class and function design with the flexibility and simplicity of a scripting language. The latter feature (ease of use) is relative to a language like C++. Example 12-6 shows how to use Python to create a simple form consisting of three checkboxes.
In this example, the CGI module is loaded with the Python import statement, and the form object is initialized so that data input to the page in the form of URL ?name=value pairs create the XUL content dynamically.
Example 12-6 takes a URL, such as http://www.brownhen.com/cgi-bin/xulgen?opt1=peter?opt2=paul?opt3=mary, and displays a checkbox for each value of the named form fields. The content type is printed before the XUL content to tell the web server what to pass when the script produces its output.
One of the important facets of dynamically generated content is interaction with a database to store and retrieve values for the user. For example, a public forum or subscription-based service could have a client that is written in XUL and requires authentication of users. Having such a client could require some form of database lookup. This section covers a simple example that uses data stored in a database to generate a XUL tree. We will use PHP to retrieve the data from the SQL-driven database and format it into XUL. Theoretically, this database could be any relational model, such as Oracle or MySQL.
Example 12-7 generates a simple tree listing with the columns "User" and "Project." The SQL script creates a table called "sample" and then inserts value pairs into the table. To use this type content generation, your database must be set up to handle table creation and dynamic updating via SQL calls.
The code in Example 12-7 creates a table with two fields, "User" and "Project." It then inserts four records into the newly created table in the database by using INSERT INTO calls. Now the script has tangible data to query.
Example 12-8 shows the creation of a simple XUL tree with PHP and a MySQL database. The "User" and "Project" columns display the data in the table.
The PHP header method is placed at the top of the file to properly format the output as XUL. The PHP MySQL APIs prepare the code for connection to a MySQL database. Finally, a loop is used to print out the stored data's treerows and treecells.
This kind of operation provides insight into the possibilities of using remote XUL when you have information stored in a database. Many web applications already do this via HTML forms and other mechanisms, but Mozilla's XPFE toolkit provides a richer widget set than HTML to display and retrieve information (see the section Section 3.6).
Some XUL widgets are created specifically to display complex tabular data such as <tree>, and some widgets provide user selection such as <checkbox>, <radio>, and <textbox>, plus the CSS used for controlling presentation. All of these widgets can be generated on the fly from the database and used to accept user-inputted information.
Unfortunately, localizing remote applications is a not as straightforward since there is no http: protocol equivalent for chrome:-included locales. You could use HTTP/1.1 content negotiation to serve the users-preferred language, but Mozilla 1.0 does not read DTD files over the wire. To overcome this problem, use server-side page processing. For example, this code includes the DTD by using PHP:
<!DOCTYPE window [ <?php require(PROJECT_PATH."/online/locale/xfly.dtd"); ?> ]>
Therefore, the served page looks like this:
<!DOCTYPE window [ <!ENTITY fileMenu.label "File"> <!ENTITY fileMenu.accesskey "f"> ... ]>
The only caveat for this approach is that you need a method to filter the entities, depending on which language is loaded. Obtaining a method could be done by reading in the locale and outputting the entities or by calling a separate script. This overhead is not necessarily high, as multiple files exist for multiple languages in a client distribution. A remote application would require the same process, but in a different format.