vdv@dyomedea.com
Many thanks to
for their review and comments
Image © Wikimedia
Image © Wikimedia
<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!-->
Image © Wikimedia
<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>
Image © Wikimedia
<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>
Image © Wikimedia
<xf:instance id="main"> <figures> <rectangle height="10in" width="4em"/> .../... <rectangle height="20in" width="4%"/> </figures> </xf:instance>
Image © Wikimedia
Lack of "components" to package group of controls with their models, views and controllers.
Image © Wikimedia
How can you reuse something split into three domains?
Image © JavaWorld
Components should have their own models, views and controllers!
Image © Wikimedia
Image © Wikimedia
Image © Wikimedia
<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
Image © Wikimedia
<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>
Image © Wikimedia
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>
Image © Wikimedia
Use a spacebar or arrow keys to navigate