You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by kn...@apache.org on 2006/10/11 10:20:38 UTC
svn commit: r462728 - in /incubator/wicket/trunk/wicket/src:
main/java/wicket/ajax/form/ main/java/wicket/markup/html/form/
test/java/wicket/markup/html/form/
Author: knopp
Date: Wed Oct 11 01:20:37 2006
New Revision: 462728
URL: http://svn.apache.org/viewvc?view=rev&rev=462728
Log:
Initial version of nested forms support. Still have to add support for nested multipart forms.
Modified:
incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/form/AjaxFormSubmitBehavior.java
incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/AbstractSubmitLink.java
incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Button.java
incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Form.java
incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/SubmitLink.java
incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ButtonTest.java
Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/form/AjaxFormSubmitBehavior.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/form/AjaxFormSubmitBehavior.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/form/AjaxFormSubmitBehavior.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/form/AjaxFormSubmitBehavior.java Wed Oct 11 01:20:37 2006
@@ -21,9 +21,7 @@
import wicket.ajax.AjaxEventBehavior;
import wicket.ajax.AjaxRequestTarget;
import wicket.ajax.ClientEvent;
-import wicket.markup.html.form.Button;
import wicket.markup.html.form.Form;
-import wicket.markup.html.form.FormComponent;
import wicket.markup.html.form.IFormSubmittingComponent;
import wicket.util.string.AppendingStringBuffer;
@@ -68,6 +66,9 @@
@Override
protected CharSequence getEventHandler()
{
+ // get the form we are really going to submit
+ final Form form = this.form.getRootForm();
+
final String formId = form.getMarkupId();
final CharSequence url = getCallbackUrl();
@@ -90,6 +91,9 @@
@Override
protected void onEvent(AjaxRequestTarget target)
{
+ // get the form we are really going to submit
+ final Form form = this.form.getRootForm();
+
form.onFormSubmitted();
if (!form.hasError())
{
Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/AbstractSubmitLink.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/AbstractSubmitLink.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/AbstractSubmitLink.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/AbstractSubmitLink.java Wed Oct 11 01:20:37 2006
@@ -163,7 +163,7 @@
*/
public String getInputName()
{
- // TODO: This is a copy & paste from the Button class.
+ // TODO: This is a copy & paste from the FormComponent class.
String id = getId();
final PrependingStringBuffer inputName = new PrependingStringBuffer(id.length());
Component c = this;
@@ -171,7 +171,7 @@
{
inputName.prepend(id);
c = c.getParent();
- if (c == null || c instanceof Form || c instanceof Page)
+ if (c == null || (c instanceof Form && ((Form)c).isRootForm()) || c instanceof Page)
{
break;
}
Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Button.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Button.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Button.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Button.java Wed Oct 11 01:20:37 2006
@@ -310,23 +310,35 @@
protected final String getTriggerJavaScript()
{
if (getForm() != null) {
+ // find the root form - the one we are really going to submit
+ Form root = getForm().getRootForm();
StringBuffer sb = new StringBuffer(100);
sb.append("var e=document.getElementById('");
- sb.append(getForm().getHiddenFieldId(Form.HIDDEN_FIELD_FAKE_SUBMIT));
+ sb.append(root.getHiddenFieldId(Form.HIDDEN_FIELD_FAKE_SUBMIT));
sb.append("'); e.name=\'");
sb.append(getInputName());
sb.append("'; e.value='x';");
sb.append("var f=document.getElementById('");
- sb.append(getForm().getMarkupId());
+ sb.append(root.getMarkupId());
sb.append("');");
if (shouldInvokeJavascriptFormOnsubmit())
{
- sb.append("if (f.onsubmit != undefined) { if (f.onsubmit()==false) return false; }");
+ if (getForm() != root)
+ {
+ sb.append("var ff=document.getElementById('");
+ sb.append(getForm().getMarkupId());
+ sb.append("');");
+ }
+ else
+ {
+ sb.append("var ff=f;");
+ }
+ sb.append("if (ff.onsubmit != undefined) { if (ff.onsubmit()==false) return false; }");
}
sb.append("f.submit();e.value='';e.name='';return false;");
return sb.toString();
} else {
return null;
- }
+ }
}
}
Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Form.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Form.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Form.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/Form.java Wed Oct 11 01:20:37 2006
@@ -116,6 +116,18 @@
* To get form components to persist their values for users via cookies, simply
* call setPersistent(true) on the form component.
* </p>
+ * <p>
+ * Forms can be nested. You can put a form in another form. Since HTML doesn't
+ * allow nested <form> tags, the inner forms will be rendered using
+ * the <div> tag. You have to submit the inner forms using explicit
+ * components (like Button or SubmitLink), you can't rely on implicit submit
+ * behavior (by using just <input type="submit"> that is not attached
+ * to a component).
+ * </p>
+ * <p>
+ * When a nested form is submitted, the user entered values in outer (parent)
+ * forms are preserved and only the fields in the submitted form are validated.
+ * </b>
*
* @param <T>
* Type of model object this component holds
@@ -255,13 +267,25 @@
* 'default' button in a form is ill defined in the standards, and of course
* IE has it's own way of doing things.
* </p>
+ * <p>
+ * There can be only one default button per form hierarchy. So if you want
+ * to get the default button on a nested form, it will actually delegate the
+ * call to root form.
+ * </b>
*
* @return The button to set as the default button, or null when you want to
* 'unset' any previously set default button
*/
public final Button getDefaultButton()
{
- return defaultButton;
+ if (isRootForm())
+ {
+ return defaultButton;
+ }
+ else
+ {
+ return getRootForm().getDefaultButton();
+ }
}
/**
@@ -339,8 +363,16 @@
}
else
{
+ // this is the root form
+ Form formToProcess = this;
+
+ // find out whether it was a nested form that was submitted
+ if (submittingButton != null)
+ {
+ formToProcess = submittingButton.getForm();
+ }
// process the form for this request
- if (process())
+ if (formToProcess.process())
{
// let clients handle further processing
delegateSubmit(submittingButton);
@@ -362,6 +394,18 @@
}
/**
+ * @see wicket.Component#internalOnAttach()
+ */
+ @Override
+ protected void internalOnAttach()
+ {
+ super.internalOnAttach();
+ setOutputMarkupId(true);
+
+ // TODO: MatejK - Handle multi part
+ }
+
+ /**
* @see wicket.Component#internalOnDetach()
*/
@Override
@@ -420,6 +464,11 @@
* 'default' button in a form is ill defined in the standards, and of course
* IE has it's own way of doing things.
* </p>
+ * <p>
+ * There can be only one default button per form hierarchy. So if you set
+ * default button on a nested form, it will actually delegate the call
+ * to root form.
+ * </b>
*
* @param button
* The button to set as the default button, or null when you want
@@ -427,7 +476,14 @@
*/
public final void setDefaultButton(Button button)
{
- this.defaultButton = button;
+ if (isRootForm())
+ {
+ this.defaultButton = button;
+ }
+ else
+ {
+ getRootForm().setDefaultButton(button);
+ }
}
/**
@@ -591,9 +647,9 @@
* </p>
*
* @param submittingComponent
- * the component that triggered this form processing, or null if the
- * processing was triggered by something else (like a non-Wicket
- * submit button or a javascript execution)
+ * the component that triggered this form processing, or null if
+ * the processing was triggered by something else (like a
+ * non-Wicket submit button or a javascript execution)
*/
protected void delegateSubmit(IFormSubmittingComponent submittingComponent)
{
@@ -602,10 +658,15 @@
if (submittingComponent != null)
{
submittingComponent.onSubmit();
+
+ // call onSubmit on the processed form
+ submittingComponent.getForm().onSubmit();
+ }
+ else
+ {
+ // No submitting button found
+ onSubmit();
}
-
- // Model was successfully updated with valid data
- onSubmit();
}
/**
@@ -625,7 +686,7 @@
final IFormSubmittingComponent submit = (IFormSubmittingComponent)component;
// Check for button-name or button-name.x request string
- if (submit.getForm() == Form.this
+ if (submit.getForm().getRootForm() == Form.this
&& (getRequest().getParameter(submit.getInputName()) != null || getRequest()
.getParameter(submit.getInputName() + ".x") != null))
{
@@ -758,21 +819,24 @@
@Override
protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag)
{
- String fs = getHiddenFieldId(HIDDEN_FIELD_FAKE_SUBMIT);
- getResponse().write(
- new AppendingStringBuffer(
- "\n<div style=\"display:none\"><input type=\"hidden\" name=\"").append(fs)
- .append("\" id=\"").append(fs).append("\"/>"));
- String ws = getHiddenFieldId(HIDDEN_FIELD_WICKET_STATE);
- getResponse().write(
- new AppendingStringBuffer("\n<input type=\"hidden\" name=\"wicketState\" id=\"")
- .append(ws).append("\"/></div>"));
-
- // if a default button was set, handle the rendering of that
- if (defaultButton != null && defaultButton.isVisibleInHierarchy()
- && defaultButton.isEnabled())
+ if (isRootForm())
{
- appendDefaultButtonField(markupStream, openTag);
+ String fs = getHiddenFieldId(HIDDEN_FIELD_FAKE_SUBMIT);
+ getResponse().write(
+ new AppendingStringBuffer(
+ "\n<div style=\"display:none\"><input type=\"hidden\" name=\"").append(fs)
+ .append("\" id=\"").append(fs).append("\"/>"));
+ String ws = getHiddenFieldId(HIDDEN_FIELD_WICKET_STATE);
+ getResponse().write(
+ new AppendingStringBuffer("\n<input type=\"hidden\" name=\"wicketState\" id=\"")
+ .append(ws).append("\"/></div>"));
+
+ // if a default button was set, handle the rendering of that
+ if (defaultButton != null && defaultButton.isVisibleInHierarchy()
+ && defaultButton.isEnabled())
+ {
+ appendDefaultButtonField(markupStream, openTag);
+ }
}
// do the rest of the processing
@@ -785,30 +849,43 @@
@Override
protected void onComponentTag(final ComponentTag tag)
{
- checkComponentTag(tag, "form");
- setOutputMarkupId(true);
super.onComponentTag(tag);
+ if (isRootForm())
+ {
+ checkComponentTag(tag, "form");
- // If the javascriptid is already generated then use that on even it was
- // before the first render. Bbecause there could be a component which
- // already uses it to submit the forum. This should be fixed when we
- // pre parse the markup so that we know the id is at front.
- tag.put("method", "post");
- tag.put("action", Strings.replaceAll(urlFor(IFormSubmitListener.INTERFACE), "&", "&"));
+ // If the javascriptid is already generated then use that on even it
+ // was
+ // before the first render. Bbecause there could be a component
+ // which
+ // already uses it to submit the forum. This should be fixed when we
+ // pre parse the markup so that we know the id is at front.
+ tag.put("method", "post");
+ tag.put("action", Strings.replaceAll(urlFor(IFormSubmitListener.INTERFACE), "&",
+ "&"));
- if (multiPart)
- {
- tag.put("enctype", "multipart/form-data");
+ if (multiPart)
+ {
+ tag.put("enctype", "multipart/form-data");
+ }
+ else
+ {
+ // sanity check
+ String enctype = (String)tag.getAttributes().get("enctype");
+ if ("multipart/form-data".equalsIgnoreCase(enctype))
+ {
+ // though not set explicitly in Java, this is a multipart
+ // form
+ setMultiPart(true);
+ }
+ }
}
else
{
- // sanity check
- String enctype = (String)tag.getAttributes().get("enctype");
- if ("multipart/form-data".equalsIgnoreCase(enctype))
- {
- // though not set explicitly in Java, this is a multipart form
- setMultiPart(true);
- }
+ tag.setName("div");
+ tag.remove("method");
+ tag.remove("action");
+ tag.remove("enctype");
}
}
@@ -1492,4 +1569,33 @@
error(new MapVariableInterpolator(error, args).toString());
}
+ /**
+ * Returns whether the form is a root form, which means that there's no
+ * other form in it's parent hierarchy.
+ *
+ * @return true if form is a root form, false otherwise
+ */
+ public boolean isRootForm()
+ {
+ return findParent(Form.class) == null;
+ }
+
+ /**
+ * Returns the root form or this, if this is the root form.
+ *
+ * @return root form or this form
+ */
+ public Form<?> getRootForm()
+ {
+ Form<?> form;
+ Form<?> parent = this;
+ do
+ {
+ form = parent;
+ parent = (Form<?>)form.findParent(Form.class);
+ }
+ while (parent != null);
+
+ return form;
+ }
}
Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java Wed Oct 11 01:20:37 2006
@@ -347,7 +347,7 @@
{
inputName.prepend(id);
c = c.getParent();
- if (c == null || c instanceof Form || c instanceof Page)
+ if (c == null || (c instanceof Form && ((Form)c).isRootForm()) || c instanceof Page)
{
break;
}
Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/SubmitLink.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/SubmitLink.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/SubmitLink.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/SubmitLink.java Wed Oct 11 01:20:37 2006
@@ -213,24 +213,35 @@
protected final String getTriggerJavaScript()
{
if (getForm() != null) {
+ // find the root form - the one we are really going to submit
+ Form root = getForm().getRootForm();
StringBuffer sb = new StringBuffer(100);
sb.append("var e=document.getElementById('");
- sb.append(getForm().getHiddenFieldId(Form.HIDDEN_FIELD_FAKE_SUBMIT));
+ sb.append(root.getHiddenFieldId(Form.HIDDEN_FIELD_FAKE_SUBMIT));
sb.append("'); e.name=\'");
sb.append(getInputName());
sb.append("'; e.value='x';");
sb.append("var f=document.getElementById('");
- sb.append(getForm().getMarkupId());
+ sb.append(root.getMarkupId());
sb.append("');");
if (shouldInvokeJavascriptFormOnsubmit())
{
- sb.append("if (f.onsubmit != undefined) { if (f.onsubmit()==false) return false; }");
+ if (getForm() != root)
+ {
+ sb.append("var ff=document.getElementById('");
+ sb.append(getForm().getMarkupId());
+ sb.append("');");
+ }
+ else
+ {
+ sb.append("var ff=f;");
+ }
+ sb.append("if (ff.onsubmit != undefined) { if (ff.onsubmit()==false) return false; }");
}
sb.append("f.submit();e.value='';e.name='';return false;");
return sb.toString();
} else {
return null;
}
- }
-
+ }
}
Modified: incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ButtonTest.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ButtonTest.java?view=diff&rev=462728&r1=462727&r2=462728
==============================================================================
--- incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ButtonTest.java (original)
+++ incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ButtonTest.java Wed Oct 11 01:20:37 2006
@@ -79,7 +79,7 @@
application.assertContains("<input name=\"button\" type=\"submit\" wicket:id=\"button\"/>");
String doc = application.getServletResponse().getDocument();
- boolean contains = doc.contains("<input onclick=\"var e=document.getElementById('form:hf:fs'); e.name='button2'; e.value='x';var f=document.getElementById('form');if (f.onsubmit != undefined) { if (f.onsubmit()==false) return false; }f.submit();e.value='';e.name='';return false;\" type=\"submit\" name=\"button2\" wicket:id=\"button2\"/>");
+ boolean contains = doc.contains("<input onclick=\"var e=document.getElementById('form:hf:fs'); e.name='button2'; e.value='x';var f=document.getElementById('form');var ff=f;if (ff.onsubmit != undefined) { if (ff.onsubmit()==false) return false; }f.submit();e.value='';e.name='';return false;\" type=\"submit\" name=\"button2\" wicket:id=\"button2\"/>");
assertTrue(contains);
}
}