Repository: wicket Updated Branches: refs/heads/grails-maven-integration 721927ef3 -> d1fc97313
Added chapter on component queuing from Igor's blog post Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/d1fc9731 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/d1fc9731 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/d1fc9731 Branch: refs/heads/grails-maven-integration Commit: d1fc97313f600e8e9ba2c4ef2e3127aff8c07f35 Parents: 721927e Author: Andrea Del Bene <[email protected]> Authored: Tue Mar 31 21:59:39 2015 +0200 Committer: Andrea Del Bene <[email protected]> Committed: Tue Mar 31 21:59:39 2015 +0200 ---------------------------------------------------------------------- wicket-user-guide/grails-app/conf/Config.groovy | 2 +- .../src/docs/guide/componentQueueing.gdoc | 2 + .../componentQueueing/componentQueueing_1.gdoc | 159 +++++++++++++++++++ .../componentQueueing/componentQueueing_2.gdoc | 23 +++ .../componentQueueing/componentQueueing_3.gdoc | 5 + .../componentQueueing/componentQueueing_4.gdoc | 31 ++++ .../componentQueueing/componentQueueing_5.gdoc | 1 + wicket-user-guide/src/docs/guide/toc.yml | 7 + 8 files changed, 229 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/grails-app/conf/Config.groovy ---------------------------------------------------------------------- diff --git a/wicket-user-guide/grails-app/conf/Config.groovy b/wicket-user-guide/grails-app/conf/Config.groovy index fd46c0e..d49fb22 100644 --- a/wicket-user-guide/grails-app/conf/Config.groovy +++ b/wicket-user-guide/grails-app/conf/Config.groovy @@ -95,7 +95,7 @@ log4j = { grails.doc.title = "Apache Wicket User Guide" grails.doc.version = "7.0" grails.doc.subtitle = "Free Online Guide for Apache Wicket framework" -grails.doc.authors = "Andrea Del Bene, Martin Grigorov, Carsten Hufe, Christian Kroemer, Daniel Bartl, Paul BorÈ, Tobias Soloschenko" +grails.doc.authors = "Andrea Del Bene, Martin Grigorov, Carsten Hufe, Christian Kroemer, Daniel Bartl, Paul BorÈ, Tobias Soloschenko, Igor Vaynberg" grails.doc.images = new File("src/docs/img") grails.doc.css = new File("src/docs/css") grails.doc.logo = """<a href="/" target="_blank"><img height="80px" src="http://wicket.apache.org/guide/img/apache-wicket.png"/></a>""" http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/componentQueueing.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/componentQueueing.gdoc b/wicket-user-guide/src/docs/guide/componentQueueing.gdoc new file mode 100644 index 0000000..7f3669b --- /dev/null +++ b/wicket-user-guide/src/docs/guide/componentQueueing.gdoc @@ -0,0 +1,2 @@ +So far to build component hierarchy we have explicitly added each component and container in accordance with the corresponding markup. This necessary step can involve repetitive and boring code which must be change every time we decide to change markup hierarchy. +Component queueing is a new feature in Wicket 7 that solves this problem allowing Wicket to build component hierarchy in Java automatically making your code simpler and more maintainable. This chapter should serve as a short introduction to what Component Queueing is and what problems it is trying to solve. http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_1.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_1.gdoc b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_1.gdoc new file mode 100644 index 0000000..62e3a8f --- /dev/null +++ b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_1.gdoc @@ -0,0 +1,159 @@ +With Wicket as developers we use to define the hierarchy of components in the markup templates: + +{code:html} +<form wicket:id='customer'> + <input wicket:id='first' type='text'/> + <input wicket:id='last' type='text'/> + <div wicket:id="child"> + <input wicket:id='first' type='text'/> + <input wicket:id='last' type='text'/> + <input wicket:id='dob' type='date'/> + </div> +</form> +{code} + +and then we repeat the same hierarchy in Java code: + +{code} +Form form=new Form("customer"); +add(form); + +form.add(new TextField("first")); +form.add(new TextField("last")); + +WebMarkupContainer child=new WebMarkupContainer("child"); +form.add(child); + +child.add(new TextField("first")); +child.add(new TextField("last")); +child.add(new TextField("dob")); +{code} + +The need for the hierarchy in the markup is obvious, it is simply how the markup works. On the Java side of things it may not be immediately apparent. After all, why can we not write the code like this? + +{code} +add(new Form("customer")); +add(new TextField("first")); +add(new TextField("last")); +WebMarkupContainer child=new WebMarkupContainer("child"); +add(child); +add(new TextField("first")); +add(new TextField("last")); +add(new TextField("dob")); +{code} + +There are a couple of reasons: + +* Ambiguities that happen with duplicate ids +* Inheriting state from parent to child + +We will examine these below. + +h3. Markup Id Ambiguities + +In the example above we have a form that collects the name of a customer along with the name of their child and the childâs date of birth. We mapped the name of the customer and child to form components with wicket ids @first@ and @last@. If we were to add all the components to the same parent we would get an error because we cannot have two components with the same wicket id under the same parent (two components with id @first@ and two with id @last@). +Without hierarchy in Java we would have to make sure that all wicket ids in a markup file are unique, no small feat in a non-trivial page or panel. But, with hierarchy on the Java side we just have to make sure that no parent has two children with the same id, which is trivial. + +h3. Inheriting State From Parents + +Suppose we wanted to hide form fields related to the child in the example above when certain conditions are met. Without hierarchy we would have to modify the @first@, @last@, and @dob@ fields to implement the visibility check. Worse, whenever we would add a new child related field we would have to remember to implement the same check; this is a maintenance headache. With hierarchy this is easy, simply hide the parent container and all children will be hidden as well â the code lives in one place and is automatically inherited by all descendant components. Thus, hierarchy on the Java side allows us to write succinct and maintainable code by making use of the parent-child relationship of components. + +h3. Pain Points of the Java-Side Hierarchy + +While undeniably useful, the Java-side hierarchy can be a pain to maintain. It is very common to get requests to change things because the designer needs to wrap some components in a @div@ with a dynamic style or class attribute. Essentially we want to go from: + +{code:html} +<form wicket:id='customer'> + <input wicket:id='first' type='text'/> + <input wicket:id='last' type='text'/> +{code} + +To: + +{code} +<form wicket:id='customer'> + <div wicket:id='container'> + <input wicket:id='first' type='text'/> + <input wicket:id='last' type='text'/> + </div> +{code} + +Seems simple enough, but to do so we need to create the new container, find the code that adds all the components that have to be relocated and change it to add to the new container instead. This code: + +{code} +Form form=new Form("customer"); +add(form); + +form.add(new TextField("first")); +form.add(new TextField("last")); +{code} + +Will become: + +{code} +Form form=new Form("customer"); +add(form); + +WebMarkupContainer container=new WebMarkupContainer("container"); +form.add(container); + +container.add(new TextField("first")); +container.add(new TextField("last")); +{code} + +Another common change is to tweak the nesting of markup tags. This is something a designer should be able to do on their own if the change is purely visual, but cannot if it means Wicket components will change parents. + +In large pages with a lot of components these kinds of simple changes tend to cause a lot of annoyance for the developers. + +h3. Component Queueing To The Rescue + +The idea behind component queueing is simple: instead of adding components to their parents directly, the developer can queue them in any ancestor and have Wicket automatically âdequeueâ them to the correct parent using the hierarchy defined in the markup. This will give us the best of both worlds: the developer only has to define the hierarchy once in markup, and have it automatically constructed in Java land. + +That means we can go from code like this: + +{code} +Form form=new Form("customer"); +add(form); + +form.add(new TextField("first")); +form.add(new TextField("last")); + +WebMarkupContainer child=new WebMarkupContainer("child"); +form.add(child); + +child.add(new TextField("first")); +child.add(new TextField("last")); +child.add(new TextField("dob")); +{code} + +To code like this: + +{code} +queue(new Form("customer")); +queue(new TextField("first")); +queue(new TextField("last")); + +WebMarkupContainer child=new WebMarkupContainer("child"); +queue(child); +child.queue(new TextField("first")); +child.queue(new TextField("last")); +child.queue(new TextField("dob")); +{code} + +{note} +Note that we had to queue childâs @first@ and @last@ name fields to the @child@ container in order to disambiguate their wicket ids. +{note} + + +The code above does not look shorter or that much different, so where is the advantage? + +Suppose our designer wants us to wrap the customerâs first and last name fields with a @div@ that changes its styling based on some condition. We saw how to do that above, we had to create a container and then reparent the two @TextField@ components into it. Using queueing we can skip the second step, all we have to do is add the following line: + +{code} +queue(new WebMarkupContainer("container")); +{code} + +When dequeueing Wicket will automatically reparent the first and last name fields into the container for us. + +If the designer later wanted to move the first name field out of the @div@ we just added for them they could do it all by themselves without requiring any changes in the Java code. Wicket would dequeue the first name field into the form and the last name field into the container div. + http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_2.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_2.gdoc b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_2.gdoc new file mode 100644 index 0000000..6f0f91d --- /dev/null +++ b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_2.gdoc @@ -0,0 +1,23 @@ +Auto components, such as Enclosure, are a very useful feature of Wicket, but they have always been a pain to implement and use. + +Suppose we have: + +{code:xml} +<wicket:enclosure childId="first"> + <input wicket:id="first" type="text"/> + <input wicket:id="last" type="text"/> +</wicket:enclosure> +{code} + +Together with: + +{code} +add(new TextField("first").setRequired(true).setVisible(false)); +add(new TextField("last").setRequired(true)); +{code} + +When developing auto components the biggest pain point is in figuring out who the children of the auto component are. In the markup above the enclosure is a parent of the text fields, but in Java it would be a sibling because auto components do not modify the java-side hierarchy. So when the Enclosure is looking for its children it has to parse the markup to figure out what they are. This is not a trivial task. + +Because auto components do not insert themselves properly into the Java hierarchy they are also hard for users to use. For example, the documentation of Enclosure does not recommend it to be used to wrap form components like we have above. When the page renders the enclosure will be hidden because @first@ component is not visible. However, when we submit the form, @last@ component will raise a required error. This is because @last@ is not made a child of the hidden enclosure and therefore does not know its hidden â so it will try to process its input and raise the error. + +Had we used @queue@ instead of @add@ in the code above, everything would work as expected. As part of Queueing implementation Wicket will properly insert auto components into the Java hierarchy. Furthermore, auto components will remain in the hierarchy instead of being added before render and removed afterwords. This is a big improvement because developers will no longer have to parse markup to find the children components â since children will be added to the enclosure by the dequeueing. Likewise, user restrictions are removed as well; the code above would work as expected. http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_3.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_3.gdoc b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_3.gdoc new file mode 100644 index 0000000..d88c237 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_3.gdoc @@ -0,0 +1,5 @@ +Once you call @queue()@, when are the components dequeued into the page hierarchy? When is it safe to call @getParent()@ or use methods such as @isVisibleInHierarchy()@ which rely on componentâs position in hierarchy? + +The components are dequeued as soon as a path is available from @Page@ to the component they are queued into. The dequeue operation needs access to markup which is only available once the Page is known (because the @Page@ object controls the extension of the markup). + +If the @Page@ is known at the time of the @queue()@ call (eg if its called inside @onInitialize()@) the components are dequeued before @queue()@ returns. http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_4.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_4.gdoc b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_4.gdoc new file mode 100644 index 0000000..6a60d41 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_4.gdoc @@ -0,0 +1,31 @@ +h3. Ancestors + +Suppose on a user profile panel we have the following code: + +{code} +queue(new Label("first")); +queue(new Label("last")); + +WebMarkupContainer secure=new WebMarkupContainer("secure") { + void onConfigure() { + super.onConfigure(); + setVisible(isViewingOwnProfile()); + } +}; + +queue(secure); +secure.queue(new Label("creditCardNumber")); +secure.queue(new Label("creditCardExpiry")); +{code} + +What is to prevent someone with access to markup from moving the @creditCardNumber@ label out of the @secure@ div, causing a big security problem for the site? + +Wicket will only dequeue components either to the component they are queued to or any of its descendants. + +In the code above this is the reason why we queued the @creditCardNumber@ label into the @secure@ container. That means it can only be dequeued into the @secure@ containerâs hierarchy. + +This restriction allows developers to enforce certain parent-child relationships in their code. + +h3. Regions + +Dequeuing of components will not happen across components that implement the @org.apache.wicket.IQueueRegion@ interface. This interface is implemented by all components that provide their own markup such as: @Page@, @Panel@, @Border@, @Fragment@. This is done so that if both a page and panel contain a component with id @foo@ the one queued into the page will not be dequeued into the panel. This minimizes confusion and debugging time. The rule so far is that if a component provides its own markup only components queued inside it will be dequeued into it. http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_5.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_5.gdoc b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_5.gdoc new file mode 100644 index 0000000..ba8f0fd --- /dev/null +++ b/wicket-user-guide/src/docs/guide/componentQueueing/componentQueueing_5.gdoc @@ -0,0 +1 @@ +Component queueing is a new and improved way of creating the component hierarchy in Wicket 7. By having to define the hierarchy only once in markup we can make the Java-side code simpler and more maintainable. http://git-wip-us.apache.org/repos/asf/wicket/blob/d1fc9731/wicket-user-guide/src/docs/guide/toc.yml ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/toc.yml b/wicket-user-guide/src/docs/guide/toc.yml index c67911d..b0489c1 100644 --- a/wicket-user-guide/src/docs/guide/toc.yml +++ b/wicket-user-guide/src/docs/guide/toc.yml @@ -99,6 +99,13 @@ repeaters: repeaters_3: The RefreshingView Component repeaters_4: Pageable repeaters repeaters_5: Summary +componentQueueing: + title: Component queueing + componentQueueing_1: Markup hierarchy and code + componentQueueing_2: Improved auto components + componentQueueing_3: When are components dequeued? + componentQueueing_4: Restrictions of queueing + componentQueueing_5: Summary i18n: title: Internationalization with Wicket i18n_1: Localization
