📄 form.java
字号:
/* * 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 java.util.HashMap;import java.util.Iterator;import java.util.Locale;import java.util.Map;import org.apache.wicket.Component;import org.apache.wicket.IRequestTarget;import org.apache.wicket.MarkupContainer;import org.apache.wicket.Page;import org.apache.wicket.Request;import org.apache.wicket.RequestCycle;import org.apache.wicket.WicketRuntimeException;import org.apache.wicket.markup.ComponentTag;import org.apache.wicket.markup.MarkupStream;import org.apache.wicket.markup.html.WebMarkupContainer;import org.apache.wicket.markup.html.border.Border;import org.apache.wicket.markup.html.form.persistence.CookieValuePersister;import org.apache.wicket.markup.html.form.persistence.IValuePersister;import org.apache.wicket.markup.html.form.upload.FileUploadField;import org.apache.wicket.markup.html.form.validation.IFormValidator;import org.apache.wicket.model.IModel;import org.apache.wicket.model.Model;import org.apache.wicket.protocol.http.RequestUtils;import org.apache.wicket.protocol.http.WebRequest;import org.apache.wicket.protocol.http.WebRequestCycle;import org.apache.wicket.request.IRequestCycleProcessor;import org.apache.wicket.request.RequestParameters;import org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget;import org.apache.wicket.settings.IApplicationSettings;import org.apache.wicket.util.lang.Bytes;import org.apache.wicket.util.string.AppendingStringBuffer;import org.apache.wicket.util.string.Strings;import org.apache.wicket.util.string.interpolator.MapVariableInterpolator;import org.apache.wicket.util.upload.FileUploadException;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;/** * Base class for forms. To implement a form, subclass this class, add FormComponents (such as * CheckBoxes, ListChoices or TextFields) to the form. You can nest multiple * IFormSubmittingComponents if you want to vary submit behavior. However, it is not necessary to * use any of Wicket's classes (such as Button or SubmitLink), just putting e.g. <input * type="submit" value="go"> suffices. * <p> * By default, the processing of a form works like this: * <li> The submitting component is looked up. An submitting IFormSubmittingComponent (such as a * button) is nested in this form (is a child component) and was clicked by the user. If an * IFormSubmittingComponent was found, and it has the defaultFormProcessing field set to false * (default is true), it's onSubmit method will be called right away, thus no validition is done, * and things like updating form component models that would normally be done are skipped. In that * respect, nesting an IFormSubmittingComponent with the defaultFormProcessing field set to false * has the same effect as nesting a normal link. If you want you can call validate() to execute form * validation, hasError() to find out whether validate() resulted in validation errors, and * updateFormComponentModels() to update the models of nested form components. </li> * <li> When no submitting IFormSubmittingComponent with defaultFormProcessing set to false was * found, this form is processed (method process()). Now, two possible paths exist: * <ul> * <li> Form validation failed. All nested form components will be marked invalid, and onError() is * called to allow clients to provide custom error handling code. </li> * <li> Form validation succeeded. The nested components will be asked to update their models and * persist their data is applicable. After that, method delegateSubmit with optionally the * submitting IFormSubmittingComponent is called. The default when there is a submitting * IFormSubmittingComponent is to first call onSubmit on that Component, and after that call * onSubmit on this form. Clients may override delegateSubmit if they want different behavior. </li> * </ul> * </li> * </li> * </p> * * Form for handling (file) uploads with multipart requests is supported by calling * setMultiPart(true) ( although wicket will try to automatically detect this for you ). Use this * with {@link org.apache.wicket.markup.html.form.upload.FileUploadField} components. You can attach * multiple FileUploadField components for multiple file uploads. * <p> * In case of an upload error two resource keys are available to specify error messages: * uploadTooLarge and uploadFailed * * ie in [page].properties * * [form-id].uploadTooLarge=You have uploaded a file that is over the allowed limit of 2Mb * * <p> * If you want to have multiple IFormSubmittingComponents which submit the same form, simply put two * or more IFormSubmittingComponents somewhere in the hierarchy of components that are children of * the form. * </p> * <p> * To get form components to persist their values for users via cookies, simply call * setPersistent(true) on each 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> * * @author Jonathan Locke * @author Juergen Donnerstag * @author Eelco Hillenius * @author Cameron Braid * @author Johan Compagner * @author Igor Vaynberg (ivaynberg) * @author David Leangen */public class Form extends WebMarkupContainer implements IFormSubmitListener{ /** * Visitor used for validation * * @author Igor Vaynberg (ivaynberg) */ public static abstract class ValidationVisitor implements FormComponent.IVisitor { /** * @see org.apache.wicket.markup.html.form.FormComponent.IVisitor#formComponent(org.apache.wicket.markup.html.form.IFormVisitorParticipant) */ public Object formComponent(IFormVisitorParticipant component) { 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()) { validate(formComponent); } } if (component.processChildren()) { return Component.IVisitor.CONTINUE_TRAVERSAL; } else { return Component.IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER; } } /** * Callback that should be used to validate form component * * @param formComponent */ public abstract void validate(FormComponent formComponent); } /** * */ class FormDispatchRequest extends Request { private final ValueMap params = new ValueMap(); private final Request realRequest; private final String url; /** * Construct. * * @param realRequest * @param url */ public FormDispatchRequest(final Request realRequest, final String url) { this.realRequest = realRequest; this.url = realRequest.decodeURL(url); String queryString = this.url.substring(this.url.indexOf("?") + 1); RequestUtils.decodeParameters(queryString, params); } /** * @see org.apache.wicket.Request#getLocale() */ public Locale getLocale() { return realRequest.getLocale(); } /** * @see org.apache.wicket.Request#getParameter(java.lang.String) */ public String getParameter(String key) { return (String)params.get(key); } /** * @see org.apache.wicket.Request#getParameterMap() */ public Map getParameterMap() { return params; } /** * @see org.apache.wicket.Request#getParameters(java.lang.String) */ public String[] getParameters(String key) { String param = (String)params.get(key); if (param != null) { return new String[] { param }; } return new String[0]; } /** * @see org.apache.wicket.Request#getPath() */ public String getPath() { return realRequest.getPath(); } public String getRelativePathPrefixToContextRoot() { return realRequest.getRelativePathPrefixToContextRoot(); } public String getRelativePathPrefixToWicketHandler() { return realRequest.getRelativePathPrefixToWicketHandler(); } /** * @see org.apache.wicket.Request#getURL() */ public String getURL() { return url; } } /** * Constant for specifying how a form is submitted, in this case using get. */ public static final String METHOD_GET = "get"; /** * Constant for specifying how a form is submitted, in this case using post. */ public static final String METHOD_POST = "post"; /** Flag that indicates this form has been submitted during this request */ private static final short FLAG_SUBMITTED = FLAG_RESERVED1; /** Log. */ private static final Logger log = LoggerFactory.getLogger(Form.class); private static final long serialVersionUID = 1L; private static final String UPLOAD_FAILED_RESOURCE_KEY = "uploadFailed"; private static final String UPLOAD_TOO_LARGE_RESOURCE_KEY = "uploadTooLarge"; /** * Any default IFormSubmittingComponent. If set, a hidden submit component will be rendered * right after the form tag, so that when users press enter in a textfield, this submit * component's action will be selected. If no default IFormSubmittingComponent is set, nothing * additional is rendered. * <p> * WARNING: note that this is a best effort only. Unfortunately having a 'default' * IFormSubmittingComponent in a form is ill defined in the standards, and of course IE has it's * own way of doing things. * </p> */ private IFormSubmittingComponent defaultSubmittingComponent; /** multi-validators assigned to this form */ private Object formValidators = null; private String javascriptId; /** * Maximum size of an upload in bytes. If null, the setting * {@link IApplicationSettings#getDefaultMaximumUploadSize()} is used. */ private Bytes maxSize = null; /** True if the form has enctype of multipart/form-data */ private boolean multiPart = false; /** * Constructs a form with no validation. * * @param id * See Component */ public Form(final String id) { super(id); setOutputMarkupId(true); } /** * @param id * See Component * @param model * See Component * @see org.apache.wicket.Component#Component(String, IModel) */ public Form(final String id, IModel model) { super(id, model); setOutputMarkupId(true); } /** * Adds a form validator to the form. * * @param validator * validator * @throws IllegalArgumentException * if validator is null * @see IFormValidator * @see IValidatorAddListener */ public void add(IFormValidator validator) { if (validator == null) { throw new IllegalArgumentException("Argument `validator` cannot be null"); } // add the validator formValidators_add(validator); // see whether the validator listens for add events if (validator instanceof IValidatorAddListener) { ((IValidatorAddListener)validator).onAdded(this); } } /** * 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]; } } formValidators = newValidators; } return removed; } } /** * Clears the input from the form's nested children of type {@link FormComponent}. This method * is typically called when a form needs to be reset. */ public final void clearInput() { // Visit all the (visible) form components and clear the input on each. visitFormComponentsPostOrder(new FormComponent.AbstractVisitor() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -