RSS and Atom feed icon News feeds

Building Rich, Encapsulated Widgets Using XBL, XForms and SVG

Introduction

Web 2.0 is pushing the boundaries of the user interface (UI), but at the same time users are expecting more. This means that web applications that people interact with must strive to represent data in as imaginative and intuitive way as possible. This can both reduce the amount of time spent on tasks, as well as reduce input errors.

Traditional browser technologies have generally only provided scripting as a means to produce such UIs, and there has rarely been a way to encapsulate these interfaces for re-use. However, using XBL as the binding language and XForms and SVG for the functionality, it is now possible to build rich widgets that are completely encapsulated, and so reusable.

In addition, by building the widgets using XForms to provide the functionality, we get two major benefits: first, since XForms is accessible, the resulting widget combinations are also accessible; and second, XForms' ability to easily manage web services means that widgets can communicate for data themselves, making it easy to produce 'smart' widgets.

Aim

The aim of this session is to explain both the use of rich widgets, and how to build them. It will focus on standard user interface languages such as XForms and SVG, and show how XBL can be used to control them.

Use Case: The Metabar

To illustrate the need for ‘smart’ widgets we’ll create a Metabar. This is a sidebar that sits in the browser and displays metadata relating to the page currently being viewed in the main browser window. Although it would be straightforward to simply display the textual value of the metadata in the panel, we can make the user experience far richer by using widgets that are geared towards the type of data being displayed. For example, if the site being viewed has geographical location data, the sidebar could render this as a map with a red cross giving the longitude and latitude of the location.

The ‘smart’ widget that we’ll discuss shows images from Flickr—the public photo archive—that have been tagged with some specified keyword. The widget itself manages the whole process of querying Flickr for a list of images, and then rendering them, which obviously means that some other photo service could easily be substituted. (We’ll call this widget the Flickr-strip.)

The display of an image is actually managed by a further widget, which takes as its input the image to be shown and the time that the photo was taken—and then displays both. The time that the photo was taken is displayed using yet a further widget.

This whole recursive process is illustrated here, showing the Metabar making use of the Flickr-strip:

Figure 1. The Metabar showing images relating to Chelsea football club. The images were chosen automatically based on the subject matter of the article being read.

The simplest form of the Flickr-strip is simply to take some input from a user, and use it to retrieve images:

Figure 2. The Flickr-strip bound to a simple input control.

Let’s look at how the Flickr-strip is created.

The Flickr-strip

The first piece of mark-up looks extremely simple—we just need XForms input and output controls:

<html>
  <head>...</head>
  <body>
    <xf:input ref="search">
      <xf:label style="display: none;">Search:</xf:label>
    </xf:input>

    <xf:output ref="search" appearance="flickr:strip">
      <xf:label style="display: none;">Search:</xf:label>
    </xf:output>
  </body>
</html>

(The display: none; on the labels is because we don’t want the text rendered in a visual display, but we don’t want to remove it altogether since then it won’t be available to assistive technologies.)

At first sight it appears that this combination of controls doesn't do anything, but the set-up actually does an enormous amount. The first aspect is that whatever the user enters into the input control will also be present in the output control, because they both refer to the same node in the instance data:

<xf:input ref="search">
  <xf:label style="display: none;">Search:</xf:label>
</xf:input>
<xf:output ref="search" appearance="flickr:strip">
  <xf:label style="display: none;">Search:</xf:label>
</xf:output>

The effect of this simple coupling is that the output control will receive notification every time the value in the node search changes. Since our framework will manage all of this for us via event notifications, we have created a very simple pipeline between our user's input, and what will ultimately be the Flickr servers.

The second thing of interest is that the output will render the list of images obtained from Flickr. Of course in ordinary XForms an output will simply render the value of the node that it is bound to, but in our Flickr-strip we're going to skin this control so that it renders a list of thumbnail images from Flickr that have been tagged with the word that the output 'contains'. (In other words, we’re not going to change the relationship between this input and output, we're simply going to change how the output is rendered.)

We can re-skin a control using many different mechanisms. So we might re-skin all triggers to be aqua buttons, or we might re-skin all modal messages to use a loud male voice. But in this example we are going to add something directly to the form mark-up, and use the appearance attribute as our skinning 'hook' (in other words, we’re going to re-skin any control that has appearance set to flickr:strip):

<xf:output ref="search" appearance="flickr:strip">
  <xf:label style="display: none;">Search:</xf:label>
</xf:output>

From an XForms point of view this is fine. If an XForms processor does not support this particular value of appearance then it can ignore it and just render the underlying data as best it can. That may not be a lot of use here, but it shows that XForms has built-in fallback features, which in turn are possible because appearance is only intended as a 'hint' to the processor, rather than a mandated operation.

And since the value of appearance is a hint, then other processors can act in a different way—and if you don't like my Flickr-strip you can do your own! (In fact you can replace my objects at any level down, including just replacing the clock and leaving everything else intact.)

Although we haven’t yet shown how we’re going to wire up this Flickr-strip to this output, let’s for a moment pretend that we have, so that we can establish just how powerful this technique is. With a Flickr-strip completely encapsulated in a simple piece of declarative mark-up, we can re-use it wherever we like. For example, to show a set of images tagged with ‘flower’, we need only do this:

<xf:output value="'flower'" appearance="flickr:strip">
  <xf:label style="display: none;">Flowers:</xf:label>
</xf:output>

And we can show multiple Flickr-strips by doing no more than this:

<xf:output value="'rose'" appearance="flickr:strip" />
<xf:output value="'tulip'" appearance="flickr:strip" />
<xf:output value="'daisy'" appearance="flickr:strip" />

And of course, since this is still XForms, we can also use other controls like repeat, to get a whole bunch of Flickr-strips based on a dynamically changing list of tag values:

<xf:repeat nodeset="strips/strip">
  <xf:output ref="." appearance="flickr:strip">
    <xf:label ref="." />
  </xf:output>
</xf:repeat>

This is exactly the technique used in the Metabar shown earlier—metadata about the page being viewed in the main browser window is retrieved and then used to obtain a set of images from Flickr. We can create as many Flickr-strips as we like, and they can relate to whatever terms we like. Now we're ready to look at how it's done.

Control Binding

The technique we use for implementing the Flickr-strip is to augment or decorate the output control with methods, properties, objects and event handlers. These are defined with the XML Binding Language (XBL), which is a language that was originally devised by the Mozilla Foundation for specifying this kind of functionality in relation to one or more document nodes.

The technique we’re using is a sort of cross between object inheritance and aspects.

Inheritance

What we’re doing is a bit like inheritance because the output control plays a role similar to a base class, onto which other classes are being layered. But it's more powerful than the inheritance you might be used to in Java and C++, since with those languages it's very difficult to add new classes at different points in the hierarchy. And it's certainly difficult to add new classes at run-time.

Aspects

Aspect programming gets round the problems that come with the inheritance model by allowing key points of an object to be supplemented with additional code. For example, you might add some functionality that you want to be run at the beginning of a function before its normal execution takes place, and some more functionality at the end, to occur after the normal execution has been performed.

But the main problem with aspect programming is that the additional code is generally added at compile at time, and the extension points have to be quite clearly defined.

Object Binding

The model we're using here is different to both of these. Instead we’re using some run-time condition (in this case, the presence of an appearance attribute with a value of “flickr:strip”) as our indicator that some methods, properties, event handlers and even other objects need to be added to the selected object. More than one set of these bindings can be added at a time, and importantly, the process is recursive—each of the objects added by the binding can itself have bindings.

The Source

Let's now walk through the source for the Flickr-strip bound object. The first part of the binding specifies further objects that will be added, indicated by the XBL content element:

<xbl:binding id="strip">
  <xbl:content>

The first thing we need to add to this object is an XForms submission that asks Flickr for a list of images that match a certain tag. This is easily done, as follows. First set up the URL and the method that will be used to retrieve the data, and indicate where the returned data should go (the instance called i-rs):

    <xf:model id="m">
      <xf:submission
       id="sub"
       action="http://www.fli[..snip..]/photos_public.gne"
       method="get"
       ref="instance('i-rq')"
       replace="instance" instance="i-rs"
       separator="&"
      />
      <xf:instance id="i-rs">
        <dummy xmlns="" />
      </xf:instance>

The actual data to be sent to Flickr is defined here, although the tags value will be replaced with the actual keywords we’re looking for:

      <xf:instance id="i-rq">
        <instanceData xmlns="">
          <tags>*</tags>
          <format>rss_200_enc</format>
        </instanceData>
      </xf:instance>

