You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by cm...@apache.org on 2012/05/23 18:03:01 UTC
git commit: allow outer forms to participate in the submit of nested
forms
Updated Branches:
refs/heads/wicket-1.5.x c572d4f1c -> 38d6c932a
allow outer forms to participate in the submit of nested forms
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/38d6c932
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/38d6c932
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/38d6c932
Branch: refs/heads/wicket-1.5.x
Commit: 38d6c932a5ab6bfae68a31e6944f4f9dc9f5a658
Parents: c572d4f
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Authored: Thu Dec 15 11:31:29 2011 +0100
Committer: Carl-Eric Menzel <cm...@wicketbuch.de>
Committed: Wed May 23 17:40:23 2012 +0200
----------------------------------------------------------------------
.../org/apache/wicket/markup/html/form/Form.java | 109 +++++++--
.../html/form/NestedFormSubmitTest$TestPage.html | 13 +
.../markup/html/form/NestedFormSubmitTest.java | 187 +++++++++++++++
3 files changed, 287 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/38d6c932/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
index d29f3af..8ad2571 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
@@ -749,14 +749,9 @@ public class Form<T> extends WebMarkupContainer implements IFormSubmitListener
}
else
{
- // this is the root form
- Form<?> formToProcess = this;
-
- // find out whether it was a nested form that was submitted
- if (submitter != null)
- {
- formToProcess = submitter.getForm();
- }
+ // the submit request might be for one of the nested forms, so let's
+ // find the right one:
+ final Form<?> formToProcess = findFormToProcess(submitter);
// process the form for this request
formToProcess.process(submitter);
@@ -771,6 +766,88 @@ public class Form<T> extends WebMarkupContainer implements IFormSubmitListener
}
}
+ /**
+ * This method finds the correct form that should be processed based on the submitting component
+ * (if there is one) and correctly handles nested forms by also looking at
+ * {@link #wantSubmitOnNestedFormSubmit()} throughout the form hierarchy. The form that needs to
+ * be processed is:
+ * <ul>
+ * <li>if there is no submitting component (i.e. a "default submit"): this form.</li>
+ * <li>if only one form exists (this): this form.</li>
+ * <li>if nested forms exist:
+ * <ul>
+ * <li>if the submitting component points at the root form: the root form</li>
+ * <li>if the submitting component points at a nested form:
+ * <ul>
+ * <li>starting at that nested form, the outermost form that returns true for
+ * {@link #wantSubmitOnNestedFormSubmit()}</li>
+ * <li>if no outer form returns true for that, the nested form is returned.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @param submitter
+ * The submitting component, if any. May be null.
+ * @return The form that needs to be processed.
+ */
+ private Form<?> findFormToProcess(IFormSubmitter submitter)
+ {
+ if (submitter == null)
+ {
+ // no submitting component => default form submit => so *this* is the
+ // form to process
+ return this;
+ }
+ else
+ {
+ // some button submitted this request, this is the form it belongs to:
+ final Form<?> targetedForm = submitter.getForm();
+ if (targetedForm == null)
+ {
+ throw new IllegalStateException(
+ "submitting component must not return 'null' on getForm()");
+ }
+
+ final Form<?> rootForm = getRootForm();
+ if (targetedForm == rootForm)
+ {
+ // the submitting component points at the root form => so let's just go with
+ // root, everything else will be submitted with it anyway.
+ return rootForm;
+ }
+ else
+ {
+ // a different form was targeted. let's find the outermost form that wants to be
+ // submitted.
+ Form<?> formThatWantsToBeSubmitted = targetedForm;
+ Form<?> current = targetedForm.findParent(Form.class);
+ while (current != null)
+ {
+ if (current.wantSubmitOnNestedFormSubmit())
+ {
+ formThatWantsToBeSubmitted = current;
+ }
+ current = current.findParent(Form.class);
+ }
+ return formThatWantsToBeSubmitted;
+ }
+ }
+ }
+
+ /**
+ * Whether this form wants to be submitted too if a nested form is submitted. By default, this
+ * is false, so when a nested form is submitted, this form will <em>not</em> be submitted. If
+ * this method is overridden to return true, this form <em>will</em> be submitted.
+ *
+ * @return Whether this form wants to be submitted too if a nested form is submitted.
+ */
+ public boolean wantSubmitOnNestedFormSubmit()
+ {
+ return false;
+ }
+
/**
* Process the form. Though you can override this method to provide your own algorithm, it is
@@ -1133,27 +1210,15 @@ public class Form<T> extends WebMarkupContainer implements IFormSubmitListener
*/
protected void delegateSubmit(IFormSubmitter submittingComponent)
{
- final Form<?> processingForm;
+ final Form<?> processingForm = findFormToProcess(submittingComponent);
+
// process submitting component (if specified)
if (submittingComponent != null)
{
- // use form of submitting component for processing
- processingForm = submittingComponent.getForm();
-
- if (processingForm == null)
- {
- throw new IllegalStateException(
- "submitting component must not return 'null' on getForm()");
- }
-
// invoke submit on component
submittingComponent.onSubmit();
}
- else
- {
- processingForm = this;
- }
// invoke Form#onSubmit(..) going from innermost to outermost
Visits.visitPostOrder(processingForm, new IVisitor<Form<?>, Void>()
http://git-wip-us.apache.org/repos/asf/wicket/blob/38d6c932/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest$TestPage.html
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest$TestPage.html b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest$TestPage.html
new file mode 100644
index 0000000..4293820
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest$TestPage.html
@@ -0,0 +1,13 @@
+<html>
+<body>
+<form wicket:id="outer">
+<input type="submit" wicket:id="submit"/>
+<form wicket:id="middle">
+<input type="submit" wicket:id="submit"/>
+<form wicket:id="inner">
+<input type="submit" wicket:id="submit"/>
+</form>
+</form>
+</form>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/wicket/blob/38d6c932/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest.java
new file mode 100644
index 0000000..c325f1f
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/NestedFormSubmitTest.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.markup.html.form;
+
+import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NestedFormSubmitTest extends WicketTestCase
+{
+
+ public class TestForm<S> extends Form<S>
+ {
+ private final IModel<Boolean> submitted;
+ private final Button submit;
+ private final boolean wantInclusion;
+
+ TestForm(String id, IModel<Boolean> submitted, boolean wantInclusion)
+ {
+ super(id);
+ this.submitted = submitted;
+ this.wantInclusion = wantInclusion;
+ submit = new Button("submit");
+ add(submit);
+ }
+
+ @Override
+ protected void onSubmit()
+ {
+ super.onSubmit();
+ submitted.setObject(Boolean.TRUE);
+ }
+
+ @Override
+ public boolean wantSubmitOnNestedFormSubmit()
+ {
+ return wantInclusion;
+ }
+ }
+
+ public class TestPage extends WebPage
+ {
+ private final TestForm outer;
+ private final TestForm middle;
+ private final TestForm inner;
+
+ public TestPage(IModel<Boolean> submittedOuter, boolean outerWantsInclusion,
+ IModel<Boolean> submittedMiddle, boolean middleWantsInclusion,
+ IModel<Boolean> submittedInner)
+ {
+ outer = new TestForm("outer", submittedOuter, outerWantsInclusion);
+ this.add(outer);
+ middle = new TestForm("middle", submittedMiddle, middleWantsInclusion);
+ outer.add(middle);
+ inner = new TestForm("inner", submittedInner, false);
+ middle.add(inner);
+ }
+ }
+
+ private Model<Boolean> submittedOuter;
+ private Model<Boolean> submittedMiddle;
+ private Model<Boolean> submittedInner;
+ private TestPage page;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ submittedOuter = Model.of(false);
+ submittedMiddle = Model.of(false);
+ submittedInner = Model.of(false);
+ }
+
+ @After
+ public void tearDown() throws Exception
+ {
+ submittedInner.setObject(false);
+ submittedMiddle.setObject(false);
+ submittedOuter.setObject(false);
+ }
+
+ @Test
+ public void testDefaultOuterSubmitShouldSubmitAll() throws Exception
+ {
+ startPage(false, false);
+ assertFormSubmitOuter(true, true, true);
+ }
+
+ private void assertFormSubmitOuter(boolean expectSubmittedOuter, boolean expectSubmittedMiddle,
+ boolean expectSubmittedInner)
+ {
+ FormTester form = tester.newFormTester(page.outer.getPageRelativePath());
+ form.submit("submit");
+ assertFormsAreSubmitted(expectSubmittedOuter, expectSubmittedMiddle, expectSubmittedInner);
+ }
+
+ private void assertFormSubmitMiddle(boolean expectSubmittedOuter,
+ boolean expectSubmittedMiddle, boolean expectSubmittedInner)
+ {
+ FormTester form = tester.newFormTester(page.outer.getPageRelativePath());
+ form.submit("middle:submit");
+ assertFormsAreSubmitted(expectSubmittedOuter, expectSubmittedMiddle, expectSubmittedInner);
+ }
+
+ private void assertFormSubmitInner(boolean expectSubmittedOuter, boolean expectSubmittedMiddle,
+ boolean expectSubmittedInner)
+ {
+ FormTester form = tester.newFormTester(page.outer.getPageRelativePath());
+ form.submit("middle:inner:submit");
+ assertFormsAreSubmitted(expectSubmittedOuter, expectSubmittedMiddle, expectSubmittedInner);
+ }
+
+ private void assertFormsAreSubmitted(boolean expectSubmittedOuter,
+ boolean expectSubmittedMiddle, boolean expectSubmittedInner)
+ {
+ assertEquals("outer", expectSubmittedOuter, submittedOuter.getObject().booleanValue());
+ assertEquals("middle", expectSubmittedMiddle, submittedMiddle.getObject().booleanValue());
+ assertEquals("inner", expectSubmittedInner, submittedInner.getObject().booleanValue());
+ }
+
+ @Test
+ public void testDefaultMiddleSubmitShouldSubmitMiddleAndInner() throws Exception
+ {
+ startPage(false, false);
+ assertFormSubmitMiddle(false, true, true);
+ }
+
+ @Test
+ public void testDefaultInnerSubmitShouldSubmitOnlyInner() throws Exception
+ {
+ startPage(false, false);
+ assertFormSubmitInner(false, false, true);
+ }
+
+ @Test
+ public void testWithOuterInclusionOuterIsSubmittedOnMiddleSubmit() throws Exception
+ {
+ startPage(true, false);
+ assertFormSubmitMiddle(true, true, true);
+ }
+
+ @Test
+ public void testWithOuterInclusionOuterIsSubmittedOnInnerSubmit() throws Exception
+ {
+ startPage(true, false);
+ assertFormSubmitInner(true, true, true);
+ }
+
+ @Test
+ public void testWithMiddleInclusionMiddleIsSubmittedOnInnerSubmit() throws Exception
+ {
+ startPage(false, true);
+ assertFormSubmitInner(false, true, true);
+ }
+
+ @Test
+ public void testWithMiddleAndOuterInclusionMiddleAndOuterIsSubmittedOnInnerSubmit()
+ throws Exception
+ {
+ startPage(true, true);
+ assertFormSubmitInner(true, true, true);
+ }
+
+ private void startPage(boolean outerWantsInclusion, boolean middleWantsInclusion)
+ {
+ page = (TestPage)tester.startPage(new TestPage(submittedOuter, outerWantsInclusion,
+ submittedMiddle, middleWantsInclusion, submittedInner));
+ }
+}