Editable Floating Fields

Floating fields have always been a bit tantalizing because while they provide you with the output you want, many users want to be able to edit directly in the floating fields.  They want the field values nested inside the static text to be actual widgets.  Unfortunately, this is one of those enhancements that never seems to percolate to the top of the priority list (but don’t let that stop you from requesting this feature!).

In the mean time, I’ve worked up a sample that simulates the interactive behaviour.  Have a look here.  The way the sample works, it that it has two objects: the text object with the embedded fields and an interactive field that’s the same size, placed over top of the text object.  When the form initializes, it populates the interactive field with the content of the text element.  Then using the change event, it prevents the user from typing into the ‘boilerplate’ parts of the text but allows them to type into the field portions.

But before talking too much about the mechanics, I’ll describe how to re-use this code in your own form:

How to add the floating field editor to a form

1. Add the scEditFF and scXML fragments to your form.  These script objects hold all the logic needed to make the sample work. 

2. Add your draw element with floating fields as you normally would. 

3. Add a text field that allows multiple lines and also enables rich text.

4. Add initialize, change and exit events to your field:

form1.#subform[0].LetterEdit::initialize – (JavaScript, client)
scEditFF.initialize(this, Letter, "#c0c0c0", 10);

form1.#subform[0].LetterEdit::change – (JavaScript, client)
scEditFF.handleChangeEvent();

form1.#subform[0].LetterEdit::exit – (JavaScript, client)
scEditFF.handleExit();

The parameters to initialize are:

/**
* initialize a field to be a floating field editor for a given
* text object
* @param vField – the field that is displaying/editing the floating
* field content
* @param vText – the text object holding the floating fields.
* @param sBGColor – the color to shade the field areas.
* Specify as a CSS color value. e.g. #101010
* @param nEmptySpace – the number of spaces to use to
* render an empty field
*/

Behaviours

Some things you will notice when using this sample:

  • When the floating field editor initializes, it makes itself visible and hides the text object
  • You can’t tab between the floating fields.  Since all the fields are housed in the same widget, it means you tab in and out of the entire group.
  • Reserve space.  Notice when a field is empty and you type in, the space collapses to the character(s) you’ve typed.  Similarly, once you empty the field, it expands back to the reserved size.  Notice also that you cannot delete the reserved spaces.
  • Extra leading space.  There’s a (non-breaking) space at the beginning of each floating field.  This is needed to ensure that the user input is always rendered with the shaded field background.  When you type into rich text, the typed text always inherits the format of the character preceding the caret.  In order to make sure that content inserted at the beginning of a floating field gets shaded, I needed to add an extra (un-editable) space character.  I initially tried using an invisible character such as a zero width space, but found that in Acrobat 9 these special Unicode spaces are made visible when they’re part of field content.  I suspect that was done for security reasons.
  • Field Updates.  When you exit the widget holding all the floating fields, the exit event fires and will update all the fields that correspond to the editable areas.
  • The script turns off Acrobat’s field highlighting.  It just looks a bit weird when the entire widget holding the floating fields is highlighted.
  • Versioning.  Notice the sample has a version checking button.  It would not be surprising if I needed to update the script for bug fixes or small enhancements.

How it Works

Floating fields are represented by some custom XHTML syntax:

<span xfa:embedType="uri" xfa:embedMode="raw" xfa:embed="#FF011680"/>

The concept is fairly simple.  The form parses the XHTML, finding all the embedded fields.  It then changes the syntax to:

<span style="background-color:#101010">referenced field value</span>

Meanwhile the form also collects the plain text from the XHTML and determines the start/end offsets of the field data.  When the user types into the field, we use the change event to ensure that their edits are within the range of one of the referenced fields.  If the edit is not in range, the form ‘swallows’ the event.

If the field has no value, we replace the field content in the display with a string of non-breaking spaces.

When exiting the field, we gather all the ranges of text that correspond to fields and push them back out to the field objects.

It’s all fairly simple in concept, but the code ended up being fairly complex.  One of the hardest parts was handling undo/redo.  Undo and redo will modify a field without firing a change event. This means that the cached offsets become stale.  There is code that detects if the field value has been modified since the last change event.  If so, the offsets are re-calculated.

Some Possible Enhancements

It would be nice if we could limit keystrokes to what is allowed by the referenced field.  e.g. if the referenced field is numeric, allow only numeric text to be entered for that floating field

Currently if the floating fields are updated externally from the floating field editor, the changes are not detected.

We could update the referenced fields on every keystroke rather than only on exit.

The sample does not handle xfa:embedMode="formatted". If this were supported then when editing the values you would see the edit format of the field and when you exit you would see the formatted value.