LiveInfo is directly evolved from Livesearch. If you don’t know what liveSearch is, liveSearch allowed users to search a website while still viewing the current page. The original can be seen here. Wanting to make use of liveSearch for one of my own projects, I proceeded to make some changes from which evolved LiveInfo. LiveInfo is a framework for multiple, real time, skinnable updatable elements within a web page. You can see LiveInfo in action on my blog where there are two LiveInfo elements. One is the blog search and the other is the UK TV listings (SynTV) search on the side.
From the client side, LiveInfo improves upon the original in the following areas:
- Support for more browsers
- Internet Explorer 5+ (Win)
- Gecko based browsers
- Opera 7+
- Should work with IE Mac, Konqueror etc. Needs testing
- Multiple LiveInfo elements on one page
- Pageable results (Keyboard navigation via left, right, up and down keys)
- Support for multiple element forms
Utilising a small backend framework, LiveInfo also provides the following functionality
- Cacheable Results
- Dynamic forms
- Skinnable Results
- Plugin support (services)
- Webservices support (via plugins)
LiveInfo comes with four services. These are as follows:
- Wordpress search – Searches a wordpress blog
- Google Search – A simple Google search. Uses Googles SOAP API.
- SynTV Search – Search UK TV listings using the syntv.com XMLRPC webservice
- SynTV Listings – Displays UK TV listings using the syntv.com XMLRPC webservice
The latest version of liveInfo can be found on my downloads page.
Extract the zip and upload the liveInfo directory to your server. I recommend uploading it to the root directory. Wherever you upload it, edit the liveInfoDir node in the liveInfo/liveInfo.xml file to point to it. The value should be a relative path and must not have an ending /. Any new services should be copied into the services directory and any css files into the css directory. Lastly make sure the cache directory is writable. You’ll need to edit the xml file for each service to suit your install but instructions are given
How it works
When a user interacts with a form, using either the XMLHttpRequest object or an iframe depending on browser capability, a request is made to the server. Whatever the results the server returns some XML from which the relevant elements are extracted and displayed.
The xml document that is returned by the server is actually an XML document with a html namespace. The reason for this is that the normal method of using innerHTML to rewrite elements won’ work on some browsers that support true XHTML documents (xml files sent with the correct application/xhtml+xml header). The workaround for this is to use the document.importNode method to import nodes from one document into another. Note this compatibilty with true XHTML documents was one of the last features to be put in and hasn’t yet been tested fully on true XHTML documents. I will update when I test more fully.
The XMLClient object
For browsers that can make use of the XMLHttpRequest object, the xmlClient simply instantiates the XMLHttpRequest object and sends the request through. For those browers that don’ have have XMLHttpRequest capability, it uses iframes. Unfortunately, its not easy to detect when a page has finished loading within an iframe so we check for a close tag for a specifed tagName which we call a closureNode (also the root node). When we encounter this, we extract and return the results.
The LiveInfo Object The LiveInfo object is really quite customisable. There a few other elements besides the actual results to display. There is a title element, a status element to display information, the page controls and other UI elements. The methods available to customise different aspects of the liveInfo page element.
The constructor for the object takes four parameters. The first is the url for the liveinfo.php. The second and third are the service name and operation name respectively. The last parameter is the name or id of the nominated form element that is to trigger the liveInfo display. There can be more than one element that triggers liveInfo but only one can be the nominated element. The nominated element is also checked for text input if it is an text field or that a choice is selected if a select element.
The status text that is displayed on various events (search, error, progress,result) is fully customisable and is based on using a token within a string which is replaced with the required value. This allows a degree of support for other languages. The default token is “?” but this can be changed with the setStatementToken method. There are four statements and these can be changed via the setSearchStatement, setErrorStatement, setProgressStatement and setResultStatement methods.
Like the original, the results are navigable via the keyboard but this can be turned of via the setActivateKeys method.
The amount of time (in secs) the results are shown before automatically disappearing can be changed from the default of 5 seconds using the setDisplayTimeout method.
Debugging can be turned on or off via the setDebug method
When a user hits the return key, the form defaults to submitting the form to the required page. This behaviour can be turned off with the setSubmit method.
We can also add a custom method that is called whenever the liveInfo is triggered but before the request is sent. An example of why we might want to do this is to sent the field of a hidden value to something depending on the value of others form elements. To add this custom method we use the addOnTriggerMethod which takes a function as a parameter.
The default validation method in liveInfo simply checks that text is entered in text field elements and that at least one option is selected for select elements. You can replace this with a custom validation method using the replaceValidateMethod method. Like addOnTriggerMethod, this takes a function as a parameter.
Examples of calling these methods can be seen below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
The framework is currently coded in PHP but it should be easily ported to other languages.
The plugin architecture is based on an abstract class called liveInfo. This class and all plugins (services) have an associated xml file which defines configuration values. The liveInfo.xml file contains default configuration values for the system. The xml files for services can override the values in the default xml file. For instance, the liveInfoContainer node contains the html (div container) that displays the results and pagecontrols. This can be used by all services or a service can have a liveInfoContainer node in its xml file which is used instead. This is what makes liveInfo skinnable. Every service also has an associated class which is a subclass of the liveInfo class.
The best way to describe how liveInfo is to use an example. The next two sections describe how to put a liveInfo element on a page and how to write a service.
Putting liveInfo on your page
We’ll use the google service as an example. The google service displays results from Google.
Inside the head section of your page or template, put the following bit of php
1 2 3 4 5 6 7
Also in the head section we need to load the js files and create the function that is called when the document has loaded. This function creates all the liveInfo objects for each of the services on the page
1 2 3 4 5 6 7 8 9
1 2 3
Now within your page or template, wherever you want, you can output the form and result HTML with the following:
And that’s it. The actual form and html is actually defined in the service xml, which is what we’ll look at next.
Default values are stored in liveInfo.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The liveInfoDir points to the install directory of liveInfo. This is used by the js liveInfo object. The cacheTTL node defines the default time in seconds to cache the service. This can be overridden by a service. The cssLink points to the location of the default css stylesheet. This can also be overridden by a service. Also overrideable by a service is the liveInfoContainer node. This defines the HTML that is displayed when results are shown. The [<infoname>][<opname>] is used as placeholders and is replaced by the serviceName and opName in the final output on a page eg googleSearch. The structure of this node can change but note that the event handlers, id and class names should be the same. You should be able to add new elements also.
The google service xml looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
The name, description and link nodes are there for informational purposes about the service. On line 6 we can see that this service is set to cache for only 15 mins. The key, q, lr, start, maxresults, filter, safesearch and restrict nodes are google webservice parameters. If a service needs service specific config values, they can be defined here in the xml and the service will pick it up.
It’s possible that a form element is dynamic. For instance, a select element’s options are loaded from the database. In this case, we can specify a method to call which will output the element. To do this we put the following in the relevant place. An example
When the service encounters the node, it calls the getDays method and inserts the return value in the form
An abstract class called liveInfo defines the interface which any service must implement. It also provides some helper methods for outputting xml, debug info and caching methods. The constructor looks like this.
1 2 3 4 5 6 7 8
The Google webservice is a soap service. Besides the liveInfo abstract class, the liveInfo framework is supplied with two subclasses called rpcLiveInfo and soapLiveInfo. These subclasses include the required library for using XMLRPC or SOAP. So if your service uses XMLRPC or SOAP you should subclass one of these methods. If not, then you should just subclass the liveInfo class. Its important that you do this and call the parent constuctor (see line 5). Calling the parent constructor, loads the default liveInfo.xml then calling the initialise() method, loads the service’s xml file initialising the object with the data in the xml file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
When a request from a liveInfo page element, its the getLiveInfo that is called. If cache is needed we get a cache object by calling the getCache method, then we call the getSearch method via the cache object’ call method. If a cache is not needed, then we would just call the getSearch method directly. Then the results are packaged for return. Note also debug data is also added if debug mode is on. The getSearch method sets up the SOAP call, contacts the webservice and passes the results to the renderResults method which returns them nicely formated into an unordered list.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The resulting document for a search for “news” looks like this : (debug mode turned off)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
If there were no results, the liveInfoResult would be replaced by a liveInfoNoResult node. If there was a fault of some sort, then the liveInfoResult node would be replaced by a liveInfoFault node.
If debugging is turned on, then liveInfo outputs the debug output that is received form the server to an element that is identified by the id of serviceName+opName+_liveInfoDebug giving (for wordpress search) wordpressSearch_liveInfoDebug. You can also do some direct checking by inserting the liveInfo url into your browser with the required parameters. For example, for wordpress, the url would be [path to liveInfo]/liveInfo/liveInfo.php?liveInfo=wordpress&opName=Search&s=rpc
Make install easier with less or ideally no editing of xml files needed