The submission can be kicked of by invoking the event ev-find-images:

      <xf:action ev:event="ev-find-images">
        <xf:send submission="sub" />
      </xf:action>
    </xf:model>

In this structure, when the submission is invoked it will take the URL in action and combine it with the data referred to by ref, in this case the instance i-rq. The parameters to Flickr (in i-rq) are the tag you are looking for, and the format of the result set—in this case RSS 2.0—these results being placed in the instance i-rs.

Once we have the results, they need to be rendered, and we do that with a simple XForms repeat:

    <xf:repeat
     model="m"
     nodeset="instance('i-rs')/channel/item"
    >
      <xf:output ref="." appearance="flickr:thumbnail" />
    </xf:repeat>
  </xbl:content>

The results of the request to Flickr are actually a set of RSS items, so this repeat simply iterates each RSS item, and then renders it by using an output. As before, the output is bound to some other object, in this case a flickr:thumbnail object.

We’ve now created an encapsulated object that does the following:

  • when it receives the event ev-find-images it will kick off a submission to Flickr to find images that are tagged with the value in tags;

  • when the results come back from Flickr the object renders them with a simple repeat;

  • each item in the repeat—i.e., each item returned by Flickr—is then rendered using another widget that displays Flickr thumbnail images.

However, there are still two things missing here; we haven’t said how to indicate what tags to search for, and we haven’t said how the whole process is kick-started.

Recall that everything we have just defined—the whole XBL component—is sitting inside an output that has been wired up to the search node in the instance data:

<xf:input ref="search">
  <xf:label style="display: none;">Search:</xf:label>
</xf:input>

<xf:output ref="search" appearance="flickr:strip">
  <xf:label style="display: none;">Search:</xf:label>
</xf:output>

Whenever the value of the search data node changes, the XForms framework will automatically notify any control that is bound to it. In fact, it does more than that, telling the control the status of the data—whether it is valid or invalid, required or optional, read-only or editable, and so on.

The XForms processor will signify to our control that the data has changed using the xforms-value-changed event, but we don’t need to implement a handler for this. Instead our framework will catch that event and invoke our object’s setValue method. This method receives one parameter which is the new value of the data, and we implement this in our component inside the XBL implementation section:

  <xbl:implementation>
    <xbl:method name="setValue">
      <xbl:parameter name="newVal" />

The actual function itself is written in script, and the first thing our function will do is check to see that the value has indeed changed:

      <xbl:body>
        // <![CDATA[
          if (newVal && newVal != '')
          {

Next we need to find the object that we created earlier so that we can set the tags element to the value that the XForms processor has just given us:

            var m = this.all.tags("model")[0];
            var i = m.all.tags("instance")[0];
            var pDOM = m.getInstanceDocument(i.id);
            var oTags = pDOM.selectSingleNode("//tags");

            oTags.firstChild.nodeValue = newVal;

Finally we tell our local, nested model to run the submission, which we do by dispatching the event ev-find-images:

            var oEvent =
              this.ownerDocument.createEvent("Event");

            oEvent.initEvent(
              "ev-find-images", false, false
            );
            m.dispatchEvent(oEvent);
          }
        // ]]>
      </xbl:body>
    </xbl:method>
  </xbl:implementation>
</xbl:binding>

Now, whenever any part of the form changes the search value—whether by using the XForms setvalue feature, or via an input control as in our example—our component will know about it. It will then set the value of tags to the same value before kicking off a submission to Flickr to get a list of images that use that tag.

There are three key parts of what we have just done:

First, we've used the ordinary notifications that the XForms processor gives us when data is updated, as our prompt to go get some data from Flickr. This is a powerful technique, because not only did we not have to write any code to monitor the user typing into the input control, but we didn’t even have to monitor the search node in the data. The framework provided all the bindings necessary to wire up our component to the underlying data, and provided us with a standard interface between them.

The second thing we did that is significant is that we encoded the request to Flickr inside the component using an XForms submission. This keeps it nicely encapsulated so that any form using the widget need not know anything about how the process is actually implemented, and further, if we wanted to change the service used it would be easy to do. These two things together effectively define the interface between our object and the outside world—on one side from the data part of the host XForm, and on the other side the interaction with Flickr—but in a way that is repeatedly ‘decoupled’.

