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 &lt;form&gt; tags, the inner forms will be rendered using
+ * the &lt;div&gt; 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 &lt;input type="submit"&gt; 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), "&", "&amp;"));
+			// 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), "&",
+					"&amp;"));
 
-		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);
 	}
 }