Projects‎ > ‎

XForms - JavaScript


[STATUS: As of 2009-12-02, enhancements described here are not implemented in Orbeon Forms yet.]

Read access

Write access

Usage

Just like name/value pairs (parameters) can be provided to JavaScript code, we introduce a mechanism by which JavaScript code can return a single value, or name/value pairs, which are then accessible through the event object in XForms. For instance:

<xxforms:script>
    <xxforms:code>
        return {
            latitude: 42,
            longitude: 43
        }
    </xxforms:code>
    <xforms:action ev:event="xxforms-script-done">
        <xxforms:variable name="result" select="event('xxforms:script-result')"/>
        <xforms:setvalue ref="/position/latitude" value="$result/latitude"/>
        <xforms:setvalue ref="/position/longitude" value="$result/longitude"/>
    </xforms:action>
</xxforms:script>

Note:
  • We add a new event xxforms-script-done. It occurs after the script has successfuly ran. The event is asyncronous, as scripts are executed asynchronously (note the similarity here with the <xforms:submission> and the xforms-submit-done event).
  • The JavaScript code can either return a value of a primitive type (e.g. 42), or an object with attribute having with a value of a primitive type (as in the example above).
  • In the event handler, event('xxforms:script-result')returns a document equivalent to the value returned by the JavaScript code encoded in JSON and converted to XML according to these rules. In essence:
    • If 42 is returned, we'll get <root type="number">42</root>.
    • If { latitude: 42, longitude: 43 }, we'll get <root><latitude type="number">42</latitude><longitude type="number">43</longitude></root>.

Implementation

If there is an event listener on xxforms-script-done, the server will tell the client that it needs to send back to the server the value returned by the script. It will also provide to the client a context which will be passed back by the client when sending the response, so the server can know for which script the response is. For instance:

<xxf:script name="xf_7_xforms_function" target-id="trigger" observer-id="group" script-id="xyz"/>

The client can then send back the value with the the following event:

<xxforms:event name="xxforms-script-done" source-control-id="xyz">
    [Result of the function
encoded in JSON]
</xxforms:event>

In the response here we pass back the script ID in the source-control-id attribute. We reuse this attribute for consistency with other events sent by the client. In this case, the
source-control-id represents a <xxforms:script> which is not a control; and this attribute should maybe be renamed (say to just source-id).

Accessing XBL parameters in JavaScript

Rationale

We want the user of an XBL component to be able to pass a value to an XBL component. This value can be either:
  • Defined globally for all the instances of the component in a property.
  • Be passed with an attribute on the component.
  • Be passed with a nested element of the component, which allows single node binding attributes

Implementing components

Rationale

  • Facilitate integration w/ JS controls such as existing and new YUI widgets
  • Facilitate integration w/ 3rd party JS controls
  • Client-side code for custom XBL components
  • Support built-in controls as well
  • Currently:
    • no API, no good patterns
    • hacks in xforms.js to support updates to itemsets and value changes, because server-side events fail to work properly within repeats

Lifecycle

Each control needs methods to control its lifecycle:
  • create
  • destroy
  • value changed
  • enable/disable
  • readonly/readwrite
  • itemset changed

Current strategy

Our current approach is to use XBL to implement components, and to use the XForms events for the events listed above. Experience will show how far we can go with this; in particular, XForms events might not always correspond to key events in the life of the component.

Page initialization performance

Overview

  • Unresolved 1s – When loading a large page (FR summary page with 100 items shown), the Firefox profiler says that 1.1s is spent in getViewportWidth(). When this call is removed, the same amount of time is spent in Dom.getStyle(). It is unclear if Firebug is reporting time that is really spent in those methods, or if those methods trigger the browser to perform some operation that has to be done, and that would happen anyway when the page loads.
  • Performance gains – Using class xforms-dnd instead of xforms-repeat-delimiter and delaying the dialog rendering improves the performance by 15%. Optimizing the way we find D&D elements gives us another 50% boost.

D&D initialization

Dialog initialization

When dialogs are rendered, the Module._initResizeMonitor() end up being called. The first time this method is called, it creates a _yuiResizeMonitor iframe, which is an expensive operation. On a fairly large page (FR summary page with 100 of lines displayed), it takes about 140 ms second. The whole time is taken by the code that sets oIFrame.style.top. We posted in the YUI mailing list about the performance of the _initResizeMonitor(). One way around this is to set the monitorresize property to false. For now, we have not opted for doing this change.



Comments