- From: Jason Eacott <jeacott@hardlight.com.au>
- Date: Wed, 5 Oct 2005 19:20:17 +0930
- To: Allan Beaufour <abeaufour@novell.com>
- Cc: www-forms@w3.org
ok, this is how I did it. it uses Chiba and some serverside stuff, but should work with any xforms engine. Here is my actual form builder form. with it you can select from a list of available existing forms or create a new one, you can then edit it and save it. you could easilly modify how the save works. my version http posts back to the server where it is processed and stored. This form probably wont be instantly useful for you, but may help somebody, and encourace some xforms work in this area. There are a number of xform hacks and workaround for both xforms and chiba shortcomings, but the result whilst not perfect does work very well. This isnt rocket science and you are free to use/modify my code as you see fit. It would be nice if you would maintain an acknowledgment of my effort though if you choose to. one benefit of this approach is that I have since been asked to incorporate workflow for others to vet the completed form. I can do this fairly easilly because I can generate different forms from the one instance so that users that need to test the form can do so without it sending emails etc to everyone, then once its approved I can regenerate the form complete with its submission detail. hope that makes sense. <?xml version="1.0" encoding="UTF-8"?> <!-- <html xmlns="http://www.w3.org/2002/06/xhtml2" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> --> <!-- Author: Jason Eacott Copyright Hardlight Interactive Pty Ltd 2005 XForm Builder, for Chiba, integrated with Manifest as a Manifest plugin. Xforms are saved to Manifest Repository. The Actual Xforms themselves are generated via XSLT run on the formdefinition instance which remains a part of the built XForm enabling it to be edited by this Builder Form. The working Xforms also use the formdefinition instance to store their own instance data. The datasink protocol is a custom generic XML data sink that will accept xml submissions from xforms and store them. each item element represent a control in the form being built. each submission element represents an email address that the resulting form's submitted data should be mailed to. --> <snapin:xform xmlns:chiba="http://chiba.sourceforge.net/xforms" chiba:stylesheet="vcard.xsl" xmlns:snapin="http://www.hardlight.com.au" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ><Properties Title="Form Builder" /> <head> <title>Form Builder</title> <xf:model id="model_1"> <xf:submission id="debug" action="http://localhost/chiba1/jsp/return-instance.jsp" method="post" replace="all" ref="instance('formdefinition')" /> <xf:submission id="editform" action="FormManager?command=loadinstance" method="post" replace="instance" ref="instance('formdefinition')//mform" /> <xf:submission id="deleteform" action="FormManager?command=delete" method="post" replace="none" ref="instance('formdefinition')//mform" /> <xf:submission id="saveform" action="FormManager?command=save" method="post" replace="instance" ref="instance('formdefinition')" /> <xf:submission id="loadformlist" action="FormManager?command=loadformlist" method="post" replace="instance" ref="instance('formlist')" /> <xf:submission id="loadpagelist" action="FormManager?command=loadpagelist" method="post" replace="instance" ref="instance('pagelist')" /> <xf:instance id="formdefinition"> <data xmlns=""> <mform title="" id="" instanceid="" name=""/> <item description="" value="" constraint="" readonly="" required="false" fieldtype="" mediatype="" filename=""><options multiselect="false" type="checkbox"><option/></options></item> <submissions> <submission action=""/> </submissions> <submission action="datasink://serversubmit" label="save" active="true" /> <forward url="page?pg=38" /> </data> </xf:instance> <!-- used to email to multiple targets for a given form --> <xf:bind id="fdsubmissions" nodeset="instance('formdefinition')/submissions" > <!-- --> <xf:bind id="submission-bind-entry" nodeset="submission" > <xf:bind id="fdsubaction" nodeset="@action" required="true()" constraint="(string-length(.) = 0) or (string-length(.) > 2 and contains(., '@') and not(starts-with(., '@')) and not(substring(., string-length(.)) = '@'))"/> <xf:bind id="fdsublabel" nodeset="@label" /> <xf:bind id="submission-bind-entry-value" nodeset="." /> </xf:bind> </xf:bind> <xf:bind id="fdsinksubmission" nodeset="instance('formdefinition')/submission" > <xf:bind id="fdsinkactive" nodeset="@active" relevant="count(instance('formdefinition')/submissions/submission)"/> </xf:bind> <xf:bind id="fdforwardto" nodeset="instance('formdefinition')/forward"> <xf:bind id="fdforwardurl" nodeset="@url" required="true()"/> </xf:bind> <xf:bind id="fdform" nodeset="instance('formdefinition')/mform"> <xf:bind id="fdtitle" nodeset="@title" /> <xf:bind id="fdname" nodeset="@name" required="true()" /> <xf:bind id="fdid" nodeset="@id" /> <xf:bind id="fdinstanceid" nodeset="@instanceid" /> <!-- <xf:bind id="fdinstance" nodeset="inst" /> --> </xf:bind> <xf:bind id="fditem" nodeset="instance('formdefinition')/item"> <xf:bind id="fdfieldtype" nodeset="@fieldtype" /> <xf:bind id="fddescription" nodeset="@description" required="true()" /> <xf:bind id="fdrequired" nodeset="@required" /> <xf:bind id="fdconstraint" nodeset="@constraint" relevant="../@description='keep'" /> <xf:bind id="fdoptions" nodeset="options[1]" relevant="../@fieldtype='option' "> <!-- <xf:bind id="fdoptionstype" nodeset="@type" /> <xf:bind id="fdmultiselect" nodeset="@multiselect" /> --> <xf:bind id="fdoptionstype" nodeset="@type" /> <xf:bind id="fdmultiselect" nodeset="@multiselect" /> <xf:bind nodeset="option" id="optionbind-entry"> <xf:bind nodeset="." id="bind-entry-value" required="true()" /> </xf:bind> </xf:bind> </xf:bind> <xf:bind id="bind-last-entry" nodeset="instance('formdefinition')/item[last()]" /> <xf:instance id="scratchpad"> <temp xmlns=""> <dummy /> <fieldTypeOptions> <!-- <option value="blank" label="" /> --> <option value="input" label="Input Field" /> <option value="textarea" label="Text Area"> </option> <option value="option" maxselect="1" label="Option"> </option> <option value="secret" label="Secret"> </option> <option value="label" label="Output"> </option> <option value="upload" label="Upload"> </option> </fieldTypeOptions> <tempoption> <option value="" label="" /> </tempoption> <work> <item description="" constraint="" readonly="" required="" rele="" fieldtype="" priority="" /> </work> <mform url=""/> </temp> </xf:instance> <xf:bind id="bscratchfieldtypeoptions" nodeset="instance('scratchpad')/fieldTypeOptions[1]" required="@required='true'"> <xf:bind nodeset="option" id="bscratchoptionbind-entry"> <xf:bind nodeset="@label" id="bscratchbind-entry- label" /> <xf:bind nodeset="@value" id="bscratchbind-entry-value" /> </xf:bind> </xf:bind> <xf:bind id="bscratchtempoption" nodeset="instance('scratchpad')/tempoption/option" /> <xf:bind id="thisform" nodeset="instance('scratchpad')/mform/@url" /> <!-- required="true()" --> <xf:action ev:event="xforms-ready"> <!-- delete the item ONLY if there is one and its description is empty. thsi should be enough to indicate we havent loaded an already built form. --> <xf:delete bind="fditem" at="if( (count(instance('formdefinition')/item)=1) and (instance('formdefinition')/item/@description=''),last(),0)" /> <xf:delete bind="submission-bind-entry" at="if( (count(instance('formdefinition')/submissions/submission)=1) and instance('formdefinition')/submissions/submission/@action='',last(),0) " /> <xf:delete bind="mlform" at="if( (count(instance('formlist')/mform)=1) and (instance('formlist')/mform/@id=''),last(),0)" /> <xf:send submission="loadformlist"/> </xf:action> <!-- needed cause output ref="concat(xpath)" breaks chiba --> <!-- <xf:action ev:event="xforms-recalculate"> <xf:setvalue bind="thisform" value="concat('http://willow/anty7/page?pg=',instance('formdefinition' )/mform/@id)"/> </xf:action> --> <!-- <xf:instance id="formlist" src="http://willow/anty7/FormManager?command=loadformlist" > --> <xf:instance id="formlist" > <data xmlns=""> <mform name="" title="" id="" source="" modifieddate="" creationdate=""/> </data> </xf:instance> <xf:bind id="mlform" nodeset="instance('formlist')/mform"> <xf:bind nodeset="@title" id="mlformtitle"/> <xf:bind nodeset="@name" id="mlformname"/> <xf:bind nodeset="@id" id="mlformid"/> <!-- <xf:bind nodeset="inst" id="mlforminstance"/> --> </xf:bind> <xf:instance id="pagelist" > <data xmlns=""> <mform id="" title="" name=""/> <page name="" id=""/> </data> </xf:instance> <xf:bind id="plpagelist" nodeset="instance('pagelist')"> <xf:bind nodeset="mform" id="plform"> <xf:bind nodeset="@name" id="plformname"/> <xf:bind nodeset="@id" id="plformid"/> </xf:bind> <!-- <xf:bind nodeset="page" id="plpages" calculate="concat('http://willow/anty7/',@id)"> --> <xf:bind nodeset="page" id="plpages"> <xf:bind nodeset="@name" id="plpagename"/> <xf:bind nodeset="@id" id="plpageid" /> <xf:bind nodeset="." id="plpage" /> </xf:bind> </xf:bind> </xf:model> <!-- <xf:model id="model_list"> <xf:instance id="formlist"> <data xmlns=""> <form title="form 1" id="1" source="http://willow/page?pg=1&stypen=xml" /> <form title="form 2" id="2" source="http://willow/page?pg=2&stypen=xml" /> <form title="form 3" id="3" source="http://willow/page?pg=3&stypen=xml" /> <form title="form 4" id="4" source="http://willow/page?pg=4&stypen=xml" /> </data> </xf:instance> </xf:model> --> </head> <body> <!-- ############# Form UI start here ###############--> <!-- ################################################ --> <xf:switch id="switch"> <xf:case id="case-formchooser" xf:selected="true"> <xf:group id="group-formchooser"> <xf:output bind="fdfieldtype" appearance="minimal"> <xf:label>create a new form</xf:label> </xf:output> <xf:trigger appearance="minimal"> <xf:label>Create New Form</xf:label> <xf:action > <xf:reset id="reset-cancel" model="model_1"/> <xf:dispatch name="xforms-ready" target="model_1" /> <xf:toggle id="toggle-cancel" case="case-editor" /> </xf:action> </xf:trigger> <xf:group > <xf:trigger> <xf:label>Refresh</xf:label> <xf:send submission="loadformlist"/> <xf:refresh/> </xf:trigger> <xf:repeat id="repeatformlist" bind="mlform"> <xf:output bind="mlformid" appearance="full"/> <xf:output bind="mlformname" appearance="full"/> <xf:output bind="mlformtitle" appearance="full"/> </xf:repeat> <xf:group appearance="compact"> <xf:trigger> <xf:label>Edit Selected</xf:label> <xf:hint>edit this item</xf:hint> <!-- submit form and get new data --> <!-- set the id of the form we want to load --> <xf:setvalue bind="fdid" value="instance('formlist')/mform[index('repeatformlist')]/@id" /> <!-- <xf:setvalue bind="fdid" value="./@id" /> --> <xf:setvalue bind="fdinstanceid" value="''" /> <xf:setvalue bind="fdname" value="'temp'" /> <!-- this is required so that the submission works it will always be replaced--> <xf:send submission="editform" /> <!-- <xf:refresh ev:event="DOMActivate" /> --> <xf:dispatch name="xforms-ready" target="model_1" /> <xf:setvalue bind="plformid" value="instance('formdefinition')//mform/@id" /> <xf:send submission="loadpagelist"/> <xf:toggle id="toggle-cancel" case="case-editor" /> <!-- <xf:delete at="1" ev:event="DOMActivate" nodeset="."/> --> </xf:trigger> <xf:trigger> <xf:label>Copy</xf:label> <xf:hint>Make a new copy of this form</xf:hint> <!-- set the id of the form we want to copy --> <xf:setvalue bind="fdid" value="instance('formlist')/mform[index('repeatformlist')]/@id" /> <xf:setvalue bind="fdinstanceid" value="''" /> <xf:setvalue bind="fdname" value="'temp'" /> <!-- this is required so that the submission works it will always be replaced--> <xf:send submission="editform" /> <xf:dispatch name="xforms-ready" target="model_1" /> <!-- set the form id to nothing to indicate to the server that this should be considered a new form. clear the form name field too. --> <xf:setvalue bind="fdname" value="''" /> <xf:setvalue bind="fdid" value="''" /> <xf:setvalue bind="fdinstanceid" value="''" /> <xf:toggle id="toggle-cancel" case="case-editor" /> <!-- <xf:delete at="1" ev:event="DOMActivate" nodeset="."/> --> </xf:trigger> <xf:trigger> <xf:label>Delete</xf:label> <xf:hint>Delete this form</xf:hint> <xf:help>This will NOT delete the data associated with this form</xf:help> <!-- set the id of the form we want to copy --> <xf:setvalue bind="fdid" value="instance('formlist')/mform[index('repeatformlist')]/@id" /> <xf:setvalue bind="fdinstanceid" value="''" /> <xf:setvalue bind="fdname" value="'temp'" /> <!-- this is required so that the submission works it will always be replaced--> <xf:send submission="deleteform" /> <xf:send submission="loadformlist"/> <!-- because we cant submit from one instance and retreive into another --> </xf:trigger> </xf:group> </xf:group> </xf:group> </xf:case> <xf:case id="case-editor"> <xf:group id="group-editor"> <xf:trigger id="trigger-formchooser"> <xf:label><-FORMS</xf:label> <xf:action id="action-formchooser"> <xf:setvalue bind="fdname" value="'temp'" /> <!-- this is required so that the submission works. it will always be replaced--> <xf:revalidate id="revalidate-formchooser" /> <xf:toggle id="toggle-formchooser" xf:case="case-formchooser" /> </xf:action> </xf:trigger> <xf:label>Form ID</xf:label> <xf:output bind="fdid" appearance="full" /> <!-- <a href="http://willow/anty7/"<xf:output bind="plformid" appearance="full" /> --> <!-- ######################### --> <xf:repeat bind="plpages" id="repeatpagelist"> <xf:output value="@name" appearance="full" />: <xf:output value="@id" appearance="anchor" /> </xf:repeat> <xf:label>Form Instance</xf:label> <xf:group appearance="minimal"> <xf:label>Form Details</xf:label> <xf:input bind="fdname"> <xf:label>Name</xf:label> <xf:hint id="hint-Name"> Please enter a Name for the form, the form will be saved with this name. </xf:hint> <xf:alert id="alert-Name">Please enter a NAME for the Form</xf:alert> </xf:input> <xf:input bind="fdtitle"> <xf:label>Title</xf:label> <xf:hint id="hint-Title"> Please enter a TITLE for the form, the title will be used in Hyperlinks. </xf:hint> <xf:alert id="alert-Title">Please enter a TITLE for the form</xf:alert> </xf:input> </xf:group> <xf:group> <xf:group appearance="minimal"> <xf:label>Form Controls</xf:label> </xf:group> <xf:group> <xf:repeat id="repeat_1" bind="fditem" appearance="compact"> <xf:textarea bind="fddescription"> <xf:label>description</xf:label> <xf:alert id="alert-description">Please specify an entry value</xf:alert> <xf:help>Please specify an entry value</xf:help> <xf:hint>Please specify an entry value</xf:hint> </xf:textarea> <xf:output bind="fdfieldtype" appearance="minimal"> <xf:label>Field Type</xf:label> </xf:output> <xf:select bind="fdrequired" appearance="full"> <xf:label>Required?</xf:label> <xf:item> <xf:value>true</xf:value> </xf:item> </xf:select> <xf:group bind="fdoptions" appearance="full"> <xf:group appearance="minimal"> <xf:trigger> <xf:label>Insert Option after selected</xf:label> <xf:action> <xf:revalidate /> <xf:insert bind="optionbind-entry" at="index('repeat_option')" position="after" /> <!-- reset this to empty if there is data here --> </xf:action> </xf:trigger> <xf:trigger> <xf:label>Delete selected option</xf:label> <xf:action> <xf:delete bind="optionbind-entry" at="index('repeat_option')" /> </xf:action> </xf:trigger> </xf:group> <!-- type --> <xf:select1 bind="fdoptionstype" appearance="full"> <xf:label>Type</xf:label> <xf:item> <xf:label>DropList</xf:label> <xf:value>droplist</xf:value> </xf:item> <xf:item> <xf:label>CheckBox</xf:label> <xf:value>checkbox</xf:value> </xf:item> <xf:item> <xf:label>ListBox</xf:label> <xf:value>listbox</xf:value> </xf:item> </xf:select1> <xf:select bind="fdmultiselect" appearance="full"> <xf:label>Multi Select?</xf:label> <xf:item> <xf:value>true</xf:value> </xf:item> </xf:select> <xf:repeat id="repeat_option" bind="optionbind-entry"> <xf:label>Option</xf:label> <xf:input bind="bind-entry-value"> <xf:label>Option</xf:label> <xf:alert id="alert-option">Please specify an entry value</xf:alert> </xf:input> </xf:repeat> </xf:group> <!-- </xf:group > --> </xf:repeat> <xf:group appearance="minimal"> <xf:select1 bind="bscratchtempoption" appearance="minimal"> <!-- <xf:label>Field Type</xf:label> --> <xf:itemset bind="bscratchoptionbind-entry"> <xf:label bind="bscratchbind-entry-label" /> <xf:value bind="bscratchbind-entry-value" /> </xf:itemset> </xf:select1> <xf:trigger> <!-- create a new item --> <xf:label>Insert Item after selected</xf:label> <xf:action> <xf:revalidate /> <xf:insert bind="fditem" at="index('repeat_1')" position="after" /> <xf:setvalue ref="instance('formdefinition')/item[index('repeat_1')]/@fieldtype" value="instance('scratchpad')/tempoption/option" /> </xf:action> </xf:trigger> <xf:trigger> <xf:label>Delete selected item</xf:label> <xf:action> <xf:delete bind="fditem" at="index('repeat_1')" /> </xf:action> </xf:trigger> </xf:group> <xf:group appearance="minimal"> <xf:label>Send data from this form to the following Email addresses:</xf:label> </xf:group> <xf:group bind="fdsubmissions" appearance="full"> <xf:group appearance="compact"> <xf:trigger> <xf:label>Insert email after selected</xf:label> <xf:action> <xf:revalidate /> <xf:insert bind="submission-bind-entry" at="index('repeat_submission')" position="after" /> <!-- reset this to empty if there is data here --> </xf:action> </xf:trigger> <xf:trigger> <xf:label>Delete selected email</xf:label> <xf:action> <xf:delete bind="submission-bind-entry" at="index('repeat_submission')" /> </xf:action> </xf:trigger> </xf:group> </xf:group> <xf:repeat id="repeat_submission" bind="submission- bind-entry"> <xf:input bind="fdsubaction"> <xf:label>Email Address</xf:label> <xf:alert id="alert-option">Please specify an entry value</xf:alert> </xf:input> </xf:repeat> <xf:group bind="fdsinkactive"> <xf:select bind="fdsinkactive" appearance="full"> <xf:label>Would you like to save the collected data from this form?</xf:label> <xf:item> <xf:label>Yes</xf:label> <xf:value>true</xf:value> </xf:item> </xf:select> </xf:group> <xf:trigger> <xf:label>Save Form</xf:label> <xf:action ev:event="DOMActivate"> <xf:send submission="saveform" /> <xf:dispatch name="xforms-ready" target="model_1" /> <!-- <xf:send submission="loadformlist"/> --> <xf:setvalue bind="plformid" value="instance('formdefinition')//mform/@id" /> <xf:send submission="loadpagelist"/> <!-- <xforms:toggle case="responseGUI" /> --> </xf:action> </xf:trigger> <xf:trigger> <xf:label>Debug Form</xf:label> <xf:action ev:event="DOMActivate"> <xf:send submission="debug" /> </xf:action> </xf:trigger> <xf:group appearance="minimal"> <xf:label>Enter a URL to navigate to After form submission</xf:label> <xf:input bind="fdforwardurl"> <xf:label>URL:</xf:label> <xf:alert id="alert-option">Required value MUST be a valid URL</xf:alert> </xf:input> </xf:group> <!-- get new id(s) back and list locations of form for viewing. --> </xf:group> </xf:group> </xf:group> </xf:case> </xf:switch> </body> </snapin:xform> From: Allan Beaufour <abeaufour@novell.com> To: www-forms@w3.org Date sent: Wed, 5 Oct 2005 10:48:50 +0200 Subject: Re: Loading & saving documents Forwarded by: www-forms@w3.org Date forwarded: Wed, 05 Oct 2005 08:49:03 +0000 > > Tuesday 04 October 2005 15:52 skrev Flinton Adam: > > I can start off hosting the page/form itself within a jsp but the files > > to be opened would always be on the user's local disk & would need to be > > persisted back to that disk. > > The tricky bit is how to let the user choose what file to load from and store > to. As long as you have a server involved, the server could create an > instance with the possible data documents. The user could then select a > location with a select1, triggering a submission that loads the appropriate > instance data ... or creates it if the user chooses a new name. > > Without a server, it's possible to load and store from the same document, but > not letting the user choose one. > > Of course you get a bit of help from XForms Buddy, but it's not exactly > smooth, and you still depend on something "extra". > > -- > Allan Beaufour > Linux Software Engineer > > Novell, Inc. > Software for the Open Enterprise > www.novell.com/open > -- Jason Eacott Hardlight Interactive http://www.hardlight.com.au Support bacteria - they're the only culture some people have.
Received on Wednesday, 5 October 2005 10:01:08 UTC