Re: Prime mover: Simple Purchase Order Form

One interpretation of this Purchase Order that does not use the "dollar 
proposal" (i.e. XPath variables that reference inner and outer binds) is 
this:

<repeat name="order" nodeset="row">
    <select1 name="Product"> ...
    <input name="Quantity"> ...
    <input name="Price"> ...
    <output name="LineTotal" calculate="Price * Quantity"/>
</repeat>
<output name="Subtotal" calculate="sum(order/row/LineTotal)"/>
<output name="Tax" calculate="Subtotal * 0.07"/>
<output name="Total" calculate="Subtotal + Tax"/>

Notice that this is extremely short and simple-- and not dot-infested 
either.  If a purchase order can really be written with this little 
markup, then I think 1.2 will be a success with web authors. 

Notice that the attribute 'name' is used, rather than using an 
pre-existing XForms UI binding attribute like ref or bind.  I think it is 
handy to use 'name' because it is convenient for today's web authors, for 
whom we are streamlining XForms, and because 'name' really does imply more 
stuff than just a UI binding.  It also implies *some* alternate meaning 
for the calculate attribute, most notably that its evaluation context is 
*not* the result of the UI binding but rather the in-scope evaluation 
context.  This is what is helping us to get rid of the dot infestation.

I am personally a little leary of using dollar signs *because* it means 
that the simplified syntax would be dollar-infested.  And the first time 
you forget a dollar, you run the risk that your expression might 
accidentally work anyway in much of the "dollar" proposal variations I 
have seen.

So, we need to figure out whether or not to go with the "dollar proposal". 
 Below is a non-dollar proposal for what the canonical form of the above 
simplified syntax should mean.  Please think about this and comment on it 
and try to create the dollar proposal version of this.

<model>
  <instance>
    <data xmlns="">
       <order>
          <row>
            <Product> ...
            <Quantity> ...
            <Price> ...
            <LineTotal> ...
          </row>
       </order>
    </data>
  </instance>

  <bind nodeset="order">
     <bind nodeset="row">
        <bind nodeset="LineTotal">
           <calculate context=".." value="Price * Quantity"/>
        </bind>
     </bind>
  </bind>

  <bind nodeset="Subtotal">
     <calculate context=".." value="sum(order/row/LineTotal)"/>
  </bind>

  <bind nodeset="Tax">
     <calculate context=".." value="Subtotal * 0.07"/>
  </bind>

  <bind nodeset="Total">
     <calculate context=".." value="Subtotal + Tax"/>
  </bind>
</model>

<repeat context="order" nodeset="row">
    <select1 ref="Product"> ...
    <input ref="Quantity"> ...
    <input ref="Price"> ...
    <output ref="LineTotal"/>
</repeat>
<output ref="Subtotal"/>
<output ref="Tax"/>
<output ref="Total"/>
 
Notice in the UI layer that the "name" became a ref for the unitary 
controls and a context for the repeat. 

Notice that the calculate attributes were removed.  They were assumed to 
be in a ".." context so that the simplified syntax would not be 
dot-infested.  This required only the ability to reset the context on the 
calculate.

Cheers,
John M. Boyer, Ph.D.
Senior Technical Staff Member
Lotus Forms Architect and Researcher
Chair, W3C Forms Working Group
Workplace, Portal and Collaboration Software
IBM Victoria Software Lab
E-Mail: boyerj@ca.ibm.com 

Blog: http://www.ibm.com/developerworks/blogs/page/JohnBoyer
Blog RSS feed: 
http://www.ibm.com/developerworks/blogs/rss/JohnBoyer?flavor=rssdw





John Boyer/CanWest/IBM@IBMCA 
Sent by: public-forms-request@w3.org
03/04/2008 10:03 PM

To
Forms WG (new) <public-forms@w3.org>
cc

Subject
Prime mover: Simple Purchase Order Form







In order to fuel the discussion of the simplified, on-the-glass syntax, 
here is the "canonical" version of a purchase order form that we would 
like to express with the simplified syntax. 

