vdv@dyomedea.com
Many thanks to
for their review and comments
<figures> <line> <length> <value>10</value> <unit>in</unit> </length> </line> </figures>
<xf:model> <xf:instance> <figures> <line> <length> <value>10</value> <unit>in</unit> </length> </line> </figures> </xf:instance> </xf:model>
<xf:group ref="line/length"> <xf:input ref="value"> <xf:label>Length: </xf:label> </xf:input> <xf:select1 ref="unit"> <xf:label></xf:label> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> <xf:item> <xf:label>font size</xf:label> <xf:value>em</xf:value> </xf:item> .../... <xf:item> <xf:label>%</xf:label> <xf:value>%</xf:value> </xf:item> </xf:select1> </xf:group>
<!--No controller... yet!-->
<xf:instance id="main"> <figures> <line length="10in"/> </figures> </xf:instance>
<xf:model> <xf:instance id="main"> <figures> <line length="10in"/> </figures> </xf:instance> <xf:instance id="split"> <line> <length> <value/> <unit/> </length> </line> </xf:instance> .../... </xf:model>
<xf:group ref="instance('split')/length"> <xf:input ref="value" id="length-control"> <xf:label>Length: </xf:label> </xf:input> <xf:select1 ref="unit" id="unit-control"> <xf:label/> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... <xf:item> <xf:label>%</xf:label> <xf:value>%</xf:value> </xf:item> </xf:select1> </xf:group>
<xf:model> .../... <xf:action ev:event="xforms-ready"> <xf:setvalue ref="instance('split')/length/value" value="translate(instance('main')/line/@length, '%incmptxe', '')"/> <xf:setvalue ref="instance('split')/length/unit" value="translate(instance('main')/line/@length, '0123456789', '')"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="length-control"> <xf:setvalue ref="instance('main')/line/@length" value="concat(instance('split')/length/value, instance('split')/length/unit)"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="unit-control"> <xf:setvalue ref="instance('main')/line/@length" value="concat(instance('split')/length/value, instance('split')/length/unit)"/> </xf:action> </xf:model>
<xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> </figures> </xf:instance>
Same than previous, twice
Hint: Copy/paste is your friend
<xf:model> <xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> </figures> </xf:instance> <xf:instance id="height"> <height> <value/> <unit/> </height> </xf:instance> .../... <xf:instance id="width"> <width> <value/> <unit/> </width> </xf:instance> .../... </xf:model>
<xf:group ref="instance('height')"> <xf:input ref="value" id="height-value-control"> <xf:label>Height: </xf:label> </xf:input> <xf:select1 ref="unit" id="height-unit-control"> <xf:label/> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... </xf:select1> </xf:group> <xh:br/> <xf:group ref="instance('width')"> <xf:input ref="value" id="width-value-control"> <xf:label>Width: </xf:label> </xf:input> <xf:select1 ref="unit" id="width-unit-control"> <xf:label/> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... </xf:select1> </xf:group>
<xf:model> .../... <xf:action ev:event="xforms-ready"> <xf:setvalue ref="instance('height')/value" value="translate(instance('main')/rectangle/@height, '%incmptxe', '')"/> <xf:setvalue ref="instance('height')/unit" value="translate(instance('main')/rectangle/@height, '0123456789', '')"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="height-value-control"> <xf:setvalue ref="instance('main')/rectangle/@height" value="concat(instance('height')/value, instance('height')/unit)"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="height-unit-control"> <xf:setvalue ref="instance('main')/rectangle/@height" value="concat(instance('height')/value, instance('height')/unit)"/> </xf:action> .../... <xf:action ev:event="xforms-ready"> <xf:setvalue ref="instance('width')/value" value="translate(instance('main')/rectangle/@width, '%incmptxe', '')"/> <xf:setvalue ref="instance('width')/unit" value="translate(instance('main')/rectangle/@width, '0123456789', '')"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="width-value-control"> <xf:setvalue ref="instance('main')/rectangle/@width" value="concat(instance('width')/value, instance('width')/unit)"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="width-unit-control"> <xf:setvalue ref="instance('main')/rectangle/@width" value="concat(instance('width')/value, instance('width')/unit)"/> </xf:action> </xf:model>
<xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> .../... <rectangle height="20in" width="4%"/> </figures> </xf:instance>
Lack of "components" to package group of controls with their models, views and controllers.
How can you reuse something split into three domains?
Components should have their own models, views and controllers!
<xf:model> <xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> </figures> </xf:instance> </xf:model>
Same as for XForms quiz (3/3)
<xh:body> <my:dimension ref="rectangle/@height"> <xf:label>Height</xf:label> </my:dimension> <br/> <my:dimension ref="rectangle/@width"> <xf:label>Width</xf:label> </my:dimension> </xh:body>
<my:dimension> elements to be replaced by a transformation
<xsl:template match="my:dimension" mode="model"> <xsl:variable name="id" select="if (@id) then @id else generate-id()"/> <xf:instance id="{$id}-instance"> <height> <value/> <unit/> </height> </xf:instance> </xsl:template>
<xsl:template match="my:dimension"> <xsl:variable name="id" select="if (@id) then @id else generate-id()"/> <xf:group ref="instance('{$id}-instance')"> <xf:input ref="value" id="{$id}-value-control"> <xsl:apply-templates/> </xf:input> <xf:select1 ref="unit" id="{$id}-unit-control"> <xf:label/> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... </xf:select1> </xf:group> </xsl:template>
<xsl:template match="my:dimension" mode="model"> <xsl:variable name="id" select="if (@id) then @id else generate-id()"/> .../... <xf:action ev:event="xforms-ready"> <xf:setvalue ref="instance('{$id}-instance')/value" value="translate(instance('main')/{@ref}, '%incmptxe', '')"/> <xf:setvalue ref="instance('{$id}-instance')/unit" value="translate(instance('main')/{@ref}, '0123456789', '')"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="{$id}-value-control"> <xf:setvalue ref="instance('main')/{@ref}" value="concat(instance('{$id}-instance')/value, instance('{$id}-instance')/unit)"/> </xf:action> <xf:action ev:event="xforms-value-changed" ev:observer="{$id}-unit-control"> <xf:setvalue ref="instance('main')/{@ref}" value="concat(instance('{$id}-instance')/value, instance('{$id}-instance')/unit)"/> </xf:action> </xsl:template>
my:dimension/@ref
won't behave like XForms' @ref
<xf:model> <xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> </figures> </xf:instance> </xf:model>
Same as for templating's model
<xh:body> <my:dimension ref="rectangle/@height"> <xf:label>Height</xf:label> </my:dimension> <br/> <my:dimension ref="rectangle/@width"> <xf:label>Width</xf:label> </my:dimension> </xh:body>
<my:dimension>
elements instantiate the component<xbl:binding id="my-dimension" element="my|dimension" xxbl:mode="lhha binding value"> <xbl:handlers> .../... </xbl:handlers> <xbl:implementation> .../... </xbl:implementation> <xbl:template> .../... </xbl:template> </xbl:binding>
<xbl:implementation> <xf:model id="my-dimension-model"> <xf:instance id="my-dimension-instance"> <dimension> <value/> <unit/> </dimension> </xf:instance> .../... </xbl:implementation>
<xbl:template> <xf:input ref="value" id="my-dimension-value-control"/> <xf:select1 ref="unit" id="my-dimension-unit-control"> <xf:label/> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... </xf:select1> </xbl:template>
<xbl:handlers> <xbl:handler event="xforms-enabled xforms-value-changed"> <xf:setvalue ref="instance('my-dimension-instance')/value" value="translate(xxf:binding('my-dimension'), '%incmptxe', '')"/> <xf:setvalue ref="instance('my-dimension-instance')/unit" value="translate(xxf:binding('my-dimension'), '0123456789', '')"/> </xbl:handler> </xbl:handlers>
<xbl:implementation> <xf:model id="my-dimension-model"> .../... <xf:setvalue ev:event="xforms-value-changed" ev:observer="my-dimension-value-control" ref="xxf:binding('my-dimension')" value="concat(instance('my-dimension-instance')/value, instance('my-dimension-instance')/unit)"/> <xf:setvalue ev:event="xforms-value-changed" ev:observer="my-dimension-unit-control" ref="xxf:binding('my-dimension')" value="concat(instance('my-dimension-instance')/value, instance('my-dimension-instance')/unit)"/> </xf:model> </xbl:implementation>
Subforms are called subforms as they are *not* components ;)
We will come up with our own component model in betterFORM 6 which will orient at more modern approaches (Web Components).
<xf:model id="dimension-model"> <xf:instance id="concat"> <data/> </xf:instance> <xf:instance id="split"> <height> <value/> <unit/> </height> </xf:instance> .../... </xf:model>
<xf:group ref="instance('split')"> <xf:input ref="value"> <xf:action ev:event="xforms-value-changed"> <xf:setvalue ref="instance('concat')" value="concat(instance('split')/value, instance('split')/unit)"/> <xf:send submission="set-dimension-value"/> </xf:action> </xf:input> <xf:select1 ref="unit"> <xf:action ev:event="xforms-value-changed"> <xf:setvalue ref="instance('concat')" value="concat(instance('split')/value, instance('split')/unit)"/> <xf:send submission="set-dimension-value"/> </xf:action> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... </xf:select1> </xf:group>
<xf:model id="dimension-model"> .../... <xf:submission id="get-dimension-value" resource="model:master#instance('dimension-interface')/*" replace="instance" method="get"> <xf:action ev:event="xforms-submit-done"> <xf:setvalue ref="instance('split')/value" value="translate(instance('concat'), '%incmptxe', '')"/> <xf:setvalue ref="instance('split')/unit" value="translate(instance('concat'), '0123456789', '')"/> </xf:action> </xf:submission> <xf:send ev:event="xforms-ready" submission="get-dimension-value"/> <xf:submission id="set-dimension-value" resource="model:master#instance('dimension-interface')/*" replace="none" method="post"/> </xf:model>
<xf:model id="master"> <xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> </figures> </xf:instance> <!-- Instance used as an "interface" with the subform --> <xf:instance id="dimension-interface"> <dimension active=""/> </xf:instance> </xf:model>
<xf:group ref="rectangle"> <!-- Height --> <xf:group ref="@height"> <xf:label>Height: </xf:label> <!-- This should be displayed when the subform is not editing the height --> <xf:group ref=".[instance('dimension-interface')/@active!='height']"> <xf:output ref="."/> <xf:trigger ref=".[instance('dimension-interface')/@active = '']"> <xf:label>Edit</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue ref="instance('dimension-interface')" value="instance('main')/rectangle/@height"/> <xf:setvalue ref="instance('dimension-interface')/@active">height</xf:setvalue> <xf:load show="embed" targetid="height" resource="subform-embedded.xhtml"/> </xf:action> </xf:trigger> </xf:group> <xh:div id="height"/> <!-- This should be displayed only when we're editing the height --> <xf:group ref=".[instance('dimension-interface')/@active='height']"> <xf:trigger> <xf:label>Done</xf:label> <xf:action ev:event="DOMActivate"> <xf:setvalue value="instance('dimension-interface')" ref="instance('main')/rectangle/@height"/> <xf:setvalue ref="instance('dimension-interface')/@active"/> <xf:load show="none" targetid="height"/> </xf:action> </xf:trigger> </xf:group> </xf:group> <br/> <!-- Width --> <xf:group ref="@width"> .../... </xf:group> </xf:group>
Porting our example from betterFORM to XSLTForms is not that difficult (see my paper)
I have implemented a new component control in XSLTForms. It is named "xf:component" and has two attributes named "@ref" and "@resource".
<xf:model> <xf:instance> <size> <value xsi:type="xsd:decimal">2</value> <unit>cm</unit> </size> </xf:instance> <xf:bind ref="subform-instance()/value" changed="translate(subform-context(), '%incmptxe', '')"/> <xf:bind ref="subform-instance()/unit" changed="translate(subform-context(), '0123456789', '')"/> </xf:model>
<xh:body> <xf:input ref="subform-instance()/value"> <xf:label/> <xf:setvalue ev:event="xforms-value-changed" ref="subform-context()" value="concat(subform-instance()/value, subform-instance()/unit)"/> </xf:input> <xf:select1 ref="subform-instance()/unit"> <xf:label/> <xf:item> <xf:label>pixels</xf:label> <xf:value>px</xf:value> </xf:item> .../... <xf:setvalue ev:event="xforms-value-changed" ref="subform-context()" value="concat(subform-instance()/value, subform-instance()/unit)"/> </xf:select1> </xh:body>
<xf:model> <xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> </figures> </xf:instance> </xf:model>
<xf:group ref="rectangle"> <!-- Height --> <xf:group ref="@height"> <xf:label>Height: </xf:label> <xf:component ref="." resource="component-subform.xml"/> </xf:group> <br/> <!-- Width --> <xf:group ref="@width"> <xf:label>Width: </xf:label> <xf:component ref="." resource="component-subform.xml"/> </xf:group> </xf:group>
Use a spacebar or arrow keys to navigate