Author: gseitz
Date: Wed Jan 9 13:59:33 2008
New Revision: 610593
URL: http://svn.apache.org/viewvc?rev=610593&view=rev
Log:
WICKET-1124: enhancement of nested form handling
Added:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
(with props)
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
(with props)
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
(with props)
Modified:
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
Modified:
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java?rev=610593&r1=610592&r2=610593&view=diff
==============================================================================
---
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
(original)
+++
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
Wed Jan 9 13:59:33 2008
@@ -86,9 +86,9 @@
if (cursor == null)
{
throw new IllegalStateException(
- "form was not specified in the
constructor and cannot "
- + "be found in
the hierarchy of the component this behavior "
- + "is attached
to");
+ "form was not specified in the
constructor and cannot "
+ + "be found in the hierarchy of
the component this behavior "
+ + "is attached to");
}
else
{
@@ -106,12 +106,13 @@
AppendingStringBuffer call = new
AppendingStringBuffer("wicketSubmitFormById('").append(
- formId).append("', '").append(url).append("',
");
+ formId).append("', '").append(url).append("', ");
if (getComponent() instanceof IFormSubmittingComponent)
{
-
call.append("'").append(((IFormSubmittingComponent)getComponent()).getInputName())
- .append("' ");
+ call.append("'")
+
.append(((IFormSubmittingComponent)getComponent()).getInputName())
+ .append("' ");
}
else
{
@@ -124,6 +125,11 @@
protected void onEvent(AjaxRequestTarget target)
{
getForm().onFormSubmitted();
+ if (!getForm().isSubmitted())
+ { // only process the form submission if the form was actually
submitted -> needs to be
+ // enabled and visible
+ return;
+ }
if (!getForm().hasError())
{
onSubmit(target);
Modified:
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java?rev=610593&r1=610592&r2=610593&view=diff
==============================================================================
---
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
(original)
+++
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
Wed Jan 9 13:59:33 2008
@@ -146,8 +146,16 @@
if (component instanceof FormComponent)
{
FormComponent formComponent =
(FormComponent)component;
+
+ Form form = formComponent.getForm();
+ if (!form.isEnabled() ||
!form.isEnableAllowed() || !form.isVisibleInHierarchy())
+ {
+ // do not validate formComponent or any
of formComponent's children
+ return
Component.IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+ }
+
if (formComponent.isVisibleInHierarchy() &&
formComponent.isValid() &&
- formComponent.isEnabled() &&
formComponent.isEnableAllowed())
+ formComponent.isEnabled() &&
formComponent.isEnableAllowed())
{
validate(formComponent);
}
@@ -381,8 +389,8 @@
if (removed == null)
{
throw new IllegalStateException(
- "Tried to remove form validator that
was not previously added. "
- + "Make sure your
validator's equals() implementation is sufficient");
+ "Tried to remove form validator that was not
previously added. "
+ + "Make sure your validator's equals()
implementation is sufficient");
}
addStateChange(new FormValidatorRemovedChange(removed));
}
@@ -508,31 +516,31 @@
*/
public final IFormSubmittingComponent findSubmittingButton()
{
- IFormSubmittingComponent submittingComponent =
(IFormSubmittingComponent)getPage()
- .visitChildren(IFormSubmittingComponent.class,
new IVisitor()
+ IFormSubmittingComponent submittingComponent =
(IFormSubmittingComponent)getPage().visitChildren(
+ IFormSubmittingComponent.class, new IVisitor()
+ {
+ public Object component(final Component
component)
{
- public Object component(final Component
component)
- {
- // Get submitting component
- final IFormSubmittingComponent
submittingComponent = (IFormSubmittingComponent)component;
+ // Get submitting component
+ final IFormSubmittingComponent
submittingComponent = (IFormSubmittingComponent)component;
- // Check for component-name or
component-name.x request string
- if
(submittingComponent.getForm() != null &&
-
submittingComponent.getForm().getRootForm() == Form.this &&
-
(getRequest().getParameter(submittingComponent.getInputName()) != null ||
getRequest()
-
.getParameter(submittingComponent.getInputName() + ".x") != null))
+ // Check for component-name or
component-name.x request string
+ if (submittingComponent.getForm() !=
null &&
+
submittingComponent.getForm().getRootForm() == Form.this &&
+
(getRequest().getParameter(submittingComponent.getInputName()) != null ||
getRequest().getParameter(
+
submittingComponent.getInputName() + ".x") != null))
+ {
+ if (!component.isVisible())
{
- if
(!component.isVisible())
- {
- throw new
WicketRuntimeException("Submit Button " +
-
submittingComponent.getInputName() + " (path=" +
-
component.getPageRelativePath() + ") is not visible");
- }
- return
submittingComponent;
+ throw new
WicketRuntimeException("Submit Button " +
+
submittingComponent.getInputName() + " (path=" +
+
component.getPageRelativePath() + ") is not visible");
}
- return CONTINUE_TRAVERSAL;
+ return submittingComponent;
}
- });
+ return CONTINUE_TRAVERSAL;
+ }
+ });
return submittingComponent;
}
@@ -579,9 +587,8 @@
{
Form root = getRootForm();
return new
AppendingStringBuffer("document.getElementById('").append(
-
root.getHiddenFieldId()).append("').value='").append(url).append(
-
"';document.getElementById('").append(root.getJavascriptId())
- .append("').submit();");
+
root.getHiddenFieldId()).append("').value='").append(url).append(
+
"';document.getElementById('").append(root.getJavascriptId()).append("').submit();");
}
/**
@@ -728,7 +735,7 @@
*/
public final void onFormSubmitted()
{
- setFlag(FLAG_SUBMITTED, true);
+ markFormsSubmitted();
if (handleMultiPart())
{
@@ -775,7 +782,7 @@
// onError
else if (hasError())
{
- onError();
+ callOnError();
}
}
@@ -790,6 +797,13 @@
*/
public boolean process()
{
+ if (!isEnabled() || !isEnableAllowed() ||
!isVisibleInHierarchy())
+ {
+ // since process() can be called outside of the default
form workflow, an additional
+ // check is needed
+ return false;
+ }
+
// run validation
validate();
@@ -800,14 +814,14 @@
markFormComponentsInvalid();
// let subclass handle error
- onError();
+ callOnError();
// Form has an error
return false;
}
else
{
- // mark all childeren as valid
+ // mark all children as valid
markFormComponentsValid();
// before updating, call the interception method for
clients
@@ -825,6 +839,55 @@
}
/**
+ * Calls onError on this [EMAIL PROTECTED] Form} and any enabled and
visible nested form, if the respective
+ * [EMAIL PROTECTED] Form} actually has errors.
+ */
+ private void callOnError()
+ {
+ onError();
+ // call onError on nested forms
+ visitChildren(Form.class, new IVisitor()
+ {
+ public Object component(Component component)
+ {
+ final Form form = (Form)component;
+ if (!form.isEnabled() ||
!form.isEnableAllowed() || !form.isVisibleInHierarchy())
+ {
+ return
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+ }
+ if (form.hasError())
+ {
+ form.onError();
+ }
+ return IVisitor.CONTINUE_TRAVERSAL;
+ }
+ });
+ }
+
+
+ /**
+ * Sets FLAG_SUBMITTED to true on this form and every enabled nested
form.
+ */
+ private void markFormsSubmitted()
+ {
+ setFlag(FLAG_SUBMITTED, true);
+
+ visitChildren(Form.class, new IVisitor()
+ {
+ public Object component(Component component)
+ {
+ Form form = (Form)component;
+ if (form.isEnabled() && form.isEnableAllowed()
&& isVisibleInHierarchy())
+ {
+ form.setFlag(FLAG_SUBMITTED, true);
+ return IVisitor.CONTINUE_TRAVERSAL;
+ }
+ return
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+ }
+ });
+ }
+
+ /**
* Removes already persisted data for all FormComponent children and
disable persistence for the
* same components.
*
@@ -932,7 +995,7 @@
}
/**
- * Convenient and typesafe way to visit all the form components on a
form
+ * Convenient and typesafe way to visit all the form components on a
form.
*
* @param visitor
* The visitor interface to call
@@ -948,26 +1011,7 @@
}
});
- /**
- * TODO Post 1.2 General: Maybe we should re-think how Borders
are implemented, because
- * there are just too many exceptions in the code base because
of borders. This time it is
- * to solve the problem tested in BoxBorderTestPage_3 where the
Form is defined in the box
- * border and the FormComponents are in the "body". Thus, the
formComponents are not childs
- * of the form. They are rather children of the border, as the
Form itself.
- */
- if (getParent() instanceof Border)
- {
- MarkupContainer border = getParent();
- Iterator iter = border.iterator();
- while (iter.hasNext())
- {
- Component child = (Component)iter.next();
- if (child instanceof FormComponent)
- {
-
visitor.formComponent((FormComponent)child);
- }
- }
- }
+ visitChildrenInContainingBorder(visitor);
}
/**
@@ -981,13 +1025,21 @@
{
FormComponent.visitFormComponentsPostOrder(this, visitor);
- /**
- * TODO Post 1.2 General: Maybe we should re-think how Borders
are implemented, because
- * there are just too many exceptions in the code base because
of borders. This time it is
- * to solve the problem tested in BoxBorderTestPage_3 where the
Form is defined in the box
- * border and the FormComponents are in the "body". Thus, the
formComponents are not
- * children of the form. They are rather children of the
border, as the Form itself.
- */
+ visitChildrenInContainingBorder(visitor);
+ }
+
+ /**
+ * TODO Post 1.2 General: Maybe we should re-think how Borders are
implemented, because there
+ * are just too many exceptions in the code base because of borders.
This time it is to solve
+ * the problem tested in BoxBorderTestPage_3 where the Form is defined
in the box border and the
+ * FormComponents are in the "body". Thus, the formComponents are not
children of the form. They
+ * are rather children of the border, as the Form itself.
+ *
+ * @param visitor
+ * The [EMAIL PROTECTED] [EMAIL PROTECTED] IVisitor} used to
visit the children.
+ */
+ private void visitChildrenInContainingBorder(final
FormComponent.IVisitor visitor)
+ {
if (getParent() instanceof Border)
{
MarkupContainer border = getParent();
@@ -1041,7 +1093,7 @@
RequestCycle rc = RequestCycle.get();
IRequestCycleProcessor processor = rc.getProcessor();
final RequestParameters requestParameters =
processor.getRequestCodingStrategy().decode(
- new FormDispatchRequest(rc.getRequest(), url));
+ new FormDispatchRequest(rc.getRequest(), url));
IRequestTarget rt = processor.resolve(rc, requestParameters);
if (rt instanceof ListenerInterfaceRequestTarget)
{
@@ -1051,8 +1103,8 @@
else
{
throw new WicketRuntimeException(
- "Attempt to access unknown request
listener interface " +
-
requestParameters.getInterfaceName());
+ "Attempt to access unknown request listener
interface " +
+ requestParameters.getInterfaceName());
}
}
@@ -1199,14 +1251,13 @@
* The open tag for the body
*/
protected void appendDefaultButtonField(final MarkupStream markupStream,
- final ComponentTag openTag)
+ final ComponentTag openTag)
{
AppendingStringBuffer buffer = new AppendingStringBuffer();
// div that is not visible (but not display:none either)
- buffer
- .append("<div
style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">");
+ buffer.append("<div
style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">");
// add an empty textfield (otherwise IE doesn't work)
buffer.append("<input type=\"text\" autocomplete=\"false\"/>");
@@ -1224,8 +1275,7 @@
}
buffer.append("\" onclick=\" var b=Wicket.$('");
buffer.append(submittingComponent.getMarkupId());
- buffer
- .append("'); if (typeof(b.onclick) !=
'undefined') { var r = b.onclick.bind(b)(); if (r != false) b.click(); } else
{ b.click(); }; return false;\" ");
+ buffer.append("'); if (typeof(b.onclick) != 'undefined') { var
r = b.onclick.bind(b)(); if (r != false) b.click(); } else { b.click(); };
return false;\" ");
buffer.append(" />");
// close div
@@ -1266,13 +1316,31 @@
{
// when the given submitting component is not null, it means
that it was the
// submitting component
+ Form formToProcess = this;
if (submittingComponent != null)
{
submittingComponent.onSubmit();
+ // use the form which the submittingComponent has
submitted for further processing
+ formToProcess = submittingComponent.getForm();
}
// Model was successfully updated with valid data
- onSubmit();
+ formToProcess.onSubmit();
+
+ // call onSubmit on nested forms
+ formToProcess.visitChildren(Form.class, new IVisitor()
+ {
+ public Object component(Component component)
+ {
+ Form form = (Form)component;
+ if (form.isEnabled() && form.isEnableAllowed()
&& form.isVisibleInHierarchy())
+ {
+ form.onSubmit();
+ return IVisitor.CONTINUE_TRAVERSAL;
+ }
+ return
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+ }
+ });
}
/**
@@ -1343,8 +1411,7 @@
// parsed out correctly
try
{
- final WebRequest multipartWebRequest =
((WebRequest)getRequest())
-
.newMultipartWebRequest(getMaxSize());
+ final WebRequest multipartWebRequest =
((WebRequest)getRequest()).newMultipartWebRequest(getMaxSize());
getRequestCycle().setRequest(multipartWebRequest);
}
catch (WicketRuntimeException wre)
@@ -1365,8 +1432,8 @@
// Resource key should be
<form-id>.uploadTooLarge to
// override default message
final String defaultValue = "Upload
must be less than " + getMaxSize();
- String msg = getString(getId() + "." +
UPLOAD_TOO_LARGE_RESOURCE_KEY, Model
- .valueOf(model),
defaultValue);
+ String msg = getString(getId() + "." +
UPLOAD_TOO_LARGE_RESOURCE_KEY,
+ Model.valueOf(model),
defaultValue);
error(msg);
}
else
@@ -1374,8 +1441,8 @@
// Resource key should be
<form-id>.uploadFailed to override
// default message
final String defaultValue = "Upload
failed: " + e.getLocalizedMessage();
- String msg = getString(getId() + "." +
UPLOAD_FAILED_RESOURCE_KEY, Model
- .valueOf(model),
defaultValue);
+ String msg = getString(getId() + "." +
UPLOAD_FAILED_RESOURCE_KEY,
+ Model.valueOf(model),
defaultValue);
error(msg);
log.warn(msg, e);
@@ -1426,16 +1493,46 @@
}
/**
- * Mark each form component on this form valid.
+ * Mark each form component on this form and on nested forms valid.
*/
protected final void markFormComponentsValid()
{
- // call invalidate methods of all nested form components
+ internalMarkFormComponentsValid();
+ markNestedFormComponentsValid();
+ }
+
+
+ /**
+ * Mark each form component on nested form valid.
+ */
+ private void markNestedFormComponentsValid()
+ {
+ visitChildren(Form.class, new IVisitor()
+ {
+ public Object component(Component component)
+ {
+ Form form = (Form)component;
+ if (form.isEnableAllowed() && form.isEnabled()
&& form.isVisibleInHierarchy())
+ {
+ form.internalMarkFormComponentsValid();
+ return CONTINUE_TRAVERSAL;
+ }
+ return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+ }
+ });
+ }
+
+ /**
+ * Mark each form component on this form valid.
+ */
+ private void internalMarkFormComponentsValid()
+ {
+ // call valid methods of all nested form components
visitFormComponentsPostOrder(new FormComponent.AbstractVisitor()
{
public void onFormComponent(final FormComponent
formComponent)
{
- if (formComponent.isVisibleInHierarchy())
+ if (formComponent.getForm() == Form.this &&
formComponent.isVisibleInHierarchy())
{
formComponent.valid();
}
@@ -1514,8 +1611,10 @@
// render the hidden field
AppendingStringBuffer buffer = new
AppendingStringBuffer(
- "<div style=\"display:none\"><input
type=\"hidden\" name=\"").append(nameAndId)
- .append("\"
id=\"").append(nameAndId).append("\" />");
+ "<div style=\"display:none\"><input
type=\"hidden\" name=\"").append(nameAndId)
+ .append("\" id=\"")
+ .append(nameAndId)
+ .append("\" />");
String method = getMethod().toLowerCase();
// if it's a get, did put the parameters in the action
attribute,
// and have to write the url parameters as hidden fields
@@ -1528,7 +1627,7 @@
{
String[] pair = params[j].split("=");
buffer.append("<input type=\"hidden\"
name=\"").append(pair[0]).append(
- "\"
value=\"").append(pair.length > 1 ? pair[1] : "").append("\" />");
+ "\"
value=\"").append(pair.length > 1 ? pair[1] : "").append("\" />");
}
}
buffer.append("</div>");
@@ -1596,9 +1695,9 @@
}
/**
- * Update the model of all form components using the fields that were
sent with the current
- * request. This method only updates models when the Form.validate() is
called first that takes
- * care of the conversion for the FormComponents.
+ * Update the model of all components on this form and nested forms
using the fields that were
+ * sent with the current request. This method only updates models when
the Form.validate() is
+ * called first that takes care of the conversion for the
FormComponents.
*
* Normally this method will not be called when a validation error
occurs in one of the form
* components.
@@ -1607,12 +1706,49 @@
*/
protected final void updateFormComponentModels()
{
+ internalUpdateFormComponentModels();
+ updateNestedFormComponentModels();
+ }
+
+ /**
+ * Update the model of all components on nested forms.
+ *
+ * @see #updateFormComponentModels()
+ */
+ private final void updateNestedFormComponentModels()
+ {
+ visitChildren(Form.class, new IVisitor()
+ {
+ public Object component(Component component)
+ {
+ Form form = (Form)component;
+ if (form.isEnabled() && form.isEnableAllowed()
&& form.isVisibleInHierarchy())
+ {
+
form.internalUpdateFormComponentModels();
+ return CONTINUE_TRAVERSAL;
+ }
+ return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+ }
+ });
+ }
+
+ /**
+ * Update the model of all components on this form.
+ *
+ * @see #updateFormComponentModels()
+ */
+ private void internalUpdateFormComponentModels()
+ {
visitFormComponentsPostOrder(new ValidationVisitor()
{
public void validate(FormComponent formComponent)
{
- // Potentially update the model
- formComponent.updateModel();
+ Form form = formComponent.getForm();
+ if (form == Form.this)
+ {
+ // Potentially update the model
+ formComponent.updateModel();
+ }
}
});
}
@@ -1628,8 +1764,13 @@
*/
protected void validate()
{
- validateComponents();
- validateFormValidators();
+ if (isEnabled() && isEnableAllowed() && isVisibleInHierarchy())
+ {
+ // since this method can be called directly by users,
this additional check is needed
+ validateComponents();
+ validateFormValidators();
+ validateNestedForms();
+ }
}
/**
@@ -1637,11 +1778,16 @@
*/
protected final void validateComponents()
{
- visitFormComponentsPostOrder(new ValidationVisitor()
+ visitFormComponents(new ValidationVisitor()
{
public void validate(final FormComponent formComponent)
{
- formComponent.validate();
+ final Form form = formComponent.getForm();
+ if (form == Form.this && form.isEnabled() &&
form.isEnableAllowed() &&
+ form.isVisibleInHierarchy())
+ {
+ formComponent.validate();
+ }
}
});
}
@@ -1712,11 +1858,10 @@
{
if (log.isWarnEnabled())
{
- log
-
.warn("IFormValidator in form `" +
-
getPageRelativePath() +
-
"` depends on a component that has been removed from the page or is no longer
visible. " +
-
"Offending component id `" + dependent.getId() + "`.");
+ log.warn("IFormValidator in
form `" +
+ getPageRelativePath() +
+ "` depends on a
component that has been removed from the page or is no longer visible. " +
+ "Offending component id
`" + dependent.getId() + "`.");
}
validate = false;
break;
@@ -1740,20 +1885,27 @@
{
validateFormValidator(formValidators_get(i));
}
+ }
- // traverse nested forms and invoke the form validators on them
+ /**
+ * Validates [EMAIL PROTECTED] FormComponent}s as well as [EMAIL
PROTECTED] IFormValidator}s in nested [EMAIL PROTECTED] Form}s.
+ *
+ * @see #validate()
+ */
+ private void validateNestedForms()
+ {
visitChildren(Form.class, new IVisitor()
{
public Object component(Component component)
{
final Form form = (Form)component;
- final int count = form.formValidators_size();
- for (int i = 0; i < count; i++)
+ if (form.isEnabled() && form.isEnableAllowed()
&& form.isVisibleInHierarchy())
{
-
form.validateFormValidator(form.formValidators_get(i));
+ form.validateComponents();
+ form.validateFormValidators();
+ return CONTINUE_TRAVERSAL;
}
-
- return IVisitor.CONTINUE_TRAVERSAL;
+ return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
}
});
}
Modified:
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java?rev=610593&r1=610592&r2=610593&view=diff
==============================================================================
---
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
(original)
+++
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
Wed Jan 9 13:59:33 2008
@@ -33,6 +33,7 @@
import org.apache.wicket.Page;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.border.Border;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.convert.ConversionException;
import org.apache.wicket.util.convert.IConverter;
@@ -75,8 +76,8 @@
* @author Igor Vaynberg (ivaynberg)
*/
public abstract class FormComponent extends LabeledWebMarkupContainer
- implements
- IFormVisitorParticipant
+ implements
+ IFormVisitorParticipant
{
/**
* Visitor for traversing form components
@@ -196,7 +197,8 @@
public String substitute(String string, Map vars) throws
IllegalStateException
{
return new MapVariableInterpolator(string,
addDefaultVars(vars), Application.get()
-
.getResourceSettings().getThrowExceptionOnMissingResource()).toString();
+ .getResourceSettings()
+
.getThrowExceptionOnMissingResource()).toString();
}
/**
@@ -354,19 +356,19 @@
* The visitor to call
*/
public static final void visitFormComponentsPostOrder(Component
component,
- final FormComponent.IVisitor visitor)
+ final FormComponent.IVisitor visitor)
{
if (visitor == null)
{
throw new IllegalArgumentException("Argument `visitor`
cannot be null");
}
-
visitFormComponentsPostOrderHelper(component, visitor);
}
+
private static final Object
visitFormComponentsPostOrderHelper(Component component,
- final FormComponent.IVisitor visitor)
+ final FormComponent.IVisitor visitor)
{
if (component instanceof MarkupContainer)
{
@@ -567,11 +569,32 @@
*/
public Form getForm()
{
- // Look for parent form
- final Form form = (Form)findParent(Form.class);
+ class FindFormVisitor implements Component.IVisitor
+ {
+ Form form = null;
+
+ public Object component(Component component)
+ {
+ form = (Form)component;
+ return Component.IVisitor.STOP_TRAVERSAL;
+ }
+ }
+
+ Form form = (Form)findParent(Form.class);
if (form == null)
{
- throw new WicketRuntimeException("Could not find Form
parent for " + this);
+ // check whether the form is a child of a surrounding
border
+ final Border border = (Border)findParent(Border.class);
+ if (border != null)
+ {
+ FindFormVisitor formVisitor = new
FindFormVisitor();
+ border.visitChildren(Form.class, formVisitor);
+ form = formVisitor.form;
+ }
+ if (form == null)
+ {
+ throw new WicketRuntimeException("Could not
find Form parent for " + this);
+ }
}
return form;
}
@@ -627,6 +650,7 @@
*/
public String getInputName()
{
+ // TODO: keep this in sync with AbstractSubmitLink#getInputName
String id = getId();
final PrependingStringBuffer inputName = new
PrependingStringBuffer(id.length());
Component c = this;
@@ -930,7 +954,7 @@
else
{
throw new UnsupportedOperationException("FormComponent
" + getClass() +
- " does not support cookies");
+ " does not support cookies");
}
return this;
}
@@ -946,7 +970,7 @@
if (!required && getType() != null && getType().isPrimitive())
{
throw new WicketRuntimeException(
- "FormComponent can't be not required
when the type is primitive class: " + this);
+ "FormComponent can't be not required when the
type is primitive class: " + this);
}
if (required != isRequired())
{
@@ -1222,8 +1246,8 @@
catch (NumberFormatException e)
{
throw new IllegalArgumentException(
- exceptionMessage("Internal error.
Request string '" + string +
- "' not a valid
integer"));
+ exceptionMessage("Internal error. Request
string '" + string +
+ "' not a valid integer"));
}
}
@@ -1247,7 +1271,7 @@
catch (NumberFormatException e)
{
throw new
IllegalArgumentException(exceptionMessage("Request string '" + string +
- "' is not a valid integer"));
+ "' is not a valid integer"));
}
}
else
@@ -1404,7 +1428,7 @@
catch (Exception e)
{
throw new WicketRuntimeException("Exception '" + e + "'
occurred during validation " +
- validator.getClass().getName() + " on
component " + getPath(), e);
+ validator.getClass().getName() + " on component
" + getPath(), e);
}
}
Added:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java?rev=610593&view=auto
==============================================================================
---
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
(added)
+++
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
Wed Jan 9 13:59:33 2008
@@ -0,0 +1,265 @@
+/*
+ * 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.Page;
+import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.markup.html.form.NestedFormsPage.NestableForm;
+import org.apache.wicket.util.tester.FormTester;
+
+/**
+ * @see <a
href="http://cwiki.apache.org/WICKET/nested-forms.html">"Specification"</a> of
nested
+ * forms handling
+ * @author Gerolf Seitz
+ */
+public class FormSubmitTest extends WicketTestCase
+{
+
+ private Page page;
+ private NestableForm outerForm;
+ private NestableForm middleForm;
+ private NestableForm innerForm;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ tester.startPage(new NestedFormsPage());
+ page = tester.getLastRenderedPage();
+ outerForm = (NestableForm)page.get("outerForm");
+ middleForm = (NestableForm)page.get("outerForm:middleForm");
+ innerForm =
(NestableForm)page.get("outerForm:middleForm:innerForm");
+ }
+
+
+ /**
+ *
+ */
+ public void testAllFormsEnabledSubmitOuterForm()
+ {
+ assertEnabledState(true, true, true);
+
+ FormTester formTester = tester.newFormTester("outerForm");
+ formTester.submit("submit");
+
+ assertOnSubmitCalled(true, true, true);
+ assertOnErrorCalled(false, false, false);
+ }
+
+ /**
+ *
+ */
+ public void testAllFormsEnabledSubmitMiddleForm()
+ {
+ assertEnabledState(true, true, true);
+
+ FormTester formTester =
tester.newFormTester("outerForm:middleForm");
+ formTester.submit("submit");
+
+ assertOnSubmitCalled(false, true, true);
+ assertOnErrorCalled(false, false, false);
+ }
+
+ /**
+ *
+ */
+ public void testAllFormsEnabledSubmitInnerForm()
+ {
+ assertEnabledState(true, true, true);
+
+ FormTester formTester =
tester.newFormTester("outerForm:middleForm:innerForm");
+ formTester.submit("submit");
+
+ assertOnSubmitCalled(false, false, true);
+ assertOnErrorCalled(false, false, false);
+ }
+
+
+ /**
+ *
+ */
+ public void testMiddleFormDisabledSubmitOuterForm()
+ {
+ // disable middle form
+ middleForm.setEnabled(false);
+ assertEnabledState(true, false, true);
+
+ // submit outer form
+ FormTester formTester = tester.newFormTester("outerForm");
+ formTester.submit("submit");
+
+ assertOnSubmitCalled(true, false, false);
+ assertOnErrorCalled(false, false, false);
+ }
+
+ /**
+ *
+ */
+ public void testInnerFormDisabledSubmitOuterForm()
+ {
+ // disable middle form
+ innerForm.setEnabled(false);
+ assertEnabledState(true, true, false);
+
+ // submit outer form
+ FormTester formTester = tester.newFormTester("outerForm");
+ formTester.submit("submit");
+
+ assertOnSubmitCalled(true, true, false);
+ assertOnErrorCalled(false, false, false);
+ }
+
+ /**
+ *
+ */
+ public void testSubmitDisabledOuterForm()
+ {
+ outerForm.setEnabled(false);
+ assertEnabledState(false, true, true);
+
+ FormTester formTester = tester.newFormTester("outerForm");
+ formTester.submit("submit");
+
+ assertOnSubmitCalled(false, false, false);
+ assertOnErrorCalled(false, false, false);
+ }
+
+ /**
+ *
+ */
+ public void testErrorOnInnerFormSubmitOuterForm()
+ {
+ assertEnabledState(true, true, true);
+
+ causeValidationErrorAndSubmit("outerForm",
"middleForm:innerForm:first");
+
+ assertOnSubmitCalled(false, false, false);
+ assertOnErrorCalled(true, true, true);
+ }
+
+ /**
+ *
+ */
+ public void testErrorOnMiddleFormSubmitOuterForm()
+ {
+ assertEnabledState(true, true, true);
+
+ causeValidationErrorAndSubmit("outerForm", "middleForm:first");
+
+ assertOnSubmitCalled(false, false, false);
+ assertOnErrorCalled(true, true, false);
+ }
+
+ /**
+ *
+ */
+ public void testErrorOnMiddleFormSubmitMiddleForm()
+ {
+ assertEnabledState(true, true, true);
+
+ causeValidationErrorAndSubmit("outerForm:middleForm", "first");
+
+ assertOnSubmitCalled(false, false, false);
+ assertOnErrorCalled(false, true, false);
+ }
+
+ /**
+ *
+ */
+ public void testErrorOnInnerFormSubmitMiddleForm()
+ {
+ assertEnabledState(true, true, true);
+
+ causeValidationErrorAndSubmit("outerForm:middleForm",
"innerForm:first");
+
+ assertOnSubmitCalled(false, false, false);
+ assertOnErrorCalled(false, true, true);
+ }
+
+ /**
+ *
+ */
+ public void testMiddleFormDisabledErrorOnOuterFormSubmitOuterForm()
+ {
+ middleForm.setEnabled(false);
+ assertEnabledState(true, false, true);
+
+ causeValidationErrorAndSubmit("outerForm", "first");
+
+ assertOnSubmitCalled(false, false, false);
+ assertOnErrorCalled(true, false, false);
+ }
+
+ /**
+ *
+ */
+ public void testErrorOnInnerFormDisabledMiddleFormSubmitOuterForm()
+ {
+ middleForm.setEnabled(false);
+ assertEnabledState(true, false, true);
+
+ causeValidationErrorAndSubmit("outerForm",
"middleForm:innerForm:first");
+
+ assertOnSubmitCalled(true, false, false);
+ assertOnErrorCalled(false, false, false);
+ }
+
+
+ private void assertEnabledState(boolean isOuterFormEnabled, boolean
isMiddleFormEnabled,
+ boolean isInnerFormEnabled)
+ {
+ assertEquals(isOuterFormEnabled, outerForm.isEnabled());
+ assertEquals(isMiddleFormEnabled, middleForm.isEnabled());
+ assertEquals(isInnerFormEnabled, innerForm.isEnabled());
+ }
+
+
+ private void assertOnErrorCalled(boolean isOuterFormOnErrorCalled,
+ boolean isMiddleFormOnErrorCalled, boolean
isInnerFormOnErrorCalled)
+ {
+ assertEquals(isOuterFormOnErrorCalled, outerForm.onErrorCalled);
+ assertEquals(isMiddleFormOnErrorCalled,
middleForm.onErrorCalled);
+ assertEquals(isInnerFormOnErrorCalled, innerForm.onErrorCalled);
+ }
+
+
+ private void assertOnSubmitCalled(boolean isOuterFormOnSubmitCalled,
+ boolean isMiddleFormOnSubmitCalled, boolean
isInnerFormOnSubmitCalled)
+ {
+ assertEquals(isOuterFormOnSubmitCalled,
outerForm.onSubmitCalled);
+ assertEquals(isMiddleFormOnSubmitCalled,
middleForm.onSubmitCalled);
+ assertEquals(isInnerFormOnSubmitCalled,
innerForm.onSubmitCalled);
+ }
+
+
+ /**
+ * @param formToBeSubmitted
+ * absolute path of the form to be submitted
+ * @param componentToGetError
+ * relative path to <code>formToBeSumitted</code> of the
component to be changed
+ * @return a [EMAIL PROTECTED] FormTester} instance
+ */
+ private FormTester causeValidationErrorAndSubmit(String
formToBeSubmitted,
+ String componentToGetError)
+ {
+ FormTester formTester;
+ formTester = tester.newFormTester(formToBeSubmitted);
+ formTester.setValue(componentToGetError, "");
+ formTester.submit("submit");
+ return formTester;
+ }
+
+}
Propchange:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
URL:
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html?rev=610593&view=auto
==============================================================================
---
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
(added)
+++
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
Wed Jan 9 13:59:33 2008
@@ -0,0 +1,55 @@
+<html>
+<head>
+ <style>
+ form, div {
+ border: 1px solid black;
+ padding: 20px;
+ margin: 20px;
+ }
+ </style>
+</head>
+<body>
+ <div wicket:id="feedback"></div>
+ <!-- <a wicket:id="ajaxToggleOuter">ajax enable/disable
outerForm</a><br/>
+ <a wicket:id="toggleOuter">enable/disable outerForm</a>
+ <form wicket:id="outerForm">
+ <a wicket:id="ajaxToggleInner">ajax enable/disable
innerForm</a><br/>
+ <a wicket:id="toggleInner">enable/disable innerForm</a>
+ <a wicket:id="ajaxSubmit">submit outerForm</a><br/>
+ <input type="submit" wicket:id="submit"/>
+ <p>
+ <form wicket:id="innerForm">
+ <input type="text" wicket:id="first"/>
+ <input type="text" wicket:id="second"/>
+ <a wicket:id="ajaxSubmit">submit
innerForm</a><br/>
+ <input type="submit" wicket:id="submit"/>
+ </form>
+ </p>
+ </form>
+ -->
+
+ <form wicket:id="outerForm">
+ <input type="text" wicket:id="first"/>
+ <input type="text" wicket:id="second"/><br/>
+ <a wicket:id="ajaxSubmit">submit via ajax</a><br/>
+ <a wicket:id="toggle">[toggle]</a><br/>
+ <input type="button" wicket:id="submit"/>
+
+ <form wicket:id="middleForm">
+ <input type="text" wicket:id="first"/>
+ <input type="text" wicket:id="second"/><br/>
+ <a wicket:id="ajaxSubmit">submit via ajax</a><br/>
+ <a wicket:id="toggle">[toggle]</a><br/>
+ <input type="button" wicket:id="submit"/>
+
+ <form wicket:id="innerForm">
+ <input type="text" wicket:id="first"/>
+ <input type="text" wicket:id="second"/><br/>
+ <a wicket:id="ajaxSubmit">submit via
ajax</a><br/>
+ <a wicket:id="toggle">[toggle]</a><br/>
+ <input type="button" wicket:id="submit"/>
+ </form>
+ </form>
+ </form>
+</body>
+</html>
\ No newline at end of file
Propchange:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java?rev=610593&view=auto
==============================================================================
---
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
(added)
+++
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
Wed Jan 9 13:59:33 2008
@@ -0,0 +1,140 @@
+/*
+ * 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.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.MarkupStream;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.form.validation.EqualInputValidator;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Gerolf Seitz
+ */
+public class NestedFormsPage extends WebPage
+{
+ private static final long serialVersionUID = 1L;
+ static Logger logger = LoggerFactory.getLogger(NestedFormsPage.class);
+
+ private final FeedbackPanel feedback;
+
+ /**
+ * Construct.
+ */
+ public NestedFormsPage()
+ {
+ feedback = new FeedbackPanel("feedback");
+ add(feedback.setOutputMarkupId(true));
+
+ Form outerForm = new NestableForm("outerForm");
+ add(outerForm.setOutputMarkupId(true));
+
+ Form middleForm = new NestableForm("middleForm");
+ outerForm.add(middleForm.setOutputMarkupId(true));
+
+ Form innerForm = new NestableForm("innerForm");
+ middleForm.add(innerForm.setOutputMarkupId(true));
+ }
+
+ public class NestableForm extends Form
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final String first = "test";
+
+ private final String second = "test";
+
+ public boolean onSubmitCalled = false;
+
+ public boolean onErrorCalled = false;
+
+ public NestableForm(String id)
+ {
+ super(id);
+ setModel(new CompoundPropertyModel(this));
+
+ TextField firstField = new RequiredTextField("first");
+ TextField secondField = new TextField("second");
+ add(firstField);
+ add(secondField);
+
+ add(new EqualInputValidator(firstField, secondField));
+ add(new AjaxSubmitLink("ajaxSubmit", this)
+ {
+ private static final long serialVersionUID = 1L;
+
+ protected void onSubmit(AjaxRequestTarget
target, Form form)
+ {
+ target.addComponent(feedback);
+ }
+
+ protected void onError(AjaxRequestTarget
target, Form form)
+ {
+ target.addComponent(feedback);
+ }
+ });
+ add(new ToggleLink("toggle", this));
+ add(new SubmitLink("submit"));
+ }
+
+ protected void onSubmit()
+ {
+ super.onSubmit();
+ onSubmitCalled = true;
+ logger.info(getId() + ".onSubmit");
+ }
+
+ protected void onError()
+ {
+ super.onError();
+ onErrorCalled = true;
+ logger.info(getId() + ".onError");
+ }
+ }
+
+ private class ToggleLink extends Link
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final Form form;
+
+ public ToggleLink(String id, Form form)
+ {
+ super(id);
+ this.form = form;
+ }
+
+ public void onClick()
+ {
+ form.setEnabled(!form.isEnabled());
+ form.info(form.getId() + ".isEnabled() == " +
form.isEnabled());
+ }
+
+ protected void onComponentTagBody(MarkupStream markupStream,
ComponentTag openTag)
+ {
+ String state = form.isEnabled() ? "enabled" :
"disabled";
+ replaceComponentTagBody(markupStream, openTag, "form is
" + state);
+ }
+ }
+
+}
Propchange:
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
------------------------------------------------------------------------------
svn:mime-type = text/plain