It is a 1.0 form, so it still uses a methodology for insert that was 
needed prior to having the origin attribute. 

Mark, this is the form that needs to be able to use bind sites and $ XPath 
variables.  Will you be able to whip up a translation before the call? 

<?xml version="1.0" encoding="UTF-8"?> 

<!-- The purpose of this form is to demonstrate the XForms 1.0 methods 
that are likely 
        to come into play when handling a simple repeat table, such as in 
a purchase order. 
 
        Here are the important aspects of how row insertion and deletion 
are done: 
 
        1) The last row of the data is regarded as containing 
'prototypical' 
           data for use in row insertion. 
        2) The last row containing the prototypical data is made 
non-relevant. 
        3) The last row is excluded from the repeat nodeset.  Although 
repeats 
                don't show non-relevant rows, the repeat index can become 
equal 
                to the position of a non-relevant row, so it is easier to 
manage 
                the repeat by excluding the non-relevant node from the 
nodeset. 
        4) A new first row of data is generated on startup (if only one 
row exists) 
                so that the user will have an initial table row with which 
to interact. 
        5) The delete trigger uses a conditional insert to make sure that 
the 
                repeat is never empty of relevant nodes. 
        6) The insert and delete triggers use a setfocus action because 
the user 
                activation of a trigger transfers focus to that trigger, 
so we want 
                the focus to go back to the repeat table when the 
operations over the 
                repeat nodeset are completed. 
--> 

<html xmlns:ev="http://www.w3.org/2001/xml-events" 
      xmlns:xforms="http://www.w3.org/2002/xforms" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 

   <head> 
     <xforms:model> 
         <xforms:instance id="po" xmlns=""> 
            <po> 
               <order> 
                   <row> 
                       <product/> 
                       <unitCost>0</unitCost> 
                       <qty>0</qty> 
                       <lineTotal>0</lineTotal> 
                   </row> 
               </order> 
               <subtotal>0</subtotal> 
               <tax>0</tax> 
               <total>0</total>     
            </po> 
         </xforms:instance> 
          
         <!-- Make the last row of the table non-relevant so it can be 
              used as prototypical data for insertion --> 
         <xforms:bind nodeset="order/row[last()]" relevant="false()"/> 
          
         <!-- If there is only one row, it is non-relevant so add another 
row --> 
         <xforms:insert ev:event="xforms-model-construct-done" 
                        nodeset="order/row[last()=1]" at="1" 
position="before"/> 
 
         <!-- This instance contains a temporary variable that allows the 
form 
                author to configure what the sales tax rate is.  This 
could be 
                obtained from external data instead using the src 
attribute. --> 
         <xforms:instance id='taxrate' xmlns=""> 
             <rate>0.07</rate> 
         </xforms:instance> 
          
         <!-- This instance contains the product list, which also could be 

                obtained externally using src.  --> 
         <xforms:instance id='products' xmlns=""> 
             <products> 
                <product name="Widget" code="W1"/> 
                <product name="Gadget" code="G1"/> 
                <product name="Trinket" code="T1"/> 
                <product name="Gromet" code="G2"/> 
             </products> 
         </xforms:instance> 
          
         <!-- The total is just the sum of the subtotal and the tax; any 
time 
                those change, the total is automatically updated --> 
         <xforms:bind nodeset="total" calculate="../subtotal + ../tax"/> 
          
         <!-- The tax is just the subtotal times the tax rate --> 
         <xforms:bind nodeset="tax" calculate="../subtotal * 
instance('taxrate')"/> 
          
         <!-- The subtotal is the sum of all the line totals.  Any time a 
row is 
                inserted, deleted or changed, the subtotal is 
automatically updated. 
                The calculate uses the 'node set' feature of XPath to get 
however 
                many line total elements exist for the summation. --> 
         <xforms:bind nodeset="subtotal" 
calculate="sum(../order/row/lineTotal)"/> 
          
         <!-- The node set feature of XPath is used to get all the line 
total 
                elements and set a calculation for each one.  A line total 
is 
                just the unit cost times the quantity.  Any time a new row 
is 
                inserted, this declaration automatically creates a new 
line total 
                calculation for it.  An update of unit cost or quantity on 
any row 
                automatically updates the line total of that row, which 
then causes 
                the subtotal, tax and total to be updated automatically. 
Even though 
                those calculations are declared before this one, XForms 
reorders the 
                calculations so that they run in the order that makes 
sense. --> 
 
         <xforms:bind nodeset="order/row/lineTotal" calculate="../unitCost 
* ../qty"/> 
 
         <!-- This submission simulates a simple server module that 
bounces submitted 
                data back to the client.  It does so by doing put then get 
on a file 
                (the location of which is based on retrieval domain of the 
form) --> 
         <xforms:submission id="S" method="put" 
includenamespaceprefixes="" 
                            replace="none" action="file:poBounce.xml"> 
              <xforms:send ev:event="xforms-submit-done" submission="T"/> 
              <xforms:message ev:event="xforms-submit-error" 
level="modal">Could not upload file</xforms:message> 
         </xforms:submission> 
          
         <xforms:submission id="T" method="get" action="file:poBounce.xml" 
replace="all"/> 
     </xforms:model> 
   </head> 
   <body> 
         <xforms:trigger> 
            <xforms:label>Add to Order</xforms:label> 
            <xforms:action ev:event="DOMActivate"> 
               <!-- Insert a new row after the one that had the focus 
before this trigger 
                        was activated, then set the focus from this 
trigger back to the repeat --> 
               <xforms:insert nodeset="order/row" at="index('orderTable')" 
position="after"/> 
               <xforms:setfocus control="orderTable"/> 
            </xforms:action> 
         </xforms:trigger> 

         <xforms:trigger> 
            <xforms:label>Delete Row</xforms:label> 
            <xforms:action ev:event="DOMActivate"> 
               <!-- Delete the row that had the focus before this trigger 
was activated. 
                    Then, if only the prototypical row remains, then 
insert a new row for 
                    the user.  Otherwise, if the last row was deleted, 
then set the table 
                    index now points at the non-relevant row containing 
the prototypical 
                    data, so we bump it up one to point to the last 
relevant row. Finally, 
                    we set the focus from the delete trigger back to the 
repeat. --> 
               <xforms:delete nodeset="order/row[last()>1]" 
at="index('orderTable')"/> 
               <xforms:insert nodeset="order/row[last()=1]" at="1" 
position="before"/> 
               <xforms:setfocus control="orderTable"/> 
            </xforms:action> 
         </xforms:trigger> 
 
         <xforms:submit submission="S"> 
                <xforms:label>Submit Order</xforms:label> 
         </xforms:submit> 

         <xforms:repeat nodeset="order/row[position()!=last()]" 
id="orderTable" startindex="1"> 
              <xforms:select1 ref="product" appearance="minimal"> 
                  <xforms:label>Product Name</xforms:label> 
                  <xforms:itemset nodeset="instance('products')/product"> 
                     <xforms:label ref="@name"/> 
                     <xforms:value ref="@code"/> 
                  </xforms:itemset> 
              </xforms:select1> 

              <xforms:input ref="unitCost"> 
                  <xforms:label>Unit Cost</xforms:label> 
              </xforms:input> 

              <xforms:input ref="qty"> 
                  <xforms:label>Quantity</xforms:label> 
              </xforms:input> 

              <xforms:output ref="lineTotal"> 
                  <xforms:label>Line Total</xforms:label> 
              </xforms:output> 
          </xforms:repeat> 

          <xforms:output ref="subtotal"> 
               <xforms:label>Subtotal: </xforms:label> 
          </xforms:output> 

          <xforms:output ref="tax"> 
               <xforms:label>Tax: </xforms:label> 
          </xforms:output> 

          <xforms:output ref="total"> 
               <xforms:label>Total: </xforms:label> 
          </xforms:output> 
   </body> 
</html> 

Received on Wednesday, 5 March 2008 17:29:02 UTC