The remaining part is that the results of the search are rendered using very simple outputs, but with an indication that we want each item rendered as a thumbnail:

    <xf:repeat
     model="m"
     nodeset="instance('i-rs')/channel/item"
    >
      <xf:output ref="." appearance="flickr:thumbnail" />
    </xf:repeat>
  </xbl:content>

The fact that the Flickr-strip is an object that is in turn made up a set of thumbnails gives our model incredible flexibility. The next step is to look at how a thumbnail is defined.

The Flickr Thumbnail

The thumbnail is very easy to create, and is simpler than the Flickr-strip since it doesn't need to do any submitting of data. Also, since it merely maps to a couple of further controls, it doesn't need to respond directly to any events.

The first thing we do is create a span of a fixed size, so that we can ensure a neat layout:

<xbl:binding id="thumbnail">
  <xbl:content>
    <span style="
       width: 83px;
       height: 95px;
       padding-right: 5px;
     "
    >

Within this span we are going to create a sort of 'canvas' onto which to render first the Flickr thumbnail image, and then the time that the photo was taken. We'll use ordinary CSS positioning to place the time on top of the image.

First the canvas:

      <div style="
         position: relative;
         top: 0;
         left: 0;
         height: 78px;
       "
      >

Next we create the actual Flickr thumbnail, and note three things:

  • first, that we are using the XForms mediatype feature to render the image from the URL provided by Flickr;

  • second, that since the image is still a plain ordinary XForms output there is nothing to stop us from using hint to show the description of the image, which is stored in Flickr;

  • and finally, we position the image on our ‘canvas’.

The mark-up is as follows:

        <span style="
            position: absolute;
            top: 0;
            left: 0;
         "
        >
          <xf:output
           ref="media:thumbnail/@url"
           mediatype="image/*"
           style="
             border: 1px solid black;
             padding: 0;
             margin: 0;
           "
          >
            <xf:hint>
              <xf:output ref="../../media:text" />
            </xf:hint>
          </xf:output>
        </span>

Having rendered the image (complete with tooltip), we now position in the top right-hand corner of the thumbnail the time that the photo was taken:

        <span style="
           position: absolute;
           top: -10px;
           right: -10px;
         "
        >
          <xf:output
           value="inline:gettime(string(pubDate))"
           appearance="fp:analogue-clock"
           class="flickr-clock"
          />
        </span>
      </div>

You'll have noticed that this is also 'skinned', this time with a binding that implements an analogue-clock. In much the same way as with the Flickr-strip, whose input was a simple string for a metadata 'tag', here the 'input' to our clock component is again a simple string, but this time a value indicated using the 24-hour clock. (And as before, since appearance is a hint, if a processor doesn't support analogue clocks, or is a speech-based system, then the time will still be rendered as text.)

The final part of our Flickr thumbnail is the actual title of the image. We use the CSS overflow property to ensure that the text of the title doesn't make our thumbnail too wide:

      <xf:output
       ref="title"
       style="
         width: 100%;
         overflow: hidden;
         white-space: nowrap;
         text-overflow: ellipsis;
       "
      />
    </xbl:span>
  </xbl:content>
</xbl:binding>

The Analogue Clock

The analogue clock is our final component and although it uses the same techniques that we have been examining, it makes use of SVG rather than plain XHTML.

We won’t show all of the SVG for the clock since it is quite long, but to illustrate our points we’ll deal with the hour hand; here is the definition:

<svg:rect
 id="hourHand"
 x="48" y="28"
 height="30" width="3.5"
 fill="rgb(200,0,0)"
/>

This defines a red rectangle of 30x3.5 that will represent the hour hand, and there is another rectangle for the minute hand, with a narrow triangle used for the second hand.

Now that we have the hand we just need to rotate it based on the value passed in. SVG supports an attribute called transform on most elements which allows us to do just this; a value of “rotate(300, 50, 50)” for example, would position the hand at (50, 50) and rotate it 300 degrees—which would give us 10 o’clock.

Although we could manipulate the SVG element hourHand directly, we’re able to hide the implementation by using an XBL feature that ‘wires’ properties of our component into some point in the underlying mark-up. This allows us, for example, to create a property called hourOrientation which when updated will actually update the transform property of hourHand. These ‘mapped’ properties are defined by referring to the element that contains the property to connect to, and the name of the property itself:

<xbl:property
 name="hourOrientation"
 element="hourHand"
 attribute="transform"
/>

With this definition in place, setting the hourOrientation property of the widget—whether from code that is within the component or externally—will result in the transform attribute in the underlying SVG being set. So how can we make use of this?

As with our other components we are notified when the underlying data value changes. By now though, we are far away from the original search node, and the clock widgets (one for each thumbnail) will be notified of changes whenever the results have been returned from Flickr, not when the user types a new search term.

We therefore need to implement a setValue method, whose first job will be to crack open the time value passed in:

<xbl:method name="setValue">
  <xbl:parameter name="newVal"/>
  <xbl:body>
    var arr = String(newVal).split(/[:\s]/);
    var h = parseInt(arr[0], 10);
    var m = parseInt(arr[1], 10);
    var s = parseInt(arr[2], 10);

Once we have the hours, minutes and seconds that make up the time we can work out where to position the hands of the clock:

    this.hourOrientation =
      "rotate(" + (h + (m / 60)) * 30 + ", 50, 50)";
    this.minOrientation =
      "rotate(" + m * 6 + ", 50, 50)";
    this.secOrientation =
      "rotate(" + s * 6  + ", 50, 50)";
  </xbl:body>
</xbl:method>

Our script is setting the values of this.hourOrientation, etc., without having to worry what exactly they mean, or where in the underlying SVG structure they actually are. And now, as with our other components, simply providing a new data value will automatically result in the clock display changing to reflect the new time.

With a component that only needs a string for input and then automatically updates its display, we can not only show static time values, such as what time a photo was taken or when your flight arrives, but by updating the value every second we can also use this as a real clock.

CSS

This approach of hiding the underlying implementation with XBL properties is yet another powerful technique to add to our toolkit, and we’ll finish with a final illustration of its strength, using CSS to control aspects of the rendering.

First we’ll add a couple more properties for the width and the height of the clock:

<xbl:property name="width" element="clock"
  attribute="width" />
<xbl:property name="height" element="clock"
  attribute="height" />

As you can see, the element these properties are wired into is clock, which is the top-level element of the SVG mark-up:

<svg:svg
 id="clock"
 viewBox="0 0 100 100"
 width="100px" height="100px"
>
  ...
</svg:svg>

The attributes on clock that these properties are connected to are the SVG width and height properties, and in SVG, if they are changed the item they are on will automatically resize. Now all some code has to do to change the size of the clock is set this.width and this.height and the clock will resize correctly.

But we can go further and connect these properties to CSS so that the size of the clock is determined by stylesheet rules. This would not only mean that the clock takes up the same amount of space, regardless of how it is rendered (which is important given that the clock could ‘fall back’ to being rendered as ordinary text), but CSS could also be used to provide effects such as changing the size of an item on ‘hover’:

Figure 3. Moving the mouse over the clock increases its size.

Here we’ve doubled the size of the clock whenever the user moves their mouse over it (and changed its position slightly so that it remains centred):

xf|output.flickr-clock
{
  width    : 30px;
  height   : 30px;
}
xf|output.flickr-clock:hover
{
  width    : 60px;
  height   : 60px;
  position : relative;
  right    : -15px;
  top      : -15px;
}

By connecting parts of the component to CSS rules in this way, we continuously abstract away features, and make them available without programming. One final illustration is to make use of the foreground colour provided by CSS rules, as the colour of the clock hands:

<xbl:property
 name="hourFill"
 element="hourHand"
 attribute="fill"
/>

(Recall that the fill attribute on the hourHand element set the rectangle’s colour.)

Conclusion

The use of declarative mark-up languages such as XForms is becoming established as a powerful way to build sturdy, testable and accessible programs. However, when coupled with XBL, both object management and reuse become even more efficient and powerful. When objects created through this mechanism are given the power to communicate with external data sources, as we saw here with the Flickr-strip, then a technology becomes available to us that can leverage the power of today’s decentralised web, but in a way that does not require enormous skills and resources.

Unlike the 'mash-up' approach where servers are used to combine different data sources together in interesting ways, the approach described here puts client software in control (or to be more precise, the user at the centre of the web), and crucially, defines clear and simple interfaces between one set of data and the next.

A new generation of web applications is made possible by this combination of technologies.