Building interactive tools with XForms

10 November 2010

Nearby documents


Organizational preliminaries

Schedule

What's where

A word from the wise

Inevitably, the people who get the most from the class share one characteristic: They remain focused on the topic at hand.
The first trick to maintaining focus is to get enough sleep. I suggest 10 hours of sleep each night when you are studying new ideas. Before dismissing this idea, try it. You will wake up refreshed and ready to learn. Caffeine is not a substitute for sleep.
The second trick is to [remember that s]ome things in this world are just hard.
Before going any further, assure yourself that you are not stupid and that some things are just hard.

-Aaron Hillegass

A request

This is a newly developed course. So:
* Interest and novelty are determined at the sole discretion of the instructors, whose decisions are final.

Goals of the course

When you leave, you should:
  • have an overview of XForms
  • have used XForms a bit yourself, hands-on
  • be able to fend for yourself
You will not become an expert here. (Sorry.)
A lot of very bright people have spent the better part of a decade developing the technology we are talking about here. You are not going to master that technology in a day and a half.
Also, XForms was not designed in an ivory tower; it was designed to fit into the context of the World Wide Web and web architecture. That's good news and bad news: it's good news because XForms is designed to fit in with other tools and work together with other parts of Web architecture. It's bad news because there are a lot of other parts of Web architecture that touch on XForms, and which you may have to learn at least a little bit about to use XForms well in practice.
So you really need to learn to fend for yourselves. By that I mean that when you go back home and try to do something more ambitious, you will if you're like me run into trouble. You should know in principle what's possible, but when things don't work ‘right’ (i.e. as you expect), you need to be able to discover, in practice and in detail, what's wrong.
So in some of the exercises I am going to let you flounder a bit. You need to get used to floundering; it's part of the task of learning a new language.

Outline of the course

  1. Introduction
  2. Atomic values and simple structures (1)
  3. Atomic values and simple structures (2)
  4. Multi-part user interfaces
  5. Repetitions
  6. Individual work, question/answer session, and wrap-up
Note that the final session will be devoted in large part to individual work. The idea is for you to try to develop a form from scratch to serve some purpose of your own.
If you don't have an idea of something you'd like to build with XForms, consider the list of possible follow-on projects pointed to from the list of workshop materials.

Assumptions

The slides and exercises assume some things:
  • You have a passing acquaintance with XHTML.
  • You either have a passing acquaintance with XPath or can pick up what you need quickly from a cheat sheet.
  • You either have a passing acquaintance with CSS, HTTP, XSLT, Javascript, and XSD datatypes, or else you can tolerate passing references to things you don't understand without becoming anxious.
  • You have a network connection and an XSLT- and Javascript-capable browser (e.g. Safari, Opera, Firefox, IE).
  • Either you can write to the server in some way (preferred)
    • Subversion check-out, check-in
    • remote WebDAV directory mount in your file system
    • FTP (?)
    Or you can create and work in a local directory, if you install XSLTForms locally
  • You can produce well-formed XML in an editor.
  • XML namespaces don't make you cry. (Cursing is fine.)
If any of these assumptions is false, please raise your hand now.

Rules

  • If you cannot hear what I'm saying or see what I'm showing, speak up.
  • If you hear but do not understand, ask a question. (But N.B. I don't promise to answer right away.)
  • If you have questions about side points, hold them for break.
  • If I'm going too fast (linguistically or conceptually), let me know.
  • If I'm going too slow, and boring you, feel free to signal “pick up the pace!” or “End the digression!”
  • During the exercises, feel free to experiment with variations on the exercise as shown in the slides. But if your experiments lead to complications, you're on your own.

Acknowledgements

Many people have provided help, examples, insights, and material shamelessly recycled here without attribution. Some have helped me personally, some have never heard of me but have helped me by making their knowledge and work available on the Web. Thanks to Mark Birbeck, John Boyer, Erik Bruchez, Kurt Cagle, Alain Couthures, Micah Dubinko, Ronald van Kujik, Steven Pemberton, T. V. Raman, Joern Turner, Christine Vanoirbeek (and colleagues)
Particular thanks to Syd Bauman, John Boyer, Leigh Klotz, Steven Pemberton.

Session 1: Introduction

Outline of this section

  1. Introduction
    • Preliminaries (mechanical info, ...)
    • Introductions around the table
    • Quick tour of XForms: high-level overview
    • Hello, world example
  2. Atomic values and simple structures (1)
  3. Atomic values and simple structures (2)
  4. Multi-part user interfaces
  5. Repetitions
  6. Individual work, question/answer session, and wrapup

Introductions

Why XForms? The usual answer

Why XForms? My answer

In other words, XForms is a technology for building padded-cell editors for XML: vocabulary-specific, task-specific tools.
The MVC pattern is best known from Smalltalk, where it had some specific technical properties which responded to rather specific characteristics of the host platform. XForms over XHTML works in a different host environment and does not possess all of those properties; it might be said to be in the spirit of the original model/view/controller pattern, without following the Smalltalk form of that pattern to the letter.
So: if you are an OO programmer and want to distinguish carefully between the MVC pattern, the MVP (model / view / presenter) pattern, the Java Model 2 architecture, the presentation / abstraction / control pattern and so on; if the difference between controllers and front controllers is important to your world view, then you need to know not to expect that kind of precision here. I'm trying to help the XForm author see and understand the different parts of XForms, not to define a software pattern
For discussion of MVC and XForms, see Micah Dubinko's post of 2 September 2010 (and the material he links to).

Overview of XForms

XForms uses the model / view / controller pattern.
So there are three things to learn:
  • what's the model? A set of XML documents.
  • what's the view? A host document language, plus widgets.
  • what's the controller? A set of widget / element (or widget-attribute) bindings.

Overview of XForms (2)

A second way to get an overview.
AC Alain Couthures, MXP Mozilla XForms Project, SP Steven Pemberton

Conceptual structure: MVC

To organize your knowledge of XForms, remember:
  • model (XML documents)
  • view (display in host language)
  • controller (binding view to model)
Plus, of course:
  • other stuff that doesn't fit this classification

The model: XForms elements

XForms model: a set of XML documents
  • xf:model element
  • xf:instance element
  • xs:schema element
  • xf:submission element
  • xf:bind element (what's that doing here?)
I'm not going to try to explain these now; on the contrary, for the moment all you need to know is that the xf:model element and its children exist, and that as you gain knowledge of XForms you'll need to organize part of it around them.
Here and in the following slides on the model, the view, and the controller, I'm trying to show you how things are organized, but not to provide a lot of details. We want to build up a framework on which you will later be able to hang a lot of details. But right at first, the framework will mostly be empty.

The model: some questions to ponder

  • What kinds of XML structures work best?
  • What if I don't have a schema?
  • Which schema types are supported? Which are most useful? When?
  • How does submission to server work?
  • How can submission be tweaked?
  • How can submission break your heart?

The view: XForms and its host

XForms an embedded language, not stand-alone.
What does each contribute to view?
XForms:
  • widgets
Host:
  • basic text structures
  • styling
Here, XHTML is the host, and CSS the styling mechanism.
But ... OpenOffice, for example.
Styling is not part of XForms proper. This has consequences.

Conceptual structure: View (Styling)

Styling is determined by host environment.
So: not part of XForms. Out of scope.

The view: widgets

  • string (‘text’) input
  • text area
  • select one, select many
  • etc.
Once you have the overall pattern of XForms down, it's not hard to figure out how to use a new kind of widget. So that's one place we'll be subsetting the language. There aren't that many kinds of widgets, but we won't attempt to cover them all in detail; we'll leave some widgets and many details for you to discover at your leisure.

The view: styling

For XForms in XHTML, styling is simple:* CSS.
Simple, that is, for some definition of simplicity.
In principle, it's straightforward and very powerful.
In practice, it's very powerful and not really very straightforward, because to
  • Browsers vary in their CSS support.
  • XForms implementations mangle the document structure in different ways and expose different classes.

The controller

The controller:
  • binds controls to the model
    • XPath
    • ID resolution
  • assigns properties to items in the model
  • performs calculations
  • initiates and propagates events
  • performs actions triggered by events

The controller: item properties

  • type (intrinsic or extrinsic)
  • readonly
  • required
  • relevant
  • calculate
  • constraint
  • assigns properties to items in the model

The controller: events

How is interaction modeled? By events.
  • initialization events (when things are ready)
  • interaction events (when users do things)
  • notification events (no default processing)
  • error events

The controller: actions and event handlers

How managed / tweaked? By actions and event handlers.
How easily can we monitor events?
Can we choose one or two event types to play with and explore?
Can we completely ignore events?

Prerequisite / useful knowledge

* Cheat sheets provided

Implementation landscape

For XForms hosted by XHTML:
  • native implementations (e.g. Mozilla plug-in, X-Smiles)
  • server-side implementations (servlets) (e.g. Chiba, Orbeon, betterFORM)
  • in-browser implementations (e.g. XSLTForms, Ubiquity, EMC Formula)
Other hosts:
  • Open Office
  • Lotus Forms

Some things that may bite you

Life is not all beer and skittles:
  • HTTP PUT (and security issues)
  • servlet memory usage
  • same-origin policy in browsers

Exercise 1: Hello, world!

  1. general setup
  2. model: specify instance
  3. model: specify submission
  4. view: specify widget
  5. controller: specify linkage
Some languages follow the principle of trying hard to make it possible to do something that at least seems useful, in a very short time. (“Simple things are easy and complex things are possible.”) Some languages have special cases and shortcuts to make the simplest examples really, really simple.
XForms does, too. But I'm not going to show you those.
The shortcuts in XForms mostly help make the language look less threatening to users of HTML forms who are nervous about XML and who would like XForms to be as simple (and thus as inflexible) as HTML Forms. They aren't shortcuts that are really useful to XML-oriented users. And they just complicate things. (For example: the instance isn't always needed, you can let it be constructed automatically. But then you have much less control over the shape of the XML, and poorer sanity checking in the form. Why would you ever bother to use such a shortcut?)

Hello, world! Setup

There's nothing magic about the template; it's just a complete XHTML document with the necessary namespace declarations.
Proposed setup:

Hello, world! Instance

It's conventional (not required) to put the xf:model element in the HTML head.
<head>
  <xf:model>
    <xf:instance xmlns="">
      <greetings>
        <greeting/>
      </greetings>
    </xf:instance>
  </xf:model>
</head>

Hello, world! Submission

Submission information also goes in the xf:model element.
<head>
  <xf:model>
    <xf:instance xmlns=""> ... </xf:instance>

    <xf:submission id="save"
      resource="whatever-filename-you-want.xml"
      method="put"
    />

  </xf:model>
</head>

Hello, world! The widget

Widgets to into the HTML body. Supply whatever surrounding prose you like. Mine says:
    <h1>Hello, world!</h1>
    <hr/>
    <p>
      <xf:input>
        <xf:label>Say hello, in the language 
          of your choice!</xf:label>
      </xf:input>
    </p>

Hello, world! The submit button

Label it as you wish. Mine says:
    <p>
      <xf:submit submission="save">
        <xf:label>Save ...</xf:label>
      </xf:submit>
    </p>

Hello, world! The binding

You must bind the widgets to the model.
  
    ...
    <xf:input ref="greeting">
    ...
    <xf:submit submission="save">

Go

  • Check well-formedness
  • Save as XHTML
  • (alternate: if not using direct WebDAV, copy to server)
  • Refresh in browser
  • Navigate to submitted resource

What can go wrong?

  • well-formedness
  • MIME type (application/xhtml or application/xml usually required)
  • missing namespaces
  • extraneous namespaces
  • bad XPath expressions in ref

Break

End of session.
Back in 30 minutes.

Session 2: Atomic values and simple structures (1)

  1. Introduction
  2. Atomic values and simple structures (1)
    • a simple form
    • conditional relevance
    • datatyping and validation
  3. Atomic values and simple structures (2)
  4. Multi-part user interfaces
  5. Repetitions
  6. Individual work, question/answer session, and wrapup

Review

First, a quick review of the essentials:

An example

A form for information about people.
TEI person has:
  • birth, death, floruit, event
  • affiliation, education, occupation, persName, residence, state
  • age, faith, langKnowledge, nationality, sex, socecStatus, trait
  • bibl
Let's start simpler:
  • type (historical [ancient or modern], fictional)
  • birth, death (for modern historical figures)
  • floruit (for ancient historical figures)
  • yearsOld (for fictional figures)
  • persName, sex (for all)
And let's make some simplifying assumptions.

Exercise 2, v1

Make the first version of this form:
  1. Template is person.xhtml
  2. Specify instance (xf:model/xf:instance).
  3. Specify submission info (xf:model/xf:submission).
  4. Specify widgets and binding (xf:input ref="..." and xf:label).
  5. Test.

Multiple xf:submission elements

In XForms, there can be more than one submission element.
The developers of XForms are rather proud of this, as it's a clear and obvious improvement on a flaw in HTML forms.

Exercise 2, v2

Add a second xf:submission and corresponding xf:submit element:
<xf:submission id="save"
  resource="name-of-your-choice.xml"
  method="put"
  replace="none"/>
<xf:submission id="show"
  resource="../../showinstance.sh"
  method="post"
  replace="all"/>
What is post vs. put?
What is replace about?

Closed sets

Our type information uses a closed list of values: ancient, modern, or fictional.
The select1 widget can exploit and enforce closed lists.

The select1 widget

select1 chooses exactly one value from a closed set:
<xf:select1 ref="{XPath}">
  <xf:label>...</xf:label> 
  <xf:item>
    <xf:label>...</xf:label> 
    <xf:value>...</xf:value> 
  </xf:item> 
  ...
</xf:select1>
Optional: select1/@appearance has well known values full, compact, minimal.
If XSLTForms is barfing on appearance="full", for any student, change enclosure from p to div.

Exercise 2, v3

Change the widget for type information:
<xf:select1 ref="/person/type">
  <xf:label>What kind of person?</xf:label> 
  <xf:item>
    <xf:label>Ancient historical figure</xf:label> 
    <xf:value>ancient</xf:value> 
  </xf:item> 
  <xf:item>
    <xf:label>Modern historical figure</xf:label> 
    <xf:value>modern</xf:value> 
  </xf:item> 
  <xf:item>
    <xf:label>Fictional character</xf:label> 
    <xf:value>fictional</xf:value> 
  </xf:item> 
</xf:select1>
Now test.

De-cluttering the form

Not everything is relevant all the time:
  • birth and death when person is modern
  • floruit when person is ancient
  • yearsOld when person is fictional
  • name and sex always

The relevance property

A new XForms element: xf:bind:
  • appears in xf:model
  • ascribes properties to items (elements and attributes) in the model
The relevant attribute specifies when a node is relevant to the meaning of the model (relevant = "{XPath}"). The XPath value is coerced to a Boolean: true means relevant (active), false means non-relevant (inactive).
The nodeset attribute specifies which nodes have the property. nodeset = "{XPath}".

Exercise 2, v4

Specify which children are relevant when:
  • birth and death when person is modern
  • floruit when person is ancient
  • yearsOld when person is fictional
<xf:model> ...
  <xf:bind nodeset="birth|death" 
    relevant="..."/>
  <xf:bind nodeset="floruit" 
    relevant="..."/>
  <xf:bind nodeset="yearsOld" 
    relevant="..."/>
</xf:model>
You fill in the blank: when are they relevant?
Test.
XSLTForms OK if you use absolute paths, no relative. But not doing relevance filtering on submission; why?

Model item properties

The xf:bind can indicate a number of properties of model items.
  • relevant
  • required
  • type
  • ...
Are there others? What others?
Hint: try the quick reference.

The type property

Simplifying assumptions:
  • birth, death years known
  • floruit is a relatively simple range
  • yearsOld is a number (years)

Exercise 2, v5

Specify which children have which type:
  • birth and death are years (or try date)
  • yearsOld is a non-negative integer
  • extra credit: regex for floruit?
<xf:model> ...
  <xf:bind nodeset="birth|death" 
    type="xsd:gYear"/>
  <xf:bind nodeset="yearsOld" 
    type="xsd:nonNegativeInteger"/>
</xf:model>
What's the XSD namespace?
What types do XForms processors know about?
What if birth and death are full dates?
Test.

Sayonara

End of the day.
Back tomorrow morning.

Session 3: Atomic values and simple structures (2)

  1. Introduction
  2. Atomic values and simple structures (1)
  3. Atomic values and simple structures (2)
    • error messages, help, hints
    • validation beyond datatypes
    • styling
    • alternate XML structures
  4. Multi-part user interfaces
  5. Repetitions
  6. Individual work, question/answer session, and wrapup

Customized alerts and diagnostics: xf:alert

Within a control, form authors can provide customized error messages (alerts) for bad data:
<xf:input ref="yearsOld">
  <xf:label>Years old</xf:label>
  <xf:alert>yearsOld must be a whole number greater 
    than or equal to zero.</xf:alert>
</xf:input>
Also available, in the same place: xf:hint, xf:help.
Behavior variable (implementation- and device-dependent).

Exercise 2, v6

Specify better diagnostics and hints.
<xf:input ref="..."> 
  <xf:label>...</xf:label>
  <xf:alert>...</xf:alert>
  <xf:hint>...</xf:hint>
  <xf:help>...</xf:help>
</xf:input>
Test.

A gotcha

In principle, we don't care about implementation internals.
But sometimes you have to.
In XSLTForms, controls with xf:alert children must not be placed in an XHTML p element.
Use div instead.
Practice fending for yourselves. Why is this so?

Limitations on xf:alert, etc.

Catching errors earlier

For validation as the user types, use incremental="true" on the control.
<xf:input ref="yearsOld" incremental="true">
  <xf:label>Age</xf:label>
  <xf:alert>Age must be a whole number 
    greater than or equal to zero.</xf:alert>
</xf:input>
This alerts the user at the first wrong character.
Not always desirable: consider xsd:date, xsd:dateTime, etc.
(Optional: test if we have time.)

CSS rules for XForms elements.

While developing a form, we look at it a lot. It would be nice if it were not ugly.
Like any elements, XForms elements can be styled. In CSS 1 and 2, use literal QName (with escaped colon):
xf\:label {font-weight: bold;}
CSS 3 has a namespace rule:
@namespace xf "http://www.w3.org/2002/xforms";
xf|label {font-weight: bold;}

XForms pseudo-classes and pseudo-elements

XForms defines several pseudo-classes; guess what they mean!
  • :valid
  • :invalid
  • :required
  • :optional
  • etc. (Quick quiz: where do you find a list?)
Cf. standard CSS2 :link, :visited, :hover, ...
Also some pseudo-elements:
  • ::value
  • ::choices
  • ::repeat-item
  • ::repeat-index
Cf. CSS2 :first-line, :before, :after.
CSS2 used “:” for pseudo-elements, CSS3 uses “::”.

Styling with CSS: nothing is simple

Direct CSS styling works in native implementations.
But many implementation translate XHTML + XForms to (X)HTML + (HTML) Forms. No XForms elements in their output.
Exercise 2.7a: examine the HTML output of our implementation.
Workaround: class names.
Exercise 2.7b: where are the class names written down?

Styling with CSS: the plot thickens

XSLTForms reads your CSS and translates it for you.
So: you can use namespaced CSS:
@namespace xf "http://www.w3.org/2002/xforms";
xf|label {font-weight: bold;}
But N.B. the document structure does change. CSS rules that rely on label and value being siblings won't work.

Exercise 2, v7

Add CSS rules:
  • Make all labels bold.
  • Make invalid elements have pink red background.
@namespace xf "http://www.w3.org/2002/xforms";
xf|label {font-weight: bold;}
:invalid ::value { background-color: pink;}
The pseudo-class :invalid is applied to the control; the pseudo-element ::value is a child (in XSLTForms, a descendant) of the control. So: :invalid ::value, not ::value:invalid, and .xforms-invalid .xforms-value, not .xforms-value.xforms-invalid.
Perhaps revise the CSS here by examining this CSS example on XForms wiki.

Alternative XML structures

So far so good. But who in their right mind would make type an element? Or sex?
What if I want them to be an attribute?
What if I want to wrap birth and death into a life-dates element?

Exercise 2, v8

Make type and sex into attributes:
  • Change the instance.
  • Change the XPath expressions.
  • Be careful you don't also change the name of the type attribute on xf:bind!
Test.

Another way to bind

Controls can bind with an XPath expression in @ref.
OR with an IDREF in @bind.
(This requires what further change?)

Exercise 2, v9

Replace all ref attributes with bind attributes.
<xf:bind id="{ID}"
         nodeset="..."
         relevant="..."
         />
<!-- ... -->
<xf:input bind="{IDREF}">
  <xf:label>...</xf:label>
</xf:input>
N.B. ref takes an XPath expression.
bind takes an IDREF; the XPath expression is the one on xf:bind/@nodeset.
Test.

Exercise 2, v10

Wrap part of your XML (e.g. birth and death into a container in the XML:
  • Change the instance.
  • Change the XPath expressions.
  • Be careful you don't also change the name of the type attribute on xf:bind!
Test.

The xf:group element

The xf:group element groups controls to be treated as a unit.
  • Has its own (optional) xf:label.
  • Has a ref attribute, so:
    • Binds to an item in the document.
    • Sets the default evaluation context for children.
    • Allows common XPath prefixes to be factored out.
  • Allows entire group of controls to become relevant, non-relevant, etc. as a unit.

Exercise 2, v11

Use xf:group to wrap some of your controls (e.g. birth and death):
  • Wrap the controls in xf:group.
  • Bind xf:group to the container.
  • Drop common prefixes from enclosed controls.
  • (Optional): move relevant property to container.
Test.

Review: the view

Not covered: the view

Other widgets for atomic values:
  • xf:select selects multiple items from a list
  • xf:upload prompts for a file to upload
  • xf:secret for passwords
  • xf:output to display a node's value
A useful UI property for widgets:
  • @incremental on widgets: Boolean flag: is model updated after each keystroke? or when focus shifts?

Review: the controller

Review: the model

Session 4: Multi-part user interfaces

  1. Introduction
  2. Atomic values and simple structures (1)
  3. Atomic values and simple structures (2)
  4. Multi-part user interfaces
    • the xf:switch element
    • tabs
    • wizards
    • multiple instances
    • dynamic user interfaces
  5. Repetitions
  6. Individual work, question/answer session, and wrapup

Quick review: the story so far

  • MVC pattern
  • Model = XML documents (plural)
  • View = host language + widgets
  • Widgets include xf:input, xf:select1, and others.
  • Every widget labeled.
  • Controller binds widgets to instance via @ref on widget or via @bind on widget, with xf:bind element.
  • xf:bind specifies model item properties: read-only, required, optional, type, ...

Quick review: treatment of atomic values

Treatment of atomics varies on several axes:
  • Model:
    • structure of your XML (context of the atomic value)
  • View
    • choice of control (xf:input, xf:select1, ...)
    • control's appearance attribute
    • control's incremental attribute
    • alerts, hints, help (xf:alert, xf:hint, xf:help)
    • CSS* styling (with pseudo-elements and -classes)
  • Control
    • submission options (@resource, @method)
    • model item properties
      • relevance, etc. (@relevant etc.)
      • type (@type)
      • ad-hoc constraints (@constraint)

The xf:switch element

The xf:switch element (part of the view) encloses a set of mutually exclusive cases (xf:case).
<xf:switch>
  <xf:case id="{ID}">
    ...
  </xf:case>
  <xf:case id="{ID}">
    ...
  </xf:case>
  <xf:case id="{ID}">
    ...
  </xf:case>
  ...
</xf:switch>

The xf:trigger control

The xf:trigger element denotes a user-activatable control (typically a button). It contains a label and may contain actions.
<xf:trigger>
  <xf:label>...<xf:label>
  <!--* zero or more help, hint, alert, or actions.
      * for example: *-->
  <xf:hint>Click me! Click me!!</xf:hint>
  <xf:toggle case="{IDREF}" ev:event="DOMActivate"/>
</xf:trigger>

The xf:toggle action

The xf:toggle element denotes an action, not a control widget. It toggles a switch to a given case.
<xf:toggle case="{IDREF}" 
           ev:event="DOMActivate"/>
Obvious questions, with guessable answers:
  • How does it know which switch to adjust?
  • Which case gets selected in that switch?
  • What happens?
A simple → example.

Anatomy of the example: ns and switch

First, the namespace declaration:
xmlns:ev="http://www.w3.org/2001/xml-events"
Then the switch:
<div style="margin-left: 3em;">I'm just mad about
  <xf:switch>
    <xf:case id="initial">? <br/>And ?</xf:case>
    <xf:case id="A">saffron, <br/>And saffron</xf:case>
    <xf:case id="B">markup <br/>And markup</xf:case>
    <xf:case id="C">XForms <br/>And XForms</xf:case>
  </xf:switch>
  is mad about me.
  <br/><i>[Repeat]</i>
  <br/>They call me mellow yellow!
</div>

Anatomy cont'd: the toggles

Then the toggles:
<div><i>Is the correct text 
  behind door A, door B, or door C?  
  Choose one!</i>
  <br/>
  <xf:trigger>
    <xf:label>?</xf:label>
    <xf:toggle case="initial" ev:event="DOMActivate" />
  </xf:trigger>
  <xf:trigger>
    <xf:label>A</xf:label>
    <xf:toggle case="A" ev:event="DOMActivate" />
  </xf:trigger>
  <xf:trigger>
    <xf:label>B</xf:label>
    <xf:toggle case="B" ev:event="DOMActivate" />
  </xf:trigger>
  <xf:trigger>
    <xf:label>C</xf:label>
    <xf:toggle case="C" ev:event="DOMActivate" />
  </xf:trigger>
</div>

Pattern 1 for switch: Tabs

Some widely used patterns for xf:switch. First, tabs:
  • xhtml:body
    • xf:toggle
    • xf:toggle
    • ...
    • xf:switch
      • xf:case
      • xf:case
      • ...
Display all your toggles, and then all your data. Everything* but the toggles is inside the switch.

Tabs example 1

Example from XForms wikibook.

Exercise 3, v1: Tabbed interface

Make a simple form with a tabbed interface.
For v1, keep it really simple: no instance, no widgets, just text.
Extra credit: guess where this is going.

Tabs example 2

Example from Steven Pemberton.
Astute use of background colors helps it look like tabs.

Tabs example 3

Example from Kurt Cagle.
Styling is all!
Oops. Cagle's example uses xf:repeat.
Modified example, without xf:repeat.
(See also the digression at the end of the next session.)

Exercise 3, v2 (optional)

Optionally, add style information to your tabbed interface, e.g. color, in the style of example 2, or clever CSS in the style of example 3.
(Hint: don't reinvent the wheel, borrow it!)

XForms model: events and actions

The xf:toggle element indicates an action.
It's triggered by an event.
Essentially all XForms interaction is built out of events and actions.

XForms events

XForms defines a long, long list of events.
  • initialization events
    • xforms-model-construct-done
    • xforms-ready
    • ...
  • interaction events
    • xforms-submit
    • xforms-refresh
    • xforms-recalculate
    • ...
  • notification events
    • xforms-insert
    • xforms-delete
    • xforms-valid
    • xforms-invalid
    • xforms-enabled
    • xforms-disabled
    • DOMActivate
    • DOMFocusIn
    • DOMFocusOut
    • xforms-select
    • xforms-deselect
  • error indications
    • xforms-submit-error
    • xforms-binding-exception
    • xforms-computer-exception
    • xforms-version-exception
    • ...

XForms events (Cliff Notes version)

For almost all purposes, and for a very long time, you will use a short, short list of events:
  • notification events
    • DOMActivate
Mostly, you care about exactly one: DOMActivate.

XForms actions

For common cases, XForms supports purely declarative forms: you specify a relation, and XForms makes things happen. You don't have to tell anybody to do anything.
For special needs, XForms actions allow you to listen for particular events, and specify what actions should happen when those events are caught.
Some we've seen:
  • toggle
  • send (performed by xf:submit)
  • message (used by xf:alert et al.)
Some we will see soon:
  • action
  • insert
  • delete
Some not:
  • set-value
  • setindex
  • setfocus
  • dispatch
  • rebuild
  • recalculate
  • revalidate
  • refresh
  • reset
  • load

The xf:message action

The basis for alert, help, and hinting behavior.
Can be specified by itself:
<xf:message level="modal | modeless | ephemeral">
  Important message for:  <xf:output ref="username"/>:
  You may have won a million dollars!  Call now!
  Operators are standing by!
</xf:message>
Or
<xf:message ref="{XPath}"/>
Or
<xf:message bind="{IDREF}"/>

The xf:action action

The xf:action element groups a sequence of child actions.
<xf:action ev:event="{EventName}">
  <xf:toggle .../>
  <xf:send .../><!--* submits instance *-->
</xf:action>
Obvious questions, with guessable answers:
  • What happens?
  • In what order?
A simple → example.

Anatomy of the example: switch

There are now two switches; the new one is:
<xf:switch>
  <xf:case id="r.initial">They call me ... something.</xf:case>
  <xf:case id="r.A">They call me mellow yellow!</xf:case>
  <xf:case id="r.B">They call me XMLer!</xf:case>
  <xf:case id="r.C">They call me padded-celler!</xf:case>
</xf:switch>

Anatomy, cont'd: toggles

The toggles are wrapped in xf:action elements:
<xf:trigger>
  <xf:label>?</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:toggle case="initial" />
    <xf:toggle case="r.initial" />
  </xf:action>
</xf:trigger>
<xf:trigger>
  <xf:label>A</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:toggle case="A" />
    <xf:toggle case="r.A" />
  </xf:action>
</xf:trigger>
<xf:trigger>
  <xf:label>B</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:toggle case="B" />
    <xf:toggle case="r.B" />
  </xf:action>
</xf:trigger>
<xf:trigger>
  <xf:label>C</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:toggle case="C" />
    <xf:toggle case="r.C" />
    <xf:message>Bingo!  You win the prize!</xf:message>
  </xf:action>
</xf:trigger>

The xf:instance/@src attribute

Gets the instance from elsewhere.
<xf:instance src="{xsd:anyURI}"/>

Exercise 3, v3: external instance

Change xf:instance to use @src instead of using an in-line instance.
There is an external TEI header in tei-skeleton.xml, so the source will be
<xf:instance 
  src="tei-skeleton.xml"/>

Exercise 3, v4: input controls in tabbed interface

Add xf:input controls for some TEI header elements. First, keep it simple:
  • fileDesc/titleStmt/title
  • fileDesc/publicationStmt/idno
  • fileDesc/sourceDesc/p
If there is time and you're ambitious:
  • fileDesc/publicationStmt/publisher
  • fileDesc/publicationStmt/date
  • encodingDesc/projectDesc/p
  • profileDesc/creation
  • profileDesc/langUsage/language (also its ID)
  • revisionDesc/change/date
  • revisionDesc/change/respStmt/name
  • revisionDesc/change/respStmt/resp

Pattern 2 for switch: wizards / conversational interactions

Another pattern: one step at a time!
  • xhtml:body
    • xf:switch
      • xf:case id="c1"
        • ... (stuff) ...
        • xf:toggle case="c2"
          • xf:label Next
      • xf:case id="c2"
        • ... (stuff) ...
        • xf:toggle case="c3"
          • xf:label Next

Pattern 2b for switch: back button

Easy to go back as well as forward!
  • xhtml:body
    • xf:switch
      • xf:case id="c1"
        • ... (stuff) ...
        • xf:toggle case="c2"
          • xf:label Next
      • xf:case id="c2"
        • ... (stuff) ...
        • xf:toggle case="c1"
          • xf:label Back
        • xf:toggle case="c3"
          • xf:label Next

Pattern 3 for switch: alternate views

Switch can also be used (obviously) for alternate views.
Basic / advanced (or terse / verbose, high-level / details) example from Steven Pemberton.
Display / edit example from Steven Pemberton.

Digression: the xf:output widget

Wait a moment.
How does that last example work?

Exercise 3, v5a: fending for yourself

Exercise 3, v5b: using xf:output

Auxiliary instances

A form can have one or more models.
A model can have one or more instances.
What could you do with a second instance?
  • Work on multiple documents.
  • Track non-document information you need.
  • Perform late binding on user interface elements.
Warning: if you work hard, you can reduce the form to a purely procedural object pretending to be declarative. Caveat utor!

Dynamic UI elements / i18n

The value of xf:label does not need to be static.
A simple → example.

Exercise (time permitting): multilingual person info

Can you do this for your person exercise?
Double exercise:
  • Fend for yourself: what's involved here?
  • Do it.

Review: the controller

  • xf:switch, xf:case: mutually exclusive alternatives
  • xf:toggle action
  • xf:message action
  • xf:action action
  • other actions ...
  • XForms events (DOMActivate)
  • XForms listeners (ev:event="DOMActivate")

Review: the view

  • visiblity affected by xf:switch
  • tabbed interface: toggles outside the switch
  • ‘wizard’ interface: toggles inside
  • optional-details interface: asymmetric cases (both have toggles; one also has data)

Review: the model

  • xf:instance/@src attribute, for external instances

Ciao

End of session 4.
Questions before or during lunch.

Session 5: Repetitions

  1. Introduction
  2. Atomic values and simple structures (1)
  3. Atomic values and simple structures (2)
  4. Multi-part user interfaces
  5. Repetitions
    • quick review
    • flat lists
    • one record at a time (names file editor, FileMaker)
    • special view for focus item
    • heterogeneous sequences
  6. Individual work, question/answer session, and wrapup

Quick review: the story so far

Model:
  • XML document(s)
  • xf:submission element(s)
  • model item properties (via xf:bind)
View:
  • Host language, with styling
  • CSS pseudo-classes and pseudo-elements
  • Controls, including xf:input, xf:select1, xf:submit, xf:group, xf:trigger, with
    • appearance = "{full | compact | minimal}"
    • incremental = "{xsd:boolean}"
Controller:
  • binding of widgets to items via @ref, @bind
  • assertion of model item properties via xf:bind
  • events, event listeners, notably event DOMActivate
  • actions, including xf:toggle, xf:message

The xf:repeat element

Allows for repetitions of widgets to match repetitions of nodes.
<xf:repeat bind="{IDREF}">
  ... your depiction of a single item here ...
</xf:repeat>
or
<xf:repeat nodeset="{XPath-as-nodeset}">
  ... your depiction of a single item here ...
</xf:repeat>
N.B. @nodeset, no @ref.

Exercise 4: homogeneous repetition

We'll do several things with a set of repeating elements.
  • single-item edit
  • multiple-item edit
  • paging through items one at a time
  • multiple-item read-only display
  • master/detail displays

Exercise 4: the data

<revisionDesc status="published">
  <change who="#BZ" when="2008-02-02" status="public"
    >Finished chapter 23</change>
  <change who="#BZ" when="2008-01-02" status="draft"
    >Finished chapter 2</change>
  <change n="P2.2" when="1991-12-21" who="#LDB"
    >Added examples to section 3</change>
  <change when="1991-11-11" who="#MSM"
    >Deleted chapter 10.  Good riddance!</change>
</revisionDesc>

Exercise 4, v1: single-item edit

  • Open the template repetitions.xhtml. Note external instance.
  • Note the xf:submission/@resource value.
  • In body, add widgets for
    • @who
    • @when (a date)
    • @status (enumerate: e.g. private draft, first public draft, public draft, last-call draft, candidate recommendation, proposed recommendation, recommendation)
    • text of element
    Assume that the change element is the context node.

Exercise 4, v1 (2)

  • Add an xf:bind element to the xf:model, and use @nodeset to bind it to the change elements. E.g.
    <xf:bind id="change-binding" 
      nodeset="/TEI/teiHeader/revisionDesc/change"/>
  • Wrap all the change-related widgets of the form in xf:group pointing to the xf:bind.
  • Test.

Exercise 4, v2: r/w repetition

  • Use xf:repeat to display all items, not just one.
  • Replace the xf:group around your widgets with an xf:repeat:
    <div class="change-log">
      <xf:repeat bind="change-binding">
        <div class="change-item">
         
          <!--* Your widgets here ... *-->
    
        </div>
      </xf:repeat>
    </div>
  • Test.

Exercise 4, v3: a read-only repetition

Comment out your widgets (don't delete!)
Insert xf:output elements to display the change log entries. E.g.
<xf:output ref="/TEI/teiHeader/revisionDesc/@status">
  <xf:label>Current status: </xf:label>
</xf:output>
<ul>
  <xf:repeat bind="change-binding">
    <li>
      <b><xf:output ref="@when"/></b>:
      (<xf:output ref="@status"/>)
      <xf:output ref="."/>
    </li>
  </xf:repeat>
</ul>
Test.
Hmm. How could we lose the extra parens, when there is no @status?

Exercise 4, v3b: Using xf:group

<xf:output ref="/TEI/teiHeader/revisionDesc/@status">
  <xf:label>Current status: </xf:label>
</xf:output>
<ul>
  <xf:repeat bind="change-binding">
    <li>
      <b><xf:output ref="@when"/></b>:
      <xf:group ref="@status">
        (<xf:output ref="."/>)
      </xf:group>
      <xf:output ref="."/>
    </li>
  </xf:repeat>
</ul>
Hmm. How could we avoid the implicit block styling?

What does xf:group do?

Not much.
But enough. It groups parts of the form, and sets the evaluation context for its descendants.
Like all controls, it is enabled only if bound. And bound only if there is something to bind to.

Exercise 4, v3c: Using choose()

The choose(condition,yes,no) function is an XForms extension to XPath.
<xf:repeat bind="change-binding">
  <li>
    <b><xf:output ref="@when"/></b>:

    <xf:output ref="
        choose(@status,
               concat('(',@status,') '),'') "/>
            
    <xf:output ref="self::*"/> 
  </li>
</xf:repeat>

See-many, edit-one display

I want to display the whole list in read-only form, but be able to select an item and edit it. You know enough to figure this out now.
Before we do it together, pause to think.
Quiz: how would you do it?

Exercise 4, v4: See-many, edit-one display

Save this version of the exercise as see-many-edit-one.xhtml. We'll come back to it.

Showing one record at a time

Some databases make it easy to page through records, one at a time.
Can we do that with XForms?
Quiz: how can we do this? What do we need?

Exercise 4, v5: One record at a time

  • Clone your exercise.
  • Convert the xf:repeat back to an xf:group.
  • Add a second instance with an ID of ui:
    <xf:model id="ui" xmlns="">
      <state>
        <current-position>1</current-position>
      </state>
    </xf:model>
  • Make the xf:group bind only to the current change log entry. How?
  • Make the Next and Prev buttons change the current position. How?
N.B. we have not covered all of this here. But you can figure it out.
Fend for yourselves!

Exercise 4, v5b: Don't run off the cliff

(Optional; may be omitted if we are running late.)
What happens if you click Prev on the first item?
Can we fix it? What do we need?
  • Make Next and Prev test for the cliff and refuse to go over it. How?
  • Make Next and Prev disappear on the first or last item? How?

The xf:insert element

Q. What might an element called xf:insert do?
Example:
<xf:trigger>
   <xf:label>Add</xf:label>
   <xf:insert nodeset="{XPath}" 
     position="{before|after}" 
     at="{XPath as integer}" 
     ev:event="DOMActivate"/>
</xf:trigger>
A. It clones a node.

Exercise 4, v6: Inserting new changelog entries

  • Go back to Exercise 4, v4 (see-many, edit-one).
  • To insert a new change element at the beginning of the revisionDesc:
    <xf:trigger>
       <xf:label>Add</xf:label>
       <xf:insert nodeset=".../change" 
         position="before" 
         at="1" 
         ev:event="DOMActivate"/>
    </xf:trigger>
  • Test.
Change logs are typically add-at-top. But what if we were barbarians and wanted to add at the bottom?

Exercise 4, v7: Initializing new changelog entries

(Optional, time permitting.)
Fend-for-yourself quiz:
  • Can we pre-supply today's date? How?
  • Can we make it read-only, so user cannot change it? How?
  • Can we make it read-write, so user can change it? How?

The xf:delete element

Q. What might an element called xf:delete do?
Example:
<xf:trigger>
   <xf:label>Subtract</xf:label>
   <xf:delete nodeset="{XPath}" 
     at="{XPath as integer}" 
     ev:event="DOMActivate"/>
</xf:trigger>
For @at, two easy variants:
index({ID of repeat element})
or (within the repeat, so once for each element)
nodeset="." at="1"

Relevance and existence

Making an element irrelevant is not the same as deleting it.

Heterogeneous sequences

Can you display all the children of a node? P, Q, P, LIST in that order?
Fend for yourselves!
What do you need? How can you do it?

Review: the model

What do you need to know and remember about the model?

Review: the view

What do you need to know and remember about the view?

Review: the controller

What do you need to know and remember about the controller?

Reminder: what happens next

After the break:
  • 45 minutes of solo work on project of your choice.
  • 44 minutes of question and answer (may include debugging).
  • 1 minute of wrap-up.

Session 6: Individual work, question/answer session, and wrapup

  1. Introduction
  2. Atomic values and simple structures
  3. Multi-part user interfaces
  4. Repetitions
  5. Mixed content
  6. Individual work, question/answer session, and wrapup
    • Where do you go from here?
    • Individual work
    • Questions and answers
    • Wrapup

Where do you go from here?

How do you learn more?
  • Write forms.
  • Write forms.
  • Write more forms.
  • Join the mailing list for your implementation.

Fending for yourself?

When you write your own forms, you'll get in trouble. Things won't work. I won't be there.
So:
  • Start small.
  • Build it up a bit at a time.
  • In case of need, debug by finding an example that works, and systematically turning it into your example.
  • The resources list has material worth consulting.
  • Join the mailing list for your implementation.
And: start right now, while I am still around to ask questions of.

Individual work

In the next 45 minutes, start on a project of your own. Raise your hand if you run into trouble.

Questions and Answers

What else would you like to know?

Wrap-up

Thank you!
Remember to fill out the course evaluation form at http://tei2010.blackmesatech.com/exx/xforms.eval.xhtml!

Notes for later attention

Coverage issues

Notes on topics to cover or not cover go here.

Model

  • bindings to different XML structures
  • insert element
  • delete element
  • untag element
  • rename element
  • reorder elements
  • sort
  • XForms-friendly XML vs. XForms-hostile XML?
  • mixed content
  • indirection via pointers (a problem? not a problem?)

View

  • how to style the form
  • visibility control
  • tabbed interfaces
  • conditional switch
  • N.B. we are NOT covering interface design here

Controller

  • using auxiliary documents for control, state, interface language
  • repeat (etc.)
  • relevance
  • validation via XSD
  • ad hoc validation (how? via calc? other?)

Context

  • making PUT work
  • mailto:
  • WebDAV
  • LDAP
  • Kerberos
  • interactions with file system
  • protection against disaster? Autoversioning in Subversion
  • installation issues
  • interaction with other Javascript? XSLT?
  • security issues (N.B. we are NOT covering them)
  • XML vocabulary design NOT covered

Unplaced material to place or kill

Practical information

  • error messages
  • multiple implementations
  • reference sources
  • the spec
  • examples
  • other resources

The XForms model: typed XML

...
<head>Implicit instance</head>
If there's no instance element, what happens?
<head>Internal instance</head>
...
<head>External instance</head>
...
<head>Submission of the form ... instance</head>
...
<head>Multiple models, multiple instances</head>
...

The XForms view: widgets

...
<head>Widgets</head>
  • text input
  • output widget
  • (multiline) text area
  • single-selects (radio buttons, select area, dropdown)
  • multi-select (checkboxes, dropdowns)
  • file select
  • triggers (reset, submit, ...)
  • option groups
  • range controls
<head>No hidden widgets?</head>
No.
Why not?

The XForms view: other aspects of the user interface

...
  • events and the ev namespace
  • message
  • setvalue
  • action (for grouping)
  • switch

The XForms controller: binding

...
  • direct binding using ref
  • indirect binding using bind
  • conditional visisiblity: relevance conditions
  • conditional read-only controls
  • required controls
  • constraints on values
  • calculated values
  • datatypes vis binding

Session 5: Mixed content

  1. Introduction
  2. Atomic values and simple structures
  3. Multi-part user interfaces
  4. Repetitions
  5. Mixed content
    • widgets in mixed content
    • editing mixed content: the spec
    • editing mixed content: the implementations
  6. Individual work, question/answer session, and wrapup
<head>Quick review: the story so far</head>
...
<head>Atomizing mixed content</head>
is this possible?
<head>Widgets for mixed content</head>
Not standardized, but sometimes provided.
  • betterForm textarea with mediatype text/html:
    <xf:textarea 
      id="control2" 
      ref="item" 
      mediatype="text/html">
        <xf:label>simple textarea</xf:label>
    </xf:textarea>
  • Orbeon uses the Rich Text Editor from YUI control.
See
<head>Form generation</head>
named entity proofreading
<head>Review: the model</head>
<head>Review: the view</head>
<head>Review: the controller</head>