Author: ivaynberg Date: Thu Jun 28 11:59:08 2007 New Revision: 551658 URL: http://svn.apache.org/viewvc?view=rev&rev=551658 Log: WICKET-709: ability to remove form validators as well as not validate formvalidators if they depend on components that are no longer on the page
Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java?view=diff&rev=551658&r1=551657&r2=551658 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java Thu Jun 28 11:59:08 2007 @@ -1413,7 +1413,8 @@ RequestCycle requestCycle = getRequestCycle(); if (requestCycle == null) { - // Happens often with WicketTester when one forgets to call createRequestCycle() + // Happens often with WicketTester when one forgets to call + // createRequestCycle() throw new WicketRuntimeException("No RequestCycle is currently set!"); } return requestCycle.getRequest(); @@ -3152,7 +3153,14 @@ return this.getFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER); } - protected final boolean isRenderAllowed() + /** + * Checks the security strategy if the [EMAIL PROTECTED] Component#RENDER} action is + * allowed on this component + * + * @return ture if [EMAIL PROTECTED] Component#RENDER} action is allowed, false + * otherwise + */ + public final boolean isRenderAllowed() { return getFlag(FLAG_IS_RENDER_ALLOWED); } Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java?view=diff&rev=551658&r1=551657&r2=551658 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java Thu Jun 28 11:59:08 2007 @@ -52,6 +52,7 @@ import org.apache.wicket.util.upload.FileUploadBase.SizeLimitExceededException; import org.apache.wicket.util.value.ValueMap; import org.apache.wicket.validation.IValidatorAddListener; +import org.apache.wicket.version.undo.Change; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -349,7 +350,7 @@ { if (validator == null) { - throw new IllegalArgumentException("validator argument cannot be null"); + throw new IllegalArgumentException("Argument `validator` cannot be null"); } // add the validator @@ -363,6 +364,112 @@ } /** + * Removes a form validator from the form. + * + * @param validator + * validator + * @throws IllegalArgumentException + * if validator is null + * @see IFormValidator + */ + public void remove(IFormValidator validator) + { + if (validator == null) + { + throw new IllegalArgumentException("Argument `validator` cannot be null"); + } + + IFormValidator removed = formValidators_remove(validator); + 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"); + } + addStateChange(new FormValidatorRemovedChange(removed)); + } + + private final int formValidators_indexOf(IFormValidator validator) + { + if (formValidators != null) + { + if (formValidators instanceof IFormValidator) + { + final IFormValidator v = (IFormValidator)formValidators; + if (v == validator || v.equals(validator)) + { + return 0; + } + } + else + { + final IFormValidator[] validators = (IFormValidator[])formValidators; + for (int i = 0; i < validators.length; i++) + { + final IFormValidator v = validators[i]; + if (v == validator || v.equals(validator)) + { + return i; + } + } + } + } + return -1; + } + + private final IFormValidator formValidators_remove(IFormValidator validator) + { + int index = formValidators_indexOf(validator); + if (index != -1) + { + return formValidators_remove(index); + } + return null; + } + + private final IFormValidator formValidators_remove(int index) + { + if (formValidators instanceof IFormValidator) + { + if (index == 0) + { + final IFormValidator removed = (IFormValidator)formValidators; + formValidators = null; + return removed; + } + else + { + throw new IndexOutOfBoundsException(); + } + } + else + { + final IFormValidator[] validators = (IFormValidator[])formValidators; + final IFormValidator removed = validators[index]; + // check if we can collapse array of 1 element into a single object + if (validators.length == 2) + { + formValidators = validators[1 - index]; + } + else + { + IFormValidator[] newValidators = new IFormValidator[validators.length - 1]; + int j = 0; + for (int i = 0; i < validators.length; i++) + { + if (i != index) + { + newValidators[j++] = validators[i]; + } + } + this.formValidators = newValidators; + } + return removed; + } + } + + + /** * Clears the input from the form's nested children of type * [EMAIL PROTECTED] FormComponent}. This method is typically called when a form needs * to be reset. @@ -1109,24 +1216,26 @@ protected void appendDefaultButtonField(final MarkupStream markupStream, 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\"/>"); - + // add the button buffer.append("<input type=\"submit\" onclick=\" var b=Wicket.$('"); buffer.append(defaultButton.getMarkupId()); - buffer.append("'); if (typeof(b.onclick) != 'undefined') { var r = b.onclick.bind(this)(); if (r != false) b.click(); } else { b.click(); }; return false;\" "); + buffer + .append("'); if (typeof(b.onclick) != 'undefined') { var r = b.onclick.bind(this)(); if (r != false) b.click(); } else { b.click(); }; return false;\" "); buffer.append(" />"); - + // close div buffer.append("</div>"); - + getResponse().write(buffer); } @@ -1540,6 +1649,39 @@ } /** + * Checks if the specified form component visible and is attached to a page + * + * @param fc + * form component + * + * @return true if the form component and all its parents are visible and + * there component is in page's hierarchy + */ + private boolean isFormComponentVisibleInPage(FormComponent fc) + { + if (fc == null) + { + throw new IllegalArgumentException("Argument `fc` cannot be null"); + } + Component c = fc; + Component last = fc; + while (c != null) + { + if (c.isRenderAllowed() && c.isVisible()) + { + last = c; + c = c.getParent(); + } + else + { + return false; + } + } + return last == this; + } + + + /** * Validates form with the given form validator * * @param validator @@ -1560,11 +1702,27 @@ for (int j = 0; j < dependents.length; j++) { final FormComponent dependent = dependents[j]; + // check if the dependent component is valid if (!dependent.isValid()) { validate = false; break; } + // check if the dependent componet is visible and is attached to + // the page + else if (!isFormComponentVisibleInPage(dependent)) + { + 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() + "`."); + } + validate = false; + break; + } } } @@ -1584,5 +1742,35 @@ { validateFormValidator(formValidators_get(i)); } + } + + /** + * Change object to keep track of form validator removals + * + * @author Igor Vaynberg (ivaynberg at apache dot org) + */ + private class FormValidatorRemovedChange extends Change + { + private static final long serialVersionUID = 1L; + + private final IFormValidator removed; + + /** + * Construct. + * + * @param removed + */ + public FormValidatorRemovedChange(final IFormValidator removed) + { + super(); + this.removed = removed; + } + + + public void undo() + { + add(removed); + } + } }