The XForms Flickrbar and Flickr-strips

The first piece of mark-up is the main form. There's nothing to it--we just need XForms
input
and output
controls:(The
<html>
<head>...</head>
<body>
<xf:input ref="search">
<xf:label style="display: none;">Search:</xf:label>
</xf:input>
<xf:output ref="search" appearance="horzthumbnaillist">
<xf:label style="display: none;">Search:</xf:label>
</xf:output>
</body>
</html>
display: none;
on the labels is simply so that assistive technologies can still make use of the text of the labels, but we actually don't want it rendered.)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:The effect of this simple coupling is that the
<xf:input ref="search">
<xf:label style="display: none;">Search:</xf:label>
</xf:input>
<xf:output ref="search" appearance="flickr:horzthumbnaillist">
<xf:label style="display: none;">Search:</xf:label>
</xf:output>
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 xf:output
will simply render the value of the node that it is bound to, but in our Flickr Topbar 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 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
trigger
s 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 direclty to the form mark-up, and use the appearance
attribute as our skinning 'hook':From an XForms point of view this is fine. First, if an XForms processor does not support this particular value of
<xf:output ref="search" appearance="flickr:horzthumbnaillist">
<xf:label style="display: none;">Search:</xf:label>
</xf:output>
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.The second reason this is OK from an XForms point of view, is that since the value of
appearance
is a hint, then other processors could act in a different way. If you don't like my thumbnails strip, go do your own! (In fact you can replace my objects at any level down, including just the clock.)We'll come to how the thumbnail stip iself is implemented in a moment, but before we do let's establish just how powerful this technique is. Now that we have a Flickr thumbnail strip completely encapsulated in a simple piece of declarative mark-up, we can re-use all over the place! For example, to show a set of images of hurricanes, we do this:
To show multiple Flickr-strips we need only do this:
<xf:output value="'hurricane'" appearance="flickr:horzthumbnaillist">
<xf:label style="display: none;">Search:</xf:label>
</xf:output>
And of course, since this is still XForms, we can also use other controls like
<xf:output value="'hurricane'" appearance="flickr:horzthumbnaillist" />
<xf:output value="'tornado'" appearance="flickr:horzthumbnaillist" />
<xf:output value="'typhoon'" appearance="flickr:horzthumbnaillist" />
repeat
, to get a whole bunch of Flickr-strips based on a dynamically changing list of tag values:In this screenshot we have a Flickr-strip bound to some tags that have been retrieved from another web service:
<xf:repeat nodeset="strips/strip">
<xf:output ref="." appearance="flickr:horzthumbnaillist">
<xf:label ref="." />
</xf:output>
</xf:repeat>

With this we have the power to creat 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.
XBL
The technique we use for implementing a Flickr-strip is to augment or decorate theoutput
control with methods, properties, objects and event handlers, defined with XBL. The technique is a sort of cross between object inheritance and aspects.Inheritance
It's a bit like inheritance because theoutput
control functions like a base class, onto which other classes are layered. But it's more poweful 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 (although the decorator pattern goes some ways towards that).Aspects
Aspect programming gets round this problem with inheritance by allowing particular key points of an application 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 it's 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 are usually pretty fixed.Object Binding
The model we're using here is different to both of these; using some condition (in this case, the presence of anappearance
attribute set to flickr:horzthumbnaillist
) we add methods, properties, event handlers and other objects to the object in question. More than one set of these bindings can be added at a time, but quite 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 XBLcontent
element:The first thing we need to add to this object is an XForms
<xbl:binding id="horzthumbnaillist">
<xbl:content>
submission
that goes to Flickr and asks for a list of images that match a certain tag. This is easily done, as follows:In this structure, when the submission is invoked it will take the URL in
<xf:model id="m">
<xf:submission id="sub"
action="http://www.flickr.com/services/feeds/photos_public.gne"
method="get"
ref="instance('i-rq')"
replace="instance" instance="i-rs"
separator="&"
/>
<xf:instance id="i-rq">
<instanceData xmlns="">
<tags>*</tags>
<format>rss_200_enc</format>
</instanceData>
</xf:instance>
<xf:instance id="i-rs">
<dummy xmlns="" />
</xf:instance>
<xf:action ev:event="ev-find-images">
<xf:send submission="sub" />
</xf:action>
</xf:model>
action
and combine it with the data referred to by ref
, in this case the instance i-rq
. The parameters to Flickr (in the 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
:This simply iterates each RSS
<xf:repeat model="m" nodeset="instance('i-rs')/channel/item">
<xf:output ref="." appearance="flickr:thumbnail" />
</xf:repeat>
</content>
item
, and then renders it with an output
, and as before, the output
is bound to some other object, in this case a flickr:thumbnail
object.All that remains is to fire this request to Flickr, which we do when the XForms model notifies us that the data has changed. (Recall that all of this is sitting inside an
output
wired up to the search
node in the instance data.) The first point is that each control must support a method called setValue
, which is called inside an event handler, and this method will receive one parameter which is the new value of the data:The actual function itself is written in script inside an XBL
<xbl:implementation>
<xbl:method name="setValue">
<xbl:parameter name="newVal" />
body
element, and the first thing we do is check for a change in the value:Next we go and find the XForms model and the instance that contains the search criteria, and set the
<xbl:body>
// <![CDATA[
if (newVal && newVal != '')
{
tags
element to the current value of the output
that contains us:Finally we tell our local, nested model to run the submission:
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;
To summarise, there are three key parts to what we have just done. The first is that 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 we're not having to do any monitoring of particular data, and the interface between the event and the source data is standardised.
var oEvent = this.ownerDocument.createEvent("Event");
oEvent.initEvent("ev-find-images", false, false);
m.dispatchEvent(oEvent);
}
// ]]>
</xbl:body>
</xbl:method>
</xbl:implementation>
</xbl:binding>
The second thing we do is to encode the request to Fickr in an XForms
submission
, which keeps it nicely encapsulated; if we want to change the service we are referring to it's easily done.These two things 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. The remaining part is that the results are rendered with very simple
output
s, 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>
</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 the thumbnail is defined.
A 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:Within this
<xbl:binding id="thumbnail">
<xbl:content>
<span style="width: 83px; height: 95px; padding-right: 5px;">
span
we going to create a sort of 'canvas' onto which to render first the Flickr thumbnail, and then the time that the photo was taken, and we'll use ordinary CSS positioning to place this on top of the image. First the canvas:Now the Flickr thumnail--and note two things; first, that we are using the XForms
<div style="position: relative; top: 0; left: 0; height: 78px;">
mediatype
feature to render the image from the URL. And 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, stored in Flickr:Having rendered the image, we now position in the top right-hand corner of the thumbnail the time that the photo was taken:
<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>
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' is again a simple string, but this time a value indicated using the 24-hour clock. (And as before, since
<span style="position: absolute; top: -10px; right: -10px;">
<xf:output
value="inline:gettime(string(pubDate))"
appearance="fp:analogue-clock"
class="flickr-clock"
/>
</span>
</div>
appearance
is a hint, if a processor doesn't support analogue clocks, then this will just render as text.)The final bit of our thumbnail is the actual title of the image. We use CSS 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 Clock
We won't recurse down to the next level, which is the analogue clock, but it's worth pointing out that the clock is implemented in SVG, and is the same clock that is used in other examples distributed with Sidewinder from the formsPlayer site. One thing worth drawing attention to though, is that the size of the clock is set using CSS in the main form:The use of CSS to specify the behaviour of dynamic widgets is incredibly powerful. Although the embedded widget was implemented with SVG, it was created so that it would use the CSS form its containing object, so all an author has to do to control the size of the clock is set the size of the element that the clock is bound to. So to increase the size of the clock when the user moves their mouse it, all we need to do is the following:
xf|output.flickr-clock
{
width : 30px;
height : 30px;
}
Here we simply double the size of the clock, and change its position slightly so that it remains centred:
xf|output.flickr-clock:hover
{
width : 60px;
height : 60px;
position : relative;
right : -15px;
top : -15px;
}

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 todays 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.
Tags: Platform 2.0 | Computers and Internet | Metadata | programming | RDF | RDF/A | Semantic Web | Web 2.0 | XHTML | XHTML 2.0 | XForms