One class of extensions that most browsers support is the addition of panels that a user can have open whilst they are browsing. For example, you might create a side-bar that allows searches to be carried out, with the advantage over a normal search in the browser window that you don't lose your list when stepping through the results.
There are many terms used for these kinds of panels. We'll take the following as our definitions:
Any XHTML document can be used as a side-bar, footer bar, toolbar or explorer bar. This makes it very easy to build bars that extend your browser, and all that we need to do is to let the browser know where to find the XHTML documents. We do this not be creating standard desktop installers, but by creating XForms that call the Soft-bar Installer API. This API provides functions to add and remove bars.
This tutorial will show how to use the API to create an installer, and to illustrate the technique we'll place the del.icio.us bookmark form created in the Introduction to XForms in a side-bar. In order to illustrate how any document can be used as a 'soft bar', we won't make any changes at all to the bookmark form, with all the work being done by the installer.
The sample and source code are available from here.
Tutorial reviewed on 2006-12-07, by MB.
TODO: Incorporate material from A del.icio.us Link Manager Written in XForms.
To create a side-bar we need two things; an XHTML document that will provide the functionality of the side-bar, and an installer that will wire the side-bar into the browser. The XHTML document we will use is the del.icio.us bookmarking form that we create in the Introduction to XForms. We'll use this partly because it's a useful form, and partly to show that any XHTML document can be used as a side-bar.
The installer will have to be created from scratch, but since it is just a normal XForm we can use the usual template as our starting-point. We'll begin by setting the document's title:
<title>Soft-bar Installer</title>
</head>
To access any external function library in XForms you need to provide a reference to a namespace that identifies the library, and you need to indicate the functions you want to access in the functions attribute on the model. So the first step is to add the following namespace to the top of the document:
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sb="urn:formsplayer.com/softbars"
>
<head>
Now add a model which will contain the data about the soft-bar we will be installing, and reference the functions that will be called to do the adding and removing:
<title>Soft-bar Installer</title>
<xf:model id="m-soft-bars" functions="sb:GenerateBar sb:RemoveBar">
...
</xf:model>
</head>
To make it easy to reuse this installer form for other bars, we'll put all information that is specific to our del.icio.us side-bar into an external XML document. Create a document called delicious-sidebar.xml that contains the following:
<bar retval="0">
<type>2</type>
<screenshot>http://static.flickr.com/142/319487219_f598c70667.jpg</screenshot>
<internalName>fpdelicioussidebar</internalName>
<name>del.icio.us Sidebar</name>
<description>
The del.icio.us Sidebar allows you to quickly add a bookmark to del.icio.us
for a document that you are viewing in the main browser window.
</description>
<uri>http://svn.x-port.net/svn/public/samples/del.icio.us/howto.html</uri>
</bar>
type, internalName, name and uri correspond to the parameters needed by sb:GenerateBar, whilst screenshot and description are used in the form, as we'll see in a moment.
To make the configuration parameters available to the form, we need to load it into an instance, so next add the following mark-up to the model:
<xf:model id="m-soft-bars" functions="sb:GenerateBar sb:RemoveBar">
<xf:instance src="delicious-sidebar.xml" />
</xf:model>
Part of the information in the configuration file is for the calls to the Soft-bar API, and some of it is just to improve the appearance of our form. Add the following controls to the body element, which will give the user some information about the soft-bar being added:
<body>
<h1><xf:output ref="name" /></h1>
<xf:output
value="concat('
<img src="',
screenshot,
'" />'
)"
/>
<div><xf:output ref="description" /></div>
</body>If you save and refresh the form, you should see a heading of the name of the soft-bar, a screenshot (if there is one), and a description of what the bar does.
The next piece we need to add is the code to install the bar. For this we have to use the sb:GenerateBar method, which is available to us because we specified the library in the functions attribute. We have to call the function from an XPath expression, and since we want the returned value (so that we know if it succeeded or not) we'll use the setvalue action. We'll put the setvalue inside an action handler that is listening for the event my-install-bar; place the following in the model element:
<xf:instance src="delicious-sidebar.xml" />
<xf:action ev:event="my-install-bar">
<xf:setvalue
ref="@retval"
value="sb:GenerateBar(
string(../type),
string(../internalName),
string(../name),
string(../uri)
)"
/>
</xf:action>
</xf:model>
Once the function returns we'll be left with either "Success" or an error message in the retval attribute. We can make use of this by following the setvalue action handler with a message:
/>
<xf:message level="modal">
'<xf:output ref="name" />'
has
<xf:output value="
if(
@retval = 'Success',
' been added. You will need to open a new browser
window to see the change.',
concat(
' failed to install. The error is "',
@retval,
'".'
)
)"
/>
</xf:message>
</xf:action>
The effect of this is to always show a message after installing, but the text of the message will depend on whether the installation was successful or not--with the if function being used to determine which.
To allow the user to install the bar, all we need do now is provide a button that will invoke the my-install-bar event. We'll put it after the other controls:
<div><xf:output ref="description" /></div>
<xf:trigger>
<xf:label>Install</xf:label>
<xf:dispatch ev:event="DOMActivate"
name="my-install-bar" target="m-soft-bars"
/>
</xf:trigger>
</body>
To complete the form we need to add an event handler and button for removing the soft-bar. The handler will use the sb:RemoveBar function and pass it the internal name of the bar. Add the following to the model:
</xf:action>
<xf:action ev:event="my-remove-bar">
<xf:setvalue
ref="@retval"
value="sb:RemoveBar(string(../internalName))"
/>
<xf:message level="modal">
'<xf:output ref="name" />'
has
<xf:output value="
if(
@retval = 'Success',
' been removed. You will need to open a new browser
window to see the change.',
concat(
' failed to be removed. The error is "',
@retval,
'".'
)
)"
/>
</xf:message>
</xf:action>
</xf:model>
To invoke the handler we need another button:
</xf:trigger>
<xf:trigger>
<xf:label>Remove</xf:label>
<xf:dispatch ev:event="DOMActivate"
name="my-remove-bar" target="m-soft-bars"
/>
</xf:trigger>
</body>
In this example we'll show how to create a topbar that can be used to search Flickr for images that have a specific tag.
A common use for browser toolbars is to make it easy to search for some information and get the results directly in the main browser window. All the main search engines have such toolbars, usually created using C++ and distributed via standard installers. But using the formsPlayer soft-bar library, we can create handy browser extensions for Internet Explorer using barely a few lines of XForms. To illustrate, we'll create a toolbar that uses the recently published API documentation for the popular Prototype Javascript Framework.
The documentation is pretty straightforward. The page for the Element object is:
http://prototypejs.org/api/element
whilst the page for the Form object is:
http://prototypejs.org/api/form
Methods and properties on an object are also available directly, for example, the method Element.addClassName is available at:
http://prototypejs.org/api/element/addclassname
A simple form to access this information need be no more than one control and an action handler, so we'll begin with an input control to collect the topic of interest to the user:
<body>
<xf:input ref="topic">
<xf:label>Topic:</xf:label>
</xf:input>
<body>
This control allows the user to enter a search term, which is then stored in a node called topic. Once the user has entered a topic to search for we want to use the value in topic as part of the URL, just as we illustrated above. We need to make one small change though, and that is we'd like a user entering element.addclassname to be taken to:
http://prototypejs.org/api/element/addclassname
To achieve this, we'll replace any periods with '/', and then add the result to the end of the basic URL for the documentation. The XPath for this is simply:
concat('http://prototypejs.org/api/', translate(topic, '.', '/'))
Now we know how to work out the URL we want, how do we make use of it?
load actionXForms provides an action handler called load that will navigate to a URL, just like <a> in HTML. load is much more powerful though, since the URL is not limited to being a string of text; it can be created from other data that is available in the XForms model. But more than that, since the navigation is tied to an action handler and not a piece of the user interface--as the anchor tag is in HTML--the features that load provides can be used in a much wider range of situations.
An example of using load with just a straightforward string literal for the URL might be:
<xf:load resource="http://prototypejs.org/api/element" />
A typical use might be to create a trigger that navigates to a page, in just the same way that <a> does; the following are in fact directly equivalent:
<xf:trigger appearance="minimal"> <xf:label>element</xf:label> <xf:load ev:event="DOMActivate" resource="http://prototypejs.org/api/element" /> </xf:trigger> <a href="http://prototypejs.org/api/element">element</>
There is no equivalent in HTML for the more advanced type of navigation, where the URL is created from data in the XForms model, although the following probably conveys the point:
<xf:trigger appearance="minimal"> <xf:label>View topic</xf:label> <xf:load ev:event="DOMActivate"> <xf:resource value="concat('http://prototypejs.org/api/', topic)" /> </xf:load> </xf:trigger> <a href="http://prototypejs.org/api/{topic}">View topic</>
DOMActivate with an inputNow that we know how to use load, we need to link it to the data entered into the input control. We could just use the trigger that we created above to illustrate the use of load, but we actually don't need to, since pressing [ENTER] in an input control will generate its own DOMActivate event. We therefore only need to add our action handler to the input control--with a minor modification to our XPath statement to take into account that topic is now our evaluation context--and we are able to perform everything we have just discussed:
<body>
<xf:input ref="topic">
<xf:label>Topic:</xf:label>
<xf:load ev:event="DOMActivate">
<xf:resource value="concat('http://prototypejs.org/api/', translate(., '.', '/'))" />
</xf:load>
</xf:input>
<body>
This is our complete form, and in just a few lines of XForms we are able to take a value from our users, and when they press [ENTER], use that value to navigate to a page within the Prototype API documentation. Now we need to turn this form into a toolbar.
As this simple form stands, if the user entered a topic to look for, and then pressed [ENTER], the form would be replaced with the correct page from the Prototype documentation. Whilst this is not ideal behaviour when the form is running in the main browser window, it's just what we want when the form is running as a soft-bar. This is because any navigation that takes place in the soft-bar--whether it's a toolbar, side-bar, footer-bar or explorer-bar--is 'bounced' through to the main window. As a result, it's very quick and easy to create toolbars such as this one, that search Google, Flickr, IMDB, Wikipedia, and so on, and show the results in the main window.
To complete turning our form into a toolbar, we need to indicate its title as it will appear in the toolbar:
<head>
<title>Prototype API Documentation Search</title>
<meta name="dc:creator" content="Mark Birbeck" />
and set the toolbar's starting, maximum and minimum dimensions:
<meta name="dc:creator" content="Mark Birbeck" />
<meta name="maxwidth" content="300" />
<meta name="maxheight" content="21" />
<meta name="minwidth" content="300" />
<meta name="minheight" content="21" />
<meta name="defwidth" content="300" />
<meta name="defheight" content="21" />
<style type="text/css">
Installation is extremely straightforward, and follows the same pattern described in HOWTO: Creating a del.icio.us side-bar and installer. If you want to install the toolbar you can do so from here. (You'll need formsPlayer, but this form will install it automatically.) Also, if you'd like to get the code and use it to create your own toolbars, it is available from here.