You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Reinhard Poetz <re...@apache.org> on 2003/10/21 10:06:44 UTC

Thoughts on Woody ...

After (nearly) finishing a project where we implemented our own little
forms frameworks (... we had already started when Woody became part of
Cocoon) I want to share some ideas with you.

To be able to make a comparisons I dived into the current implementation
of Woody. Now I can say that I'm really impressed by the architecture
and I also like it very much *how* you did it.

So here a few (random) thoughts what could be useful for Woody:

Global widget definition repository 
-----------------------------------

Currently we have a strict binding between widget definition and the
template where the widgets are instantiated:

         1           :           1
   +------------+         +------------+
   |            |         |            |
   |   widget-  |         |   widget-  |
   |  defintion | ----->  |  instances |
   |            |         |            |
   |            |         |            |
   +------------+         +------------+
 
This goes so far that all defined widgets must be instantiated in order
to get no (hidden) errors during validation. This also means for
applications that consist of more than one form you sooner or later have
to define your widgets (e.g. an email address) as often as you
instantiate them.

I think we should decouple this behaviour into following:


   +------------+ 
   |            | 
   |   global   |
   |   widget   |\
   | repository | \
   |            |  \
   +------------+   \use
         |           \
         | ext        \
         V             \
   +------------+       \ +------------+
   |            |         |            |
   |   widget-  |  use    |   widget-  |
   |  defintion | ------- |  instances |
   |            |         |            |
   |            |         |            |
   +------------+         +------------+


The global widget repository contains widgets that can be reused in all
forms within your Cocoon installation. I also think that it could be
possible to extend global widget defintions:

  <wd:field id="glEmail" required="true">
    <wd:datatype base="string">
      <wd:validation>
        <wd:email/>
      </wd:validation>
    </wd:datatype>
  </wd:field>

  <wd:field id="supplierEmail" extends="glEmail">
    <wd:label>Supplier's email address:</wd:label>
  </wd:field>

  <wd:field id="customerEmail" extends="glEmail">
    <wd:label>Customer's email address:</wd:label>
  </wd:field>


Multi page forms
----------------

We have already discussed this several times on the dev-list and at the
GetTogether in Gent. IIUC Thorsten, Bruno and I agreed that we don't
like some kind of a "phases" concept because everything you need can be
found at the template and why should you declare things twice. If you
think of dynamic forms (e.g. wheter a widget is show depends on the
rights of the user) you also come into troubles because your phases will
have to become dynamic too!

As mentioned the list of the required widgets is already known because
the template transformer instantiates all widgets. But there is a
problem (or at least I'm not sure how to solve it) with this approach:
The template transformer is the last step before a new continuation is
created. So it would be possible to save a list of all required widgets.
That's fine. The problem is that this list has to be connected to a
certain continuation because otherwise you would get serious troubles if
the user clones the window. OTOH if we save the list of the required
widgets with the continuation it can become expensive from a memory POV,
can't it?

Are there other thougts how to solve the multi page forms problem? 
Sylvain, you mentioned at the end of your presentation something at the
GT Hackaton but I can't remember. Could you help us (me)?


Lookup values
-------------

We already have some helpers to make it easy to enter correct data into
your fields. One thing missing is the possibility to lookup values.
Suppose you have a field "country". One possibility would be to a drop
down field the other possibility a usual input field with an icon on its
right side. If you click on this icon another window opens (inline like
in Eclipse or a popup) and you get a list of all countries. You can
select one and the value is copied into the main form. So what's the
advantage compared to a selection list:

 * You don't need to load such a long list like all countries
   in the world at form load time but then when the user
   wants to fill in the value
   (this makes no real difference for one field but if you have e.g.
    10 fields containing so many possible values there is one, believe
me!)
 * You can provide additional information: e.g. you have to
   select a customer - you could show the address, the birthdate, ...
   to make the choice for the user easier
 * You can structure your date  e.g. you can create
   a tree where all countries can be found in a tree
 * You can provide help when a selection list is not
   good enough. Think of a search form e.g. you can search in your
   customers database for the right one and select it. The
   selected customer is filled in the form.
 * You can fill in more than one field with one selection (think
   of a row in a table --> with one selection the whole row
   could be completed)


Thoughts?

Cheers,
Reinhard

P.S. Thanks to Michael Gerzabek because the first and the third point
are definitly inspired by him :-)



Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Leszek Gawron wrote:

>On Wed, Oct 22, 2003 at 12:06:01PM +0200, Sylvain Wallez wrote:
>  
>
>>Joerg Heinicke wrote:
>>
>>    
>>
>>>Sylvain Wallez wrote:
>>>      
>>>
>><snip/>
>>
>>    
>>
>>>>Well, "backtracking" means "go back to a previous state and restart 
>>>>        
>>>>
>>>>from there". And this is what continuations allow easily.
>>>
>>>
>>>But when I use "go back" in a wizard I don't want to loose the entries 
>>>already done in the second page. So simply calling the other 
>>>continuation is not good in my opinion. 
>>>      
>>>
>>The flowscript allows you to implement any strategy you like for this.
>>
>>Want to keep the values :
>> var form1 = new Form("form1.xml");
>> var form2 = new Form("form2.xml");
>> form1.showForm("view1.html");
>> form2.showForm("view2.html");
>>
>>If you display form2 and then go back to form1 (even with the browser 
>>back button), the values in form2 won't be lost.
>>    
>>
>The problem is that this is not "even" but "only". Otherwise you have to use
>JavaScript.
>

Sorry, I don't get it. Do you mean "JavaScript on the browser" ?

Please read my flowscript-wizard proposal earlier in this thread. The 
idea is that a particular submit button (a regular one, with no JS) will 
trigger the wizard to go back to a previous continuation.

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



Re: Thoughts on Woody ...

Posted by Leszek Gawron <ou...@wlkp.org>.
On Wed, Oct 22, 2003 at 12:06:01PM +0200, Sylvain Wallez wrote:
> Joerg Heinicke wrote:
> 
> >Sylvain Wallez wrote:
> 
> <snip/>
> 
> >>Well, "backtracking" means "go back to a previous state and restart 
> >>from there". And this is what continuations allow easily.
> >
> >
> >But when I use "go back" in a wizard I don't want to loose the entries 
> >already done in the second page. So simply calling the other 
> >continuation is not good in my opinion. 
> 
> 
> The flowscript allows you to implement any strategy you like for this.
> 
> Want to keep the values :
>  var form1 = new Form("form1.xml");
>  var form2 = new Form("form2.xml");
>  form1.showForm("view1.html");
>  form2.showForm("view2.html");
> 
> If you display form2 and then go back to form1 (even with the browser 
> back button), the values in form2 won't be lost.
The problem is that this is not "even" but "only". Otherwise you have to use
JavaScript.
	LG
-- 
            __
         | /  \ |        Leszek Gawron            //  \\
        \_\\  //_/       ouzo@wlkp.org           _\\()//_
         .'/()\'.     Phone: +48(501)720812     / //  \\ \
          \\  //  recursive: adj; see recursive  | \__/ |


Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Reinhard Poetz wrote:

>From: Sylvain Wallez
>  
>
>>>This is fine and already works today.
>>>But how do we handle data binding, suppose you have a 10 pages form. I don't want to do this explicitly for each form [this means writing 10 times load(...) and 10 times save(...)] or is this the way we should go?
>>>      
>>>
>>Mmmh... is this a "composite binding" on a "composite form" composed of several individual forms?
>>
>>Or maybe just a helper JS library for linear multi-form wizards to which you would just give the list of definitions, views and bindings.
>>    
>>
>
>Some mails ago you introduced a wizard object, maybe we can use it:
>
>function myWizard() {
>  var myBean = new BlaBla(); // get values from your backend
>  var wiz = new Wizard();
>  wiz.setForm( "form1", new Form( "form1.xml" ), [myBean] );
>  wiz.setForm( "form1", new Form( "form1.xml" ), [myBean] );
>
>  wiz.getForm("form1").showView( "myForm1Pipeline", {} );
>  wiz.getForm("form1").showView( "myForm1Pipeline", {} );
>}
>
>
>interface Wizard() {
>  void setForm(String id, Form form, Object[] binding);
>  Form getForm(String id);
>}
>
>... I think I get it slowly, don't I?
>

Yep ;-)

The wizard I was thinking of was generic and not woody-related, so the 
one you outline above can be a FormWizard built on top of the generic 
Wizard class.

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



RE: Thoughts on Woody ...

Posted by Reinhard Poetz <re...@apache.org>.
From: Sylvain Wallez

> >This is fine and already works today.
> >But how do we handle data binding, suppose you have a 10 
> pages form. I 
> >don't want to do this explicitly for each form [this means 
> writing 10 
> >times load(...) and 10 times save(...)] or is this the way we should 
> >go?
> >
> 
> Mmmh... is this a "composite binding" on a "composite form" 
> composed of 
> several individual forms?
> 
> Or maybe just a helper JS library for linear multi-form 
> wizards to which 
> you would just give the list of definitions, views and bindings.

Some mails ago you introduced a wizard object, maybe we can use it:

function myWizard() {
  var myBean = new BlaBla(); // get values from your backend
  var wiz = new Wizard();
  wiz.setForm( "form1", new Form( "form1.xml" ), [myBean] );
  wiz.setForm( "form1", new Form( "form1.xml" ), [myBean] );

  wiz.getForm("form1").showView( "myForm1Pipeline", {} );
  wiz.getForm("form1").showView( "myForm1Pipeline", {} );
}


interface Wizard() {
  void setForm(String id, Form form, Object[] binding);
  Form getForm(String id);
}

... I think I get it slowly, don't I?

Reinhard



Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Reinhard Poetz wrote:

>From: Sylvain Wallez
>
>  
>
>>Joerg Heinicke wrote:
>>
>>    
>>
>>>Sylvain Wallez wrote:
>>>      
>>>
>><snip/>
>>
>>    
>>
>>>>Well, "backtracking" means "go back to a previous state and restart from there". And this is what continuations allow easily.
>>>>        
>>>>
>>>But when I use "go back" in a wizard I don't want to loose the entries already done in the second page. So simply calling the other continuation is not good in my opinion. 
>>>      
>>>
>>The flowscript allows you to implement any strategy you like for this.
>>
>>Want to keep the values :
>>  var form1 = new Form("form1.xml");
>>  var form2 = new Form("form2.xml");
>>  form1.showForm("view1.html");
>>  form2.showForm("view2.html");
>>    
>>
>
>This is fine and already works today.
>But how do we handle data binding, suppose you have a 10 pages form. I
>don't want to do this explicitly for each form [this means writing 10
>times load(...) and 10 times save(...)] or is this the way we should go?
>

Mmmh... is this a "composite binding" on a "composite form" composed of 
several individual forms?

Or maybe just a helper JS library for linear multi-form wizards to which 
you would just give the list of definitions, views and bindings.

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



RE: Thoughts on Woody ...

Posted by Reinhard Poetz <re...@apache.org>.
From: Sylvain Wallez

> Joerg Heinicke wrote:
> 
> > Sylvain Wallez wrote:
> 
> <snip/>
> 
> >> Well, "backtracking" means "go back to a previous state and restart
> >> from there". And this is what continuations allow easily.
> >
> >
> > But when I use "go back" in a wizard I don't want to loose 
> the entries
> > already done in the second page. So simply calling the other 
> > continuation is not good in my opinion. 
> 
> 
> The flowscript allows you to implement any strategy you like for this.
> 
> Want to keep the values :
>   var form1 = new Form("form1.xml");
>   var form2 = new Form("form2.xml");
>   form1.showForm("view1.html");
>   form2.showForm("view2.html");
> 

This is fine and already works today.
But how do we handle data binding, suppose you have a 10 pages form. I
don't want to do this explicitly for each form [this means writing 10
times load(...) and 10 times save(...)] or is this the way we should go?

Reinhard


Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Joerg Heinicke wrote:

> Sylvain Wallez wrote:

<snip/>

>> Well, "backtracking" means "go back to a previous state and restart 
>> from there". And this is what continuations allow easily.
>
>
> But when I use "go back" in a wizard I don't want to loose the entries 
> already done in the second page. So simply calling the other 
> continuation is not good in my opinion. 


The flowscript allows you to implement any strategy you like for this.

Want to keep the values :
  var form1 = new Form("form1.xml");
  var form2 = new Form("form2.xml");
  form1.showForm("view1.html");
  form2.showForm("view2.html");

If you display form2 and then go back to form1 (even with the browser 
back button), the values in form2 won't be lost.

Do not want to keep the values:
  var form1 = new Form("form1.xml");
  form1.showForm("view1.html");
  var form2 = new Form("form2.xml");
  form2.showForm("view2.html");

In this case, since the "form2" variable is created _after_ form1 is 
displayed, it is created anew each time you exit form1.

This is the magic of continuations ;-)

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
>>> hm.. that's what I had in mind when I read Reinhard's proposal
> 
> 
> I see a difference between a widget repository and a datatype 
> repository. When presenting Woody in our company I was asked for a 
> widget repository too. But more important is the datatype repository, 
> the widget repository does not avoid so much typing.

+1

>>>>  What I mentioned was the need for a generic flowscript wizard library,
>>>> that could allow to define "backtrack points" in the list of 
>>>> ancestors of the current continuation.
>>>
>>>
>>>
>>>
>>> hm... why is backtracking needed? or what do you mean by it? 
>>
>>
>>
>>
>> Well, "backtracking" means "go back to a previous state and restart 
>> from there". And this is what continuations allow easily.
> 
> 
> But when I use "go back" in a wizard I don't want to loose the entries 
> already done in the second page. So simply calling the other 
> continuation is not good in my opinion.

That's exactly my point :) ..we would need to popluate
into the data of the continuation we are coming from when
going back to the one that got us there. (Hope noone got
too crosseyed at that sentence ;)
--
Torsten


Re: Thoughts on Woody ...

Posted by Christopher Oliver <re...@verizon.net>.
Sylvain Wallez wrote:

> Christopher Oliver wrote:
>
>> I think you're making this much more complicated than it needs to be. 
>> Please look at how JXForms does this. First it creates a continuation 
>> immediately before and immediately after a page is sent to the 
>> browser. The latter continuation behaves exactly like 
>> sendPageAndWait(). However, by invoking the former you cause the page 
>> to be resent (and processing to restart when that page is 
>> resubmitted). So:
>>
>> 1) If you invoke the current continuation processing continues after 
>> the current page is submitted.
>> 2) If you invoke its parent continuation the current page is resent 
>> to the browser.
>> 3) If you invoke the grandparent continuation the actions following 
>> submission of the previous page are replayed.
>> 4) If you invoke the great-grandparent continuation the previous page 
>> is resent to the browser.
>>
>> So to implement the "back" button, you invoke (4).
>>
>> The idea is that instead of only encoding the continuation id in the 
>> form or request url, you also associate a "forward" or "back" action 
>> with the submit button. The form submits are _always_ submitted to 
>> the same location, where some Java or JavaScript code looks at the 
>> continuation id together with "forward" or "back" indication of the 
>> submit button. If the indication is "forward" then you simply look up 
>> the continuation associated with the continuation id and invoke it. 
>> But if the indication is "back" then you invoke the great-grandparent 
>> of the continuation.
>
>
>
> I'll look more closely to JXForms. However, does the above behaviour 
> fit with the fact that form.showForm() creates several continuations 
> when iterating until the form is valid? In that case, we cannot just 
> consider restarting at the n-2th or n-3th continuations, since 
> intermediate continuations may have occured inbetween...

Yes it does fit.  An initial continuation is created outside the loop. 
It is reused in each iteration of the loop, becoming the parent of the 
continuation created in each iteration.

>
>> With this approach your example reduces to this (and most importantly 
>> you don't have to explicitly code back/forward navigation in your 
>> flow script):
>>
>> function myWizard() {
>>    var wizard = new Wizard("wizard-spec.xml");
>>    wizard.show("first-page.html");
>>    wizard.show("second-page.html");
>>    wizard.show("third-page.html");
>>    cocoon.sendPage("finished.html");
>> } 
>
>
>
> Mmmh... what I don't like above is that the wizard is sending the 
> pages. How can we with this approach mix form.showForm and 
> cocoon.sendPageAndWait in the same wizard-style interaction?

Why do you need to mix in sendPageAndWait()?



RE: Thoughts on Woody ...

Posted by Reinhard Poetz <re...@apache.org>.
From: Sylvain Wallez

> Christopher Oliver wrote:
> 
> > I think you're making this much more complicated than it 
> needs to be.
> > Please look at how JXForms does this. First it creates a 
> continuation 
> > immediately before and immediately after a page is sent to the 
> > browser. The latter continuation behaves exactly like 
> > sendPageAndWait(). However, by invoking the former you 
> cause the page 
> > to be resent (and processing to restart when that page is 
> > resubmitted). So:
> >
> > 1) If you invoke the current continuation processing continues after
> > the current page is submitted.
> > 2) If you invoke its parent continuation the current page 
> is resent to 
> > the browser.
> > 3) If you invoke the grandparent continuation the actions following 
> > submission of the previous page are replayed.
> > 4) If you invoke the great-grandparent continuation the 
> previous page 
> > is resent to the browser.
> >
> > So to implement the "back" button, you invoke (4).
> >
> > The idea is that instead of only encoding the continuation id in the
> > form or request url, you also associate a "forward" or 
> "back" action 
> > with the submit button. The form submits are _always_ 
> submitted to the 
> > same location, where some Java or JavaScript code looks at the 
> > continuation id together with "forward" or "back" indication of the 
> > submit button. If the indication is "forward" then you 
> simply look up 
> > the continuation associated with the continuation id and invoke it. 
> > But if the indication is "back" then you invoke the 
> great-grandparent 
> > of the continuation.
> 
> 
> I'll look more closely to JXForms. However, does the above 
> behaviour fit 
> with the fact that form.showForm() creates several continuations when 
> iterating until the form is valid? In that case, we cannot 
> just consider 
> restarting at the n-2th or n-3th continuations, since intermediate 
> continuations may have occured inbetween...

I think Chris means this (out of the JXForms example):

JXForm.prototype.sendView = function(uri, validator) {
    var lastWebCont = this.lastWebContinuation;
    // create a continuation, the invocation of which will resend
    // the page: this is used to implement <xf:submit
continuation="back">
    var wk = this.start(lastWebCont);
    while (true) {
        this.removeForm();
        this.saveForm();
        var thisWebCont = this._sendView(uri, wk);
        // _sendView creates a continuation, the invocation of which
        // will return right here: it is used to implement 
        // <xf:submit continuation="forward">
        this.populateForm();
        var phase = cocoon.request.getAttribute("jxform-submit-phase");
        if (validator != undefined) {
            validator(this);
        }
        this.validateForm(phase);
        if (!this.hasViolations()) {
            this.lastWebContinuation = thisWebCont;
            break;
        }
    }
}


> 
> > With this approach your example reduces to this (and most 
> importantly 
> > you don't have to explicitly code back/forward navigation 
> in your flow 
> > script):
> >
> > function myWizard() {
> >    var wizard = new Wizard("wizard-spec.xml");
> >    wizard.show("first-page.html");
> >    wizard.show("second-page.html");
> >    wizard.show("third-page.html");
> >    cocoon.sendPage("finished.html");
> > } 
> 
> 
> Mmmh... what I don't like above is that the wizard is sending 
> the pages. 
> How can we with this approach mix form.showForm and 
> cocoon.sendPageAndWait in the same wizard-style interaction?

What do you mean here? Can you give an example of your use case?

Reinhard


Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Christopher Oliver wrote:

> I think you're making this much more complicated than it needs to be. 
> Please look at how JXForms does this. First it creates a continuation 
> immediately before and immediately after a page is sent to the 
> browser. The latter continuation behaves exactly like 
> sendPageAndWait(). However, by invoking the former you cause the page 
> to be resent (and processing to restart when that page is 
> resubmitted). So:
>
> 1) If you invoke the current continuation processing continues after 
> the current page is submitted.
> 2) If you invoke its parent continuation the current page is resent to 
> the browser.
> 3) If you invoke the grandparent continuation the actions following 
> submission of the previous page are replayed.
> 4) If you invoke the great-grandparent continuation the previous page 
> is resent to the browser.
>
> So to implement the "back" button, you invoke (4).
>
> The idea is that instead of only encoding the continuation id in the 
> form or request url, you also associate a "forward" or "back" action 
> with the submit button. The form submits are _always_ submitted to the 
> same location, where some Java or JavaScript code looks at the 
> continuation id together with "forward" or "back" indication of the 
> submit button. If the indication is "forward" then you simply look up 
> the continuation associated with the continuation id and invoke it. 
> But if the indication is "back" then you invoke the great-grandparent 
> of the continuation.


I'll look more closely to JXForms. However, does the above behaviour fit 
with the fact that form.showForm() creates several continuations when 
iterating until the form is valid? In that case, we cannot just consider 
restarting at the n-2th or n-3th continuations, since intermediate 
continuations may have occured inbetween...

> With this approach your example reduces to this (and most importantly 
> you don't have to explicitly code back/forward navigation in your flow 
> script):
>
> function myWizard() {
>    var wizard = new Wizard("wizard-spec.xml");
>    wizard.show("first-page.html");
>    wizard.show("second-page.html");
>    wizard.show("third-page.html");
>    cocoon.sendPage("finished.html");
> } 


Mmmh... what I don't like above is that the wizard is sending the pages. 
How can we with this approach mix form.showForm and 
cocoon.sendPageAndWait in the same wizard-style interaction?

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



Re: Thoughts on Woody ...

Posted by Christopher Oliver <re...@verizon.net>.
I think you're making this much more complicated than it needs to be. 
Please look at how JXForms does this. First it creates a continuation 
immediately before and immediately after a page is sent to the browser. 
The latter continuation behaves exactly like sendPageAndWait(). However, 
by invoking the former you cause the page to be resent (and processing 
to restart when that page is resubmitted). So:

1) If you invoke the current continuation processing continues after the 
current page is submitted.
2) If you invoke its parent continuation the current page is resent to 
the browser.
3) If you invoke the grandparent continuation the actions following 
submission of the previous page are replayed.
4) If you invoke the great-grandparent continuation the previous page is 
resent to the browser.

So to implement the "back" button, you invoke (4).

The idea is that instead of only encoding the continuation id in the 
form or request url, you also associate a "forward" or "back" action 
with the submit button. The form submits are _always_ submitted to the 
same location, where some Java or JavaScript code looks at the 
continuation id together with "forward" or "back" indication of the 
submit button. If the indication is "forward" then you simply look up 
the continuation associated with the continuation id and invoke it. But 
if the indication is "back" then you invoke the great-grandparent of the 
continuation. With this approach your example reduces to this (and most 
importantly you don't have to explicitly code back/forward navigation in 
your flow script):

function myWizard() {
    var wizard = new Wizard("wizard-spec.xml");
    wizard.show("first-page.html");
    wizard.show("second-page.html");
    wizard.show("third-page.html");
    cocoon.sendPage("finished.html");
}

Sylvain Wallez wrote:

> Torsten Curdt wrote:
>
>>> No problem with the wizard approach I suggested: the form contains a 
>>> link only to *one* continuation (the one that displayed the current 
>>> page), and upon post, the wizard ressurects the previous continuation.
>>>
>>> This means that the current form can be populated and then the 
>>> previous one displayed.
>>
>>
>>
>> ok, so let's the say the back button is linked (via POST) to the
>> exact same continuation that got us to that particular view - how
>> should we actually control to go back to the previous one? we are
>> asking for the same one!
>>
>> sorry, don't get that...
>
>
> Let's look again at the (still hypothetical) wizard library:
>
> function myWizard() {
> var wizard = new Wizard();
> // register the current execution location as a backtrack point
> wizard.markStep();
> cocoon.sendPageAndWait("first-page.html");
> var value = cocoon.request.getParameter("value");
> wizard.markStep();
> if (value == "foo") {
>   cocoon.sendPageAndWait("foo-page.html");
>   wizard.handleBack();
> } else {
>   cocoon.sendPageAndWait("bar-page.html");
>   wizard.handleBack();
> }
> wizard.markStep();
> cocoon.sendPageAndWait("third-page.html");
> wizard.handleBack();
> cocoon.sendPage("finished.html");
> }
>
> The wizard object contains a stack of continuations. When 
> wizard.markStep() is called, a continuation corresponding to the 
> current location is added on the top of the stack. Notice how 
> wizard.markStep() is called before every page is displayed: this will 
> allow us to go back just before that display.
>
> In wizard.handleBack(), we examine the request for a particular 
> request parameter that indicates that the "previous" button was 
> clicked. If we find this, we pop _two_ continuations from the stack 
> (the first one would just redisplay the same page) and restore that 
> continuation.
>
> When that popped continuation is restored, flowscript execution goes 
> back to the wizard.markStep() statement where this continuation was 
> pushed on the stack. We then redisplay the previous page.
>
> Is it clearer?
>
> Note: (argh, I will obscure things again) implementation-wise, we 
> can't just have a stack in the wizard object, as it would have the 
> same value for all continuations (remember, once an object is 
> declared, its is shared by all descendant continuations). We need a 
> "ContinuationLocal" variable, analogous to "InheritableThreadLocal" 
> but for continuations, i.e. the value will be different for every 
> continuation. This is not available today, even if I have some ideas 
> on how to do it.
>
> Sylvain
>



Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Torsten Curdt wrote:

>> No problem with the wizard approach I suggested: the form contains a 
>> link only to *one* continuation (the one that displayed the current 
>> page), and upon post, the wizard ressurects the previous continuation.
>>
>> This means that the current form can be populated and then the 
>> previous one displayed.
>
>
> ok, so let's the say the back button is linked (via POST) to the
> exact same continuation that got us to that particular view - how
> should we actually control to go back to the previous one? we are
> asking for the same one!
>
> sorry, don't get that...

Let's look again at the (still hypothetical) wizard library:

function myWizard() {
 var wizard = new Wizard();
 // register the current execution location as a backtrack point
 wizard.markStep();
 cocoon.sendPageAndWait("first-page.html");
 var value = cocoon.request.getParameter("value");
 wizard.markStep();
 if (value == "foo") {
   cocoon.sendPageAndWait("foo-page.html");
   wizard.handleBack();
 } else {
   cocoon.sendPageAndWait("bar-page.html");
   wizard.handleBack();
 }
 wizard.markStep();
 cocoon.sendPageAndWait("third-page.html");
 wizard.handleBack();
 cocoon.sendPage("finished.html");
}

The wizard object contains a stack of continuations. When 
wizard.markStep() is called, a continuation corresponding to the current 
location is added on the top of the stack. Notice how wizard.markStep() 
is called before every page is displayed: this will allow us to go back 
just before that display.

In wizard.handleBack(), we examine the request for a particular request 
parameter that indicates that the "previous" button was clicked. If we 
find this, we pop _two_ continuations from the stack (the first one 
would just redisplay the same page) and restore that continuation.

When that popped continuation is restored, flowscript execution goes 
back to the wizard.markStep() statement where this continuation was 
pushed on the stack. We then redisplay the previous page.

Is it clearer?

Note: (argh, I will obscure things again) implementation-wise, we can't 
just have a stack in the wizard object, as it would have the same value 
for all continuations (remember, once an object is declared, its is 
shared by all descendant continuations). We need a "ContinuationLocal" 
variable, analogous to "InheritableThreadLocal" but for continuations, 
i.e. the value will be different for every continuation. This is not 
available today, even if I have some ideas on how to do it.

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
> No problem with the wizard approach I suggested: the form contains a 
> link only to *one* continuation (the one that displayed the current 
> page), and upon post, the wizard ressurects the previous continuation.
> 
> This means that the current form can be populated and then the previous 
> one displayed.

ok, so let's the say the back button is linked (via POST) to the
exact same continuation that got us to that particular view - how
should we actually control to go back to the previous one? we are
asking for the same one!

sorry, don't get that...

> But I know the next complain: we don't want the form to enforce 
> validation when clicking on the "back" button.

I wouldn't complain about that one
...but good to know both is possible already ;)
--
Torsten


Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Torsten Curdt wrote:

>>>>> hm... why is backtracking needed? or what do you mean by it?
>>>>
>>>>
>>>>
>>>>
>>>> Well, "backtracking" means "go back to a previous state and restart 
>>>> from
>>>> there". And this is what continuations allow easily.
>>>
>>>
>>> But when I use "go back" in a wizard I don't want to loose the 
>>> entries already done in the second page. So simply calling the other 
>>> continuation is not good in my opinion.
>>
>>
>>
>> If you jump back you don't lose data with flowscript because the only
>> one stack is saved and not the stacks which belong to a certain
>> continuation.
>
>
> Well, true - but if you change some values woody knows only after a 
> *POST* about it! so having a link to the previous continuation *does* 
> loose data. You need to do a post and populate to save the values.
>
> That's the problem 


No problem with the wizard approach I suggested: the form contains a 
link only to *one* continuation (the one that displayed the current 
page), and upon post, the wizard ressurects the previous continuation.

This means that the current form can be populated and then the previous 
one displayed.

But I know the next complain: we don't want the form to enforce 
validation when clicking on the "back" button.

This can be achieved easily by declaring the "previous" button as a 
non-validating submit widget: <wd:submit id="previous" validate="false"> 
and have the wizard.handleBack() method react on the same "previous" submit.

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



Re: Thoughts on Woody ...

Posted by Christopher Oliver <re...@verizon.net>.
Sorry, my bad. I just re-read your post (more carefully...) and I now 
see you had the same solution :)

Regards,
Chris

Torsten Curdt wrote:

> Christopher Oliver wrote:
>
>> No, we're not on the same page :(. Please see the approach taken in 
>> XMLForm/JXForms and my response to Sylvain's last message. If you 
>> follow that approach I don't think there's a problem here.
>
>
> Sorry, Dude, I cannot really see why we are not...
> Actually I don't see a major difference - just phrased
> differently... Anyway
>
> regards
> -- 
> Torsten
>
>



Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
Christopher Oliver wrote:
> No, we're not on the same page :(. Please see the approach taken in 
> XMLForm/JXForms and my response to Sylvain's last message. If you follow 
> that approach I don't think there's a problem here.

Sorry, Dude, I cannot really see why we are not...
Actually I don't see a major difference - just phrased
differently... Anyway

regards
--
Torsten


Re: Thoughts on Woody ...

Posted by Christopher Oliver <re...@verizon.net>.
No, we're not on the same page :(. Please see the approach taken in 
XMLForm/JXForms and my response to Sylvain's last message. If you follow 
that approach I don't think there's a problem here.

Regards,

Chris

Torsten Curdt wrote:

>> I don't understand what you mean. As far as I understand it the idea 
>> is to invoke a continuation that causes a previous page to be displayed. 
>
>
> yes
>
>> Control returns to the flow script when this page is submitted. 
>> Whatever values are submitted with the form are modified. Any others 
>> retain the same values. What data is lost?
>
>
> ok ...examples:
>
> page1 - associated with continuation id 1:
>  <wt:form-template action="1.continue" method="POST">
>    <wt:widget id="email"/>
>    <wt:widget id="phone"/>
>    <input type="submit" value="Next"/>
>  </wt:form-template>
>
> page2 - associated with continuation id 2:
>  <wt:form-template action="2.continue" method="POST">
>    <wt:widget id="address"/>
>    <wt:widget id="zip"/>
>  </wt:form-template>
>
>
> Now how do we go back
>
> 1) Link
>
>  <wt:form-template action="2.continue" method="POST">
>    <wt:widget id="address"/>
>    <wt:widget id="zip"/>
>    <a href="1.continue">Back</a>
>  </wt:form-template>
>
>  Does (of course) not work. We need a POST to save the values from page2
>
>
> 2) Always POST to same continuation (as Sylvain suggested)
>
>  What I did not understand:
>
>  <wt:form-template action="1.continue" method="POST">
>    <wt:widget id="address"/>
>    <wt:widget id="zip"/>
>    <input type="submit" value="Back"/>
>  </wt:form-template>
>
>    ...
>    sendPageAndWait(page1) -> continuation 1
>  continuation1:
>    save values from page1
>    ...
>    sendPageAndWait(page2) -> continuation 2
>  continuation2:
>    save values from page2
>    ...
>
>
>  Since we go back to continuation1 again and woody
>  is meant to use indirect population we would always
>  try to save values of page1 *not* page2.
>  *And* we end up showing page2 again. Of course...
>
>  So we would need to specify what to show...
>
>  <wt:form-template action="1.continue" method="POST">
>    <wt:widget id="email"/>
>    <wt:widget id="phone"/>
>    <input type="submit" name="wizard-page2" value="Next"/>
>  </wt:form-template>
>
>  <wt:form-template action="1.continue" method="POST">
>    <wt:widget id="address"/>
>    <wt:widget id="zip"/>
>    <input type="submit" name="wizard-page1" value="Back"/>
>    <input type="submit" name="wizard-page2" value="Next"/>
>  </wt:form-template>
>
>    ...
>    sendPageAndWait(page1) -> continuation 1
>  continuation1:
>    var page = extractWizardPage("wizard-",cocoon.request);
>    if (page == "page1") {
>      sendPageAndWait(page1) -> continuation x
>  continuationx:
>      save values from page1
>      "goto" continuation1
>    }
>    else if (page == "page2") {
>  continuationy:
>      sendPageAndWait(page2) -> continuation y
>      save values from page2
>      "goto" continuation1
>    }
>    else {
>    }
>
>  But how should this work when we always continue with
>  continuation 1? We never go back to continuation x or y
>
>  Well, we could move the value saving...
>
>    ...
>    sendPageAndWait(page1) -> continuation 1
>  continuation1:
>    var page = extractWizardPage("wizard-",cocoon.request);
>    save values from page ?
>    if (page == "page1") {
>      sendPageAndWait(page1) -> continuation x
>    }
>    else if (page == "page2") {
>      sendPageAndWait(page2) -> continuation y
>    }
>    else {
>    }
>
>  But since woody is meant to use indirect population
>  we need to know the page we are coming from. So the
>  only way see is to pass this request parameter as
>  well.
>
>    ...
>    sendPageAndWait(page1) -> continuation 1
>  continuation1:
>    var to = extractWizardPage("wizard-to-",cocoon.request);
>    var from = extractWizardPage("wizard-from-",cocoon.request);
>
>    if (from == "page1") {
>      save values from page1
>    }
>    else if (from == "page2") {
>      save values from page2
>    }
>
>    if (to == "page1") {
>      sendPageAndWait(page1) -> continuation x (never used)
>    }
>    else if (to == "page2") {
>      sendPageAndWait(page2) -> continuation y (never used)
>    }
>    else {
>    }
>
>  But this is stupid and does not use the continuation features
>  at all. I guess the re-use of the continuation got me on the
>  wrong track.
>
>  What I (guess) Sylvain had in mind was (please fire
>  at will ;)
>
>    ...
>  continuation1:
>    sendPageAndWait(page1) -> continuation 2
>  continuation2:
>    save values from page1
>    if (cocoon.request.getParameter("wizard-back")) {
>      "goto" continuation1
>    }
>    ...
>  continuation3:
>    sendPageAndWait(page2) -> continuation 4
>  continuation4:
>    save values from page2
>    if (cocoon.request.getParameter("wizard-back")) {
>      "goto" continuation3
>    }
>    ...
>
> Of course more modular ;)
>
> Puh... Are we now all on the same page? :)
> -- 
> Torsten
>
>



Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
> I don't understand what you mean. As far as I understand it the idea is 
> to invoke a continuation that causes a previous page to be displayed. 

yes

> Control returns to the flow script when this page is submitted. Whatever 
> values are submitted with the form are modified. Any others retain the 
> same values. What data is lost?

ok ...examples:

page1 - associated with continuation id 1:
  <wt:form-template action="1.continue" method="POST">
    <wt:widget id="email"/>
    <wt:widget id="phone"/>
    <input type="submit" value="Next"/>
  </wt:form-template>

page2 - associated with continuation id 2:
  <wt:form-template action="2.continue" method="POST">
    <wt:widget id="address"/>
    <wt:widget id="zip"/>
  </wt:form-template>


Now how do we go back

1) Link

  <wt:form-template action="2.continue" method="POST">
    <wt:widget id="address"/>
    <wt:widget id="zip"/>
    <a href="1.continue">Back</a>
  </wt:form-template>

  Does (of course) not work. We need a POST to save the values from page2


2) Always POST to same continuation (as Sylvain suggested)

  What I did not understand:

  <wt:form-template action="1.continue" method="POST">
    <wt:widget id="address"/>
    <wt:widget id="zip"/>
    <input type="submit" value="Back"/>
  </wt:form-template>

    ...
    sendPageAndWait(page1) -> continuation 1
  continuation1:
    save values from page1
    ...
    sendPageAndWait(page2) -> continuation 2
  continuation2:
    save values from page2
    ...


  Since we go back to continuation1 again and woody
  is meant to use indirect population we would always
  try to save values of page1 *not* page2.
  *And* we end up showing page2 again. Of course...

  So we would need to specify what to show...

  <wt:form-template action="1.continue" method="POST">
    <wt:widget id="email"/>
    <wt:widget id="phone"/>
    <input type="submit" name="wizard-page2" value="Next"/>
  </wt:form-template>

  <wt:form-template action="1.continue" method="POST">
    <wt:widget id="address"/>
    <wt:widget id="zip"/>
    <input type="submit" name="wizard-page1" value="Back"/>
    <input type="submit" name="wizard-page2" value="Next"/>
  </wt:form-template>

    ...
    sendPageAndWait(page1) -> continuation 1
  continuation1:
    var page = extractWizardPage("wizard-",cocoon.request);
    if (page == "page1") {
      sendPageAndWait(page1) -> continuation x
  continuationx:
      save values from page1
      "goto" continuation1
    }
    else if (page == "page2") {
  continuationy:
      sendPageAndWait(page2) -> continuation y
      save values from page2
      "goto" continuation1
    }
    else {
    }

  But how should this work when we always continue with
  continuation 1? We never go back to continuation x or y

  Well, we could move the value saving...

    ...
    sendPageAndWait(page1) -> continuation 1
  continuation1:
    var page = extractWizardPage("wizard-",cocoon.request);
    save values from page ?
    if (page == "page1") {
      sendPageAndWait(page1) -> continuation x
    }
    else if (page == "page2") {
      sendPageAndWait(page2) -> continuation y
    }
    else {
    }

  But since woody is meant to use indirect population
  we need to know the page we are coming from. So the
  only way see is to pass this request parameter as
  well.

    ...
    sendPageAndWait(page1) -> continuation 1
  continuation1:
    var to = extractWizardPage("wizard-to-",cocoon.request);
    var from = extractWizardPage("wizard-from-",cocoon.request);

    if (from == "page1") {
      save values from page1
    }
    else if (from == "page2") {
      save values from page2
    }

    if (to == "page1") {
      sendPageAndWait(page1) -> continuation x (never used)
    }
    else if (to == "page2") {
      sendPageAndWait(page2) -> continuation y (never used)
    }
    else {
    }

  But this is stupid and does not use the continuation features
  at all. I guess the re-use of the continuation got me on the
  wrong track.

  What I (guess) Sylvain had in mind was (please fire
  at will ;)

    ...
  continuation1:
    sendPageAndWait(page1) -> continuation 2
  continuation2:
    save values from page1
    if (cocoon.request.getParameter("wizard-back")) {
      "goto" continuation1
    }
    ...
  continuation3:
    sendPageAndWait(page2) -> continuation 4
  continuation4:
    save values from page2
    if (cocoon.request.getParameter("wizard-back")) {
      "goto" continuation3
    }
    ...

Of course more modular ;)

Puh... Are we now all on the same page? :)
--
Torsten


Re: Thoughts on Woody ...

Posted by Christopher Oliver <re...@verizon.net>.
Torsten Curdt wrote:

<snip>

>> If you jump back you don't lose data with flowscript because the only
>> one stack is saved and not the stacks which belong to a certain
>> continuation.
>
>
> Well, true - but if you change some values woody knows only after
> a *POST* about it! so having a link to the previous continuation
> *does* loose data. You need to do a post and populate to save the
> values.
>
> That's the problem
> -- 
> Torsten

I don't understand what you mean. As far as I understand it the idea is 
to invoke a continuation that causes a previous page to be displayed. 
Control returns to the flow script when this page is submitted. Whatever 
values are submitted with the form are modified. Any others retain the 
same values. What data is lost?

Chris


RE: Thoughts on Woody ...

Posted by Reinhard Poetz <re...@apache.org>.
From: Torsten Curdt 

> >>>>hm... why is backtracking needed? or what do you mean by it?
> >>>
> >>>
> >>>
> >>>Well, "backtracking" means "go back to a previous state and restart
> >>>from
> >>>there". And this is what continuations allow easily.
> >>
> >>But when I use "go back" in a wizard I don't want to loose
> >>the entries 
> >>already done in the second page. So simply calling the other 
> >>continuation is 
> >>not good in my opinion.
> > 
> > 
> > If you jump back you don't lose data with flowscript 
> because the only 
> > one stack is saved and not the stacks which belong to a certain 
> > continuation.
> 
> Well, true - but if you change some values woody knows only 
> after a *POST* about it! so having a link to the previous continuation
> *does* loose data. You need to do a post and populate to save 
> the values.
> 
> That's the problem

Yep I see.
I've already thought a lot about this but haven't been able to find a
solution that works in the continuations world.

Reinhard 


Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
>>>>hm... why is backtracking needed? or what do you mean by it?
>>>
>>>
>>>
>>>Well, "backtracking" means "go back to a previous state and restart 
>>>from
>>>there". And this is what continuations allow easily.
>>
>>But when I use "go back" in a wizard I don't want to loose 
>>the entries 
>>already done in the second page. So simply calling the other 
>>continuation is 
>>not good in my opinion.
> 
> 
> If you jump back you don't lose data with flowscript because the only
> one stack is saved and not the stacks which belong to a certain
> continuation.

Well, true - but if you change some values woody knows only after
a *POST* about it! so having a link to the previous continuation
*does* loose data. You need to do a post and populate to save the
values.

That's the problem
--
Torsten



RE: Thoughts on Woody ...

Posted by Reinhard Poetz <re...@apache.org>.
From: Joerg Heinicke

> Sylvain Wallez wrote:
> > Torsten Curdt wrote:
> > 
> >> <snip/>
> >>
> >>> I proposed to introduce a datatype dictionary to factorize common
> >>> type definition (along with their validators and selection-list). 
> >>> This would turn your example into something like:
> >>>
> >>> <wd:datatype id="email" base="string">
> >>>  <wd:validation>
> >>>    <wd:email/>
> >>>  </wd:validation>
> >>> </wd:datatype>
> >>>
> >>> And then:
> >>> <wd:widget id="supplierEmail" required="true">
> >>>  <wd:datatype base="email"/>
> >>> </wd:widget>
> >>
> >>
> >>
> >> hm.. that's what I had in mind when I read Reinhard's proposal
> 
> I see a difference between a widget repository and a datatype 
> repository. 
> When presenting Woody in our company I was asked for a widget 
> repository 
> too. But more important is the datatype repository, the 
> widget repository 
> does not avoid so much typing.

If you have a widget repository and you can extend existing widgets it
would help you. But maybe datatypes are the cleaner approach.

> 
> 
> >>>  What I mentioned was the need for a generic flowscript wizard 
> >>> library, that could allow to define "backtrack points" in 
> the list 
> >>> of ancestors of the current continuation.
> >>
> >>
> >>
> >> hm... why is backtracking needed? or what do you mean by it?
> > 
> > 
> > 
> > Well, "backtracking" means "go back to a previous state and restart 
> > from
> > there". And this is what continuations allow easily.
> 
> But when I use "go back" in a wizard I don't want to loose 
> the entries 
> already done in the second page. So simply calling the other 
> continuation is 
> not good in my opinion.

If you jump back you don't lose data with flowscript because the only
one stack is saved and not the stacks which belong to a certain
continuation.

Reinhard


Re: Thoughts on Woody ...

Posted by Joerg Heinicke <jh...@virbus.de>.
Sylvain Wallez wrote:
> Torsten Curdt wrote:
> 
>> <snip/>
>>
>>> I proposed to introduce a datatype dictionary to factorize common 
>>> type definition (along with their validators and selection-list). 
>>> This would turn your example into something like:
>>>
>>> <wd:datatype id="email" base="string">
>>>  <wd:validation>
>>>    <wd:email/>
>>>  </wd:validation>
>>> </wd:datatype>
>>>
>>> And then:
>>> <wd:widget id="supplierEmail" required="true">
>>>  <wd:datatype base="email"/>
>>> </wd:widget>
>>
>>
>>
>> hm.. that's what I had in mind when I read Reinhard's proposal

I see a difference between a widget repository and a datatype repository. 
When presenting Woody in our company I was asked for a widget repository 
too. But more important is the datatype repository, the widget repository 
does not avoid so much typing.


>>>  What I mentioned was the need for a generic flowscript wizard library,
>>> that could allow to define "backtrack points" in the list of 
>>> ancestors of the current continuation.
>>
>>
>>
>> hm... why is backtracking needed? or what do you mean by it? 
> 
> 
> 
> Well, "backtracking" means "go back to a previous state and restart from 
> there". And this is what continuations allow easily.

But when I use "go back" in a wizard I don't want to loose the entries 
already done in the second page. So simply calling the other continuation is 
not good in my opinion.

Joerg

-- 
System Development
VIRBUS AG
Fon  +49(0)341-979-7419
Fax  +49(0)341-979-7409
joerg.heinicke@virbus.de
www.virbus.de


Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Torsten Curdt wrote:

> <snip/>
>
>> I proposed to introduce a datatype dictionary to factorize common 
>> type definition (along with their validators and selection-list). 
>> This would turn your example into something like:
>>
>> <wd:datatype id="email" base="string">
>>  <wd:validation>
>>    <wd:email/>
>>  </wd:validation>
>> </wd:datatype>
>>
>> And then:
>> <wd:widget id="supplierEmail" required="true">
>>  <wd:datatype base="email"/>
>> </wd:widget>
>
>
> hm.. that's what I had in mind when I read Reinhard's proposal


Cool.

>>> Multi page forms
>>> ----------------
>>>
>>> We have already discussed this several times on the dev-list and at the
>>> GetTogether in Gent. IIUC Thorsten, Bruno and I agreed that we don't
>>> like some kind of a "phases" concept because everything you need can be
>>> found at the template and why should you declare things twice. If you
>>> think of dynamic forms (e.g. wheter a widget is show depends on the
>>> rights of the user) you also come into troubles because your phases 
>>> will
>>> have to become dynamic too!
>>>
>>> As mentioned the list of the required widgets is already known because
>>> the template transformer instantiates all widgets. But there is a
>>> problem (or at least I'm not sure how to solve it) with this approach:
>>> The template transformer is the last step before a new continuation is
>>> created.
>>
>>
>> Nope. The continuation is created in the controller, before the view 
>> processing starts.
>
>
> well, but the stuff *could* still be saved inside the continuation 


Sure, but do you mean that the transformer would have a side effect on 
the form it displays?

> <snip/>
>
>>  What I mentioned was the need for a generic flowscript wizard library,
>> that could allow to define "backtrack points" in the list of 
>> ancestors of the current continuation.
>
>
> hm... why is backtracking needed? or what do you mean by it? 


Well, "backtracking" means "go back to a previous state and restart from 
there". And this is what continuations allow easily.

> I still do see the problem of population if you go back to a previous 
> contiuation. not sure how to use contiuations here properly...


Which "population"? That of the form, or that of the application data? 
IMO, populating application data should only occur at the end of the 
wizard. For this, you can either extract the meaningful form information 
after each screen is displayed, or keep the various forms that compose 
the wizard and save them all in the application data at the end of the 
wizard.

>> The idea is to have a Wizard class that provides two methods:
>> - markStep(): mark a step in the wizard. A step is a location in the 
>> flowscript where we can go back. We may eventually want to name step 
>> to allow going back to directly to a step that's not the immediate 
>> previous one.
>> - handleBack(): if the "wizard-back" button was clicked, restore the 
>> previous continuation in the step stack.
>
>
> hm... could elaborate a bit more here? 


The wizard keeps a stack of continuations, and a new one is added on 
markStep(). The handleBack() method checks if a particular button has 
been clicked (the "back" button in the form) and in that case pops the 
last continuation and restores it, thus displaying the "previous" screen.

>> I already did this on a previous project to select people in a 
>> corporate directory containing about 6000 entries. The user can type 
>> in a few letters, and then the popup automatically displays the names 
>> starting with these letters.
>
>
> cool ...as a new type of widget? 


Well, soooo many widgets to write... ;-)

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
<snip/>

> I proposed to introduce a datatype dictionary to factorize common type 
> definition (along with their validators and selection-list). This would 
> turn your example into something like:
> 
> <wd:datatype id="email" base="string">
>  <wd:validation>
>    <wd:email/>
>  </wd:validation>
> </wd:datatype>
> 
> And then:
> <wd:widget id="supplierEmail" required="true">
>  <wd:datatype base="email"/>
> </wd:widget>

hm.. that's what I had in mind when I read Reinhard's proposal

>> Multi page forms
>> ----------------
>>
>> We have already discussed this several times on the dev-list and at the
>> GetTogether in Gent. IIUC Thorsten, Bruno and I agreed that we don't
>> like some kind of a "phases" concept because everything you need can be
>> found at the template and why should you declare things twice. If you
>> think of dynamic forms (e.g. wheter a widget is show depends on the
>> rights of the user) you also come into troubles because your phases will
>> have to become dynamic too!
>>
>> As mentioned the list of the required widgets is already known because
>> the template transformer instantiates all widgets. But there is a
>> problem (or at least I'm not sure how to solve it) with this approach:
>> The template transformer is the last step before a new continuation is
>> created.
>>
> 
> Nope. The continuation is created in the controller, before the view 
> processing starts.

well, but the stuff *could* still be saved inside the continuation

<snip/>

>  What I mentioned was the need for a generic flowscript wizard library,
> that could allow to define "backtrack points" in the list of ancestors 
> of the current continuation.

hm... why is backtracking needed? or what do you mean by it?

I still do see the problem of population if you go back to a
previous contiuation. not sure how to use contiuations here
properly...


> The idea is to have a Wizard class that provides two methods:
> - markStep(): mark a step in the wizard. A step is a location in the 
> flowscript where we can go back. We may eventually want to name step to 
> allow going back to directly to a step that's not the immediate previous 
> one.
> - handleBack(): if the "wizard-back" button was clicked, restore the 
> previous continuation in the step stack.

hm... could elaborate a bit more here?

> I already did this on a previous project to select people in a corporate 
> directory containing about 6000 entries. The user can type in a few 
> letters, and then the popup automatically displays the names starting 
> with these letters.

cool ...as a new type of widget?
--
Torsten


Re: Thoughts on Woody ...

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Reinhard Poetz wrote:

>After (nearly) finishing a project where we implemented our own little
>forms frameworks (... we had already started when Woody became part of
>Cocoon) I want to share some ideas with you.
>
>To be able to make a comparisons I dived into the current implementation
>of Woody. Now I can say that I'm really impressed by the architecture
>and I also like it very much *how* you did it.
>
>So here a few (random) thoughts what could be useful for Woody:
>
>Global widget definition repository 
>-----------------------------------
>
>Currently we have a strict binding between widget definition and the
>template where the widgets are instantiated:
>
>         1           :           1
>   +------------+         +------------+
>   |            |         |            |
>   |   widget-  |         |   widget-  |
>   |  defintion | ----->  |  instances |
>   |            |         |            |
>   |            |         |            |
>   +------------+         +------------+
> 
>This goes so far that all defined widgets must be instantiated in order
>to get no (hidden) errors during validation. This also means for
>applications that consist of more than one form you sooner or later have
>to define your widgets (e.g. an email address) as often as you
>instantiate them.
>

I think you misunderstand the exact role of the WoodyTransformer and the 
moment where instances are created.

If we make an analogy between forms and objects, we can consider a form 
definition as a class and a form instance as an object, instance of the 
forementioned class.

This instance is created in the controller part of the request 
processing (flowscript or action) and is made available to the view 
pipeline through a request attribute.

What the WoodyTransforme does is just asking to the widget instances 
referenced by the <wt:widget> elements to output their representation. 
It *does not* instanciate the widgets.

>I think we should decouple this behaviour into following:
>
>
>   +------------+ 
>   |            | 
>   |   global   |
>   |   widget   |\
>   | repository | \
>   |            |  \
>   +------------+   \use
>         |           \
>         | ext        \
>         V             \
>   +------------+       \ +------------+
>   |            |         |            |
>   |   widget-  |  use    |   widget-  |
>   |  defintion | ------- |  instances |
>   |            |         |            |
>   |            |         |            |
>   +------------+         +------------+
>
>
>The global widget repository contains widgets that can be reused in all
>forms within your Cocoon installation. I also think that it could be
>possible to extend global widget defintions:
>
>  <wd:field id="glEmail" required="true">
>    <wd:datatype base="string">
>      <wd:validation>
>        <wd:email/>
>      </wd:validation>
>    </wd:datatype>
>  </wd:field>
>
>  <wd:field id="supplierEmail" extends="glEmail">
>    <wd:label>Supplier's email address:</wd:label>
>  </wd:field>
>
>  <wd:field id="customerEmail" extends="glEmail">
>    <wd:label>Customer's email address:</wd:label>
>  </wd:field>
>

I proposed to introduce a datatype dictionary to factorize common type 
definition (along with their validators and selection-list). This would 
turn your example into something like:

<wd:datatype id="email" base="string">
  <wd:validation>
    <wd:email/>
  </wd:validation>
</wd:datatype>

And then:
<wd:widget id="supplierEmail" required="true">
  <wd:datatype base="email"/>
</wd:widget>

>Multi page forms
>----------------
>
>We have already discussed this several times on the dev-list and at the
>GetTogether in Gent. IIUC Thorsten, Bruno and I agreed that we don't
>like some kind of a "phases" concept because everything you need can be
>found at the template and why should you declare things twice. If you
>think of dynamic forms (e.g. wheter a widget is show depends on the
>rights of the user) you also come into troubles because your phases will
>have to become dynamic too!
>
>As mentioned the list of the required widgets is already known because
>the template transformer instantiates all widgets. But there is a
>problem (or at least I'm not sure how to solve it) with this approach:
>The template transformer is the last step before a new continuation is
>created.
>

Nope. The continuation is created in the controller, before the view 
processing starts.

>So it would be possible to save a list of all required widgets.
>That's fine. The problem is that this list has to be connected to a
>certain continuation because otherwise you would get serious troubles if
>the user clones the window. OTOH if we save the list of the required
>widgets with the continuation it can become expensive from a memory POV,
>can't it?
>
>Are there other thougts how to solve the multi page forms problem? 
>Sylvain, you mentioned at the end of your presentation something at the
>GT Hackaton but I can't remember. Could you help us (me)?
>

What I mentioned was the need for a generic flowscript wizard library, 
that could allow to define "backtrack points" in the list of ancestors 
of the current continuation.

The idea is to have a Wizard class that provides two methods:
- markStep(): mark a step in the wizard. A step is a location in the 
flowscript where we can go back. We may eventually want to name step to 
allow going back to directly to a step that's not the immediate previous 
one.
- handleBack(): if the "wizard-back" button was clicked, restore the 
previous continuation in the step stack.

Example usage (notice that the second page depends on a value input on 
the first one):

function myWizard() {
  var wizard = new Wizard();
  // register the current execution location as a backtrack point
  wizard.markStep();
  cocoon.sendPageAndWait("first-page.html");
  var value = cocoon.request.getParameter("value");
  wizard.markStep();
  if (value == "foo") {
    cocoon.sendPageAndWait("foo-page.html");
    wizard.handleBack();
  } else {
    cocoon.sendPageAndWait("bar-page.html");
    wizard.handleBack();
  }
  wizard.markStep();
  cocoon.sendPageAndWait("third-page.html");
  wizard.handleBack();
  cocoon.sendPage("finished.html");
}

A real application would of course extract form data afer each page and 
use it before sending "finished.html".

>Lookup values
>-------------
>
>We already have some helpers to make it easy to enter correct data into
>your fields. One thing missing is the possibility to lookup values.
>Suppose you have a field "country". One possibility would be to a drop
>down field the other possibility a usual input field with an icon on its
>right side. If you click on this icon another window opens (inline like
>in Eclipse or a popup) and you get a list of all countries. You can
>select one and the value is copied into the main form. So what's the
>advantage compared to a selection list:
>
> * You don't need to load such a long list like all countries
>   in the world at form load time but then when the user
>   wants to fill in the value
>   (this makes no real difference for one field but if you have e.g.
>    10 fields containing so many possible values there is one, believe
>me!)
> * You can provide additional information: e.g. you have to
>   select a customer - you could show the address, the birthdate, ...
>   to make the choice for the user easier
> * You can structure your date  e.g. you can create
>   a tree where all countries can be found in a tree
> * You can provide help when a selection list is not
>   good enough. Think of a search form e.g. you can search in your
>   customers database for the right one and select it. The
>   selected customer is filled in the form.
> * You can fill in more than one field with one selection (think
>   of a row in a table --> with one selection the whole row
>   could be completed)
>

I already did this on a previous project to select people in a corporate 
directory containing about 6000 entries. The user can type in a few 
letters, and then the popup automatically displays the names starting 
with these letters.

Mmmh... can this be a particular implementation and rendering of a 
selection list where the possible values are available through an 
externally visible pipeline?

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }
Orixo, the opensource XML business alliance  -  http://www.orixo.com



RE: Thoughts on Woody ...

Posted by Reinhard Poetz <re...@apache.org>.
From: Torsten Curdt

> Reinhard Poetz wrote:
> 
> > After (nearly) finishing a project where we implemented our 
> own little 
> > forms frameworks (... we had already started when Woody 
> became part of
> > Cocoon) I want to share some ideas with you.
> 
> ..another one ;)

I hope many other follow us!
Beside blocks Cocoon forms is the next big thing! Whenever I talk about
Cocoon I nearly always get questions on form handling ...

> 
> <snip/
> 
> > The global widget repository contains widgets that can be reused in 
> > all forms within your Cocoon installation. I also think 
> that it could 
> > be possible to extend global widget defintions:
> > 
> >   <wd:field id="glEmail" required="true">
> >     <wd:datatype base="string">
> >       <wd:validation>
> >         <wd:email/>
> >       </wd:validation>
> >     </wd:datatype>
> >   </wd:field>
> > 
> >   <wd:field id="supplierEmail" extends="glEmail">
> >     <wd:label>Supplier's email address:</wd:label>
> >   </wd:field>
> > 
> >   <wd:field id="customerEmail" extends="glEmail">
> >     <wd:label>Customer's email address:</wd:label>
> >   </wd:field>
> 
> I think this sounds like a good idea

Bruno, what do you think?

> 
> > We have already discussed this several times on the dev-list and at 
> > the GetTogether in Gent. IIUC Thorsten, Bruno and I agreed that we 
> > don't
> 
> please note: Torsten - no "h" ;)

sorry for this :-(

> 
> > like some kind of a "phases" concept because everything you 
> need can 
> > be found at the template and why should you declare things 
> twice. If 
> > you think of dynamic forms (e.g. wheter a widget is show depends on 
> > the rights of the user) you also come into troubles because your 
> > phases will have to become dynamic too!
> 
> yes, we are on the same page here. phases are bad from a SOC 
> point of view.
> 
> > As mentioned the list of the required widgets is already 
> known because 
> > the template transformer instantiates all widgets. But there is a 
> > problem (or at least I'm not sure how to solve it) with 
> this approach: 
> > The template transformer is the last step before a new 
> continuation is 
> > created. So it would be possible to save a list of all required 
> > widgets. That's fine. The problem is that this list has to be 
> > connected to a certain continuation because otherwise you would get 
> > serious troubles if the user clones the window. OTOH if we save the 
> > list of the required widgets with the continuation it can become 
> > expensive from a memory POV, can't it?
> 
> hm... hard to say... it would definitly increase the size of a 
> continuation quite a bit!
> 
> > Are there other thougts how to solve the multi page forms problem?
> > Sylvain, you mentioned at the end of your presentation 
> something at the
> > GT Hackaton but I can't remember. Could you help us (me)?
> 
> Sylvain has made a valid point at the GT. The flow might want 
> to decide which form is to be shown next

yes, that's definitly the responsibility of the flow

>  - which makes a 
> general definition of a multipage form quite complicated.

currently it is difficult because when the form is validated *all*
widgets of the widget definition file are needed. if we remove this
restriction and use the instantiated widgets it should become easier ...

> 
> On the other hand the result of a multipage form is quite 
> often needed as a single form instance. 

this makes the writing of flow applications easier
and less ugly (otherwise you would have to do the
load/save for every page and at the end you have to
take care that you don't persist e.g. your bean
if there is a problem

> So *if* we split a 
> multipage forms into different individual forms we would need 
> an easy way to aggregate the data again.
> 
> But I don't really have a clue here yet...

Sylvain suggested to introduce variables that are bound to a
continuation. If we add the list off all widgets which have to be
validated we'll have the first use case ;-)

Are there any other thoughts on this?

> 
> <snip/>
> 
> >  * You don't need to load such a long list like all countries
> >    in the world at form load time but then when the user
> >    wants to fill in the value
> >    (this makes no real difference for one field but if you have e.g.
> >     10 fields containing so many possible values there is 
> one, believe
> > me!)
> 
> sounds like a good idea! (I feel your pain ;)
> one of our customers insisted to have a dropdrown list
> of up to 300 entries)

did we have the same customer? ;-)

Reinhard


Re: Thoughts on Woody ...

Posted by Torsten Curdt <tc...@vafer.org>.
Reinhard Poetz wrote:

> After (nearly) finishing a project where we implemented our own little
> forms frameworks (... we had already started when Woody became part of
> Cocoon) I want to share some ideas with you.

..another one ;)

<snip/

> The global widget repository contains widgets that can be reused in all
> forms within your Cocoon installation. I also think that it could be
> possible to extend global widget defintions:
> 
>   <wd:field id="glEmail" required="true">
>     <wd:datatype base="string">
>       <wd:validation>
>         <wd:email/>
>       </wd:validation>
>     </wd:datatype>
>   </wd:field>
> 
>   <wd:field id="supplierEmail" extends="glEmail">
>     <wd:label>Supplier's email address:</wd:label>
>   </wd:field>
> 
>   <wd:field id="customerEmail" extends="glEmail">
>     <wd:label>Customer's email address:</wd:label>
>   </wd:field>

I think this sounds like a good idea

> We have already discussed this several times on the dev-list and at the
> GetTogether in Gent. IIUC Thorsten, Bruno and I agreed that we don't

please note: Torsten - no "h" ;)

> like some kind of a "phases" concept because everything you need can be
> found at the template and why should you declare things twice. If you
> think of dynamic forms (e.g. wheter a widget is show depends on the
> rights of the user) you also come into troubles because your phases will
> have to become dynamic too!

yes, we are on the same page here. phases are bad from a SOC point
of view.

> As mentioned the list of the required widgets is already known because
> the template transformer instantiates all widgets. But there is a
> problem (or at least I'm not sure how to solve it) with this approach:
> The template transformer is the last step before a new continuation is
> created. So it would be possible to save a list of all required widgets.
> That's fine. The problem is that this list has to be connected to a
> certain continuation because otherwise you would get serious troubles if
> the user clones the window. OTOH if we save the list of the required
> widgets with the continuation it can become expensive from a memory POV,
> can't it?

hm... hard to say... it would definitly increase the size of a 
continuation quite a bit!

> Are there other thougts how to solve the multi page forms problem? 
> Sylvain, you mentioned at the end of your presentation something at the
> GT Hackaton but I can't remember. Could you help us (me)?

Sylvain has made a valid point at the GT. The flow might want
to decide which form is to be shown next - which makes a general
definition of a multipage form quite complicated.

On the other hand the result of a multipage form is quite often
needed as a single form instance. So *if* we split a multipage forms
into different individual forms we would need an easy way to
aggregate the data again.

But I don't really have a clue here yet...

<snip/>

>  * You don't need to load such a long list like all countries
>    in the world at form load time but then when the user
>    wants to fill in the value
>    (this makes no real difference for one field but if you have e.g.
>     10 fields containing so many possible values there is one, believe
> me!)

sounds like a good idea! (I feel your pain ;)
one of our customers insisted to have a dropdrown list
of up to 300 entries)
--
Torsten