/*
* 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.ajax.attributes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.wicket.ajax.AjaxChannel;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.time.Duration;
/**
* Attributes of an Ajax Request.
*
* @author Matej Knopp
*/
public final class AjaxRequestAttributes
{
/**
* The method to be used when submitting a form
*/
public enum Method
{
/** get */
GET,
/** post */
POST;
@Override
public String toString()
{
return name();
}
}
/**
* The JavaScript event propagation type
*/
public enum EventPropagation
{
/**
* Stops the propagation of the JavaScript event to the parent of its target
*/
STOP,
/**
* Stops the propagation of the JavaScript event to the parent of its target and all other
* event listeners registered on the same target
*/
STOP_IMMEDIATE,
/**
* Do not stop the propagation of the JavaScript event
*/
BUBBLE
}
public static final String XML_DATA_TYPE = "xml";
private boolean multipart = false;
private Method method = Method.GET;
private Duration requestTimeout;
private boolean preventDefault = false;
private EventPropagation eventPropagation = EventPropagation.BUBBLE;
/**
* The names of the events which will trigger the Ajax call
*/
private String[] eventNames = new String[0];
/**
* The id of the for that should be submitted
*/
private String formId;
/**
* The id of the button/link that submitted the form
*/
private String submittingComponentName;
/**
* Indicates whether or not this AjaxBehavior will produce <ajax-response>. By default it will
* produce it but some behaviors may need to return their own response which shouldn't be
* processed by wicket-ajax.js
*/
private boolean wicketAjaxResponse = true;
private String dataType = XML_DATA_TYPE;
private List<IAjaxCallListener> ajaxCallListeners;
private Map<String, Object> extraParameters;
private List<CharSequence> dynamicExtraParameters;
private AjaxChannel channel;
/**
* Whether or not to use asynchronous XMLHttpRequest
*/
private boolean async = true;
/**
* The settings to use if the Ajax call should be throttled. Throttled behaviors only execute
* once within the given delay even though they are triggered multiple times.
* <p>
* For example, this is useful when attaching a behavior to the keypress event. It is not
* desirable to have an ajax call made every time the user types so we throttle that call to a
* desirable delay, such as once per second. This gives us a near real time ability to provide
* feedback without overloading the server with ajax calls.
*/
private ThrottlingSettings throttlingSettings;
/**
* A selector string to filter the descendants of the selected
* elements that trigger the event. If the selector is null or empty,
* the event is always triggered when it reaches the selected HTML element.
*
* @see <a href="http://api.jquery.com/on/">jQuery#on's selector</a>
*/
private CharSequence childSelector;
/**
* A flag indicating whether to collect (submit) the name/value pairs for all HTML form elements
* children of the HTML element with the JavaScript listener
*/
private boolean serializeRecursively;
/**
* @see #childSelector
* @return The selector string that filters the descendants
*/
public CharSequence getChildSelector()
{
return childSelector;
}
/**
* @see #childSelector
* @param childSelector
* The selector string that filters the descendants
*/
public void setChildSelector(CharSequence childSelector)
{
this.childSelector = childSelector;
}
/**
* Returns whether the form submit is multipart.
* <p>
* Note that for multipart AJAX requests a hidden IFRAME will be used and that can have negative
* impact on error detection.
*
* @return <code>true</code> if the form submit should be multipart, <code>false</code>
* otherwise
*/
public boolean isMultipart()
{
return multipart;
}
/**
* Determines whether the form submit is multipart.
*
* <p>
* Note that for multipart AJAX requests a hidden IFRAME will be used and that can have negative
* impact on error detection.
*
* @param multipart
* @return this object
*/
public AjaxRequestAttributes setMultipart(boolean multipart)
{
this.multipart = multipart;
return this;
}
/**
* Returns the type of the Ajax request: <code>GET</code> or <code>POST</code>.
* <p>
* For a <code>POST</code>request all URL arguments are submitted as body. This can be useful if
* the URL parameters are longer than maximal URL length.
*
* @return the type of the Ajax request. Default: {@linkplain Method#GET}
*/
public Method getMethod()
{
return method;
}
/**
* Sets the type of the Ajax request: <code>GET</code> or <code>POST</code>.
* <p>
* For a <code>POST</code>request all URL arguments are submitted as body. This can be useful if
* the URL parameters are longer than maximal URL length.
*
* @param method
* the type of the Ajax request
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setMethod(final Method method)
{
this.method = Args.notNull(method, "method");
return this;
}
/**
* Returns the timeout in milliseconds for the AJAX request. This only involves the actual
* communication and not the processing afterwards. Can be <code>null</code> in which case the
* default request timeout will be used.
*
* @return request timeout or <code>null<code> for default timeout. Default: no timeout.
*/
public Duration getRequestTimeout()
{
return requestTimeout;
}
/**
* Sets the timeout in milliseconds for the AJAX request. This only involves the actual
* communication and not the processing afterwards. Can be <code>null</code> in which case the
* default request timeout will be used.
*
* @param requestTimeout
* @return this object
*/
public AjaxRequestAttributes setRequestTimeout(final Duration requestTimeout)
{
this.requestTimeout = requestTimeout;
return this;
}
/**
* @return a list of {@link IAjaxCallListener}s which will be notified during the the execution
* of the Ajax call.
*/
public List<IAjaxCallListener> getAjaxCallListeners()
{
if (ajaxCallListeners == null)
{
ajaxCallListeners = new ArrayList<>();
}
return ajaxCallListeners;
}
/**
* Map that contains additional (static) URL parameters. These will be appended to the request
* URL. If you need more than one value for a key then use a java.util.List or an Object[] as a
* value of that key.
*
* @return a map with additional URL arguments
* @see #getDynamicExtraParameters()
*/
public Map<String, Object> getExtraParameters()
{
if (extraParameters == null)
{
extraParameters = new HashMap<>();
}
return extraParameters;
}
/**
* Array of JavaScript functions that produce additional URL arguments.
*
* <p>
* If there are no multivalued parameters then the function can return a simple JavaScript
* object. Example:
*
* <pre>
* return {
* 'param1': document.body.tagName,
* 'param2': calculateParam2()
* }
* </pre>
*
* </p>
* <p>
* If there are multivalued parameters then an array of objects may be used. Example:
*
* <pre>
* return [
* { name: 'param1', value: document.body.tagName },
* { name: 'param1', value: calculateSecondValueForParam1() },
* { name: 'param2', value: calculateParam2() }
* ]
*
* </pre>
*
* </p>
*
* @return a list of functions that produce additional URL arguments.
* @see #getExtraParameters()
*/
public List<CharSequence> getDynamicExtraParameters()
{
if (dynamicExtraParameters == null)
{
dynamicExtraParameters = new ArrayList<>();
}
return dynamicExtraParameters;
}
/**
* Only applies for event behaviors. Returns whether the behavior should prevent the default event
* handler to be invoked. For example if the behavior is attached to a link and
* isPreventDefault() returns <code>true</code>, the link's
* URL will not be followed. If the Ajax behavior is attached to a checkbox or a radio button
* then the default behavior should be allowed to actually check the box or radio button, i.e.
* this method should return <code>false</code>.
*
* @return {@code false} if the default event handler should be invoked
*/
public boolean isPreventDefault()
{
return preventDefault;
}
/**
* Only applies for event behaviors. Determines whether the behavior should prevent the default
* event handler to be invoked.
*
* @see #isPreventDefault()
*
* @param preventDefault
* @return {@code this} object for chaining
* @see #isPreventDefault()
*/
public AjaxRequestAttributes setPreventDefault(boolean preventDefault)
{
this.preventDefault = preventDefault;
return this;
}
/**
* Only applies for event behaviors. Returns whether the behavior should allow the JavaScript
* event to propagate to the parent of its target.
*/
public EventPropagation getEventPropagation()
{
return eventPropagation;
}
/**
* Only applies to event behaviors. Determines whether the behavior should allow the JavaScript
* event to propagate to the parent of its target.
*
* @param eventPropagation
* the type of the stop
* @return {@code this} object, for chaining
*/
public AjaxRequestAttributes setEventPropagation(EventPropagation eventPropagation)
{
this.eventPropagation = Args.notNull(eventPropagation, "eventPropagation");
return this;
}
/**
* @param async
* a flag whether to do asynchronous Ajax call or not
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setAsynchronous(final boolean async)
{
this.async = async;
return this;
}
/**
* @return whether to do asynchronous Ajax call
*/
public boolean isAsynchronous()
{
return async;
}
/**
* @return the channel to use
*/
public AjaxChannel getChannel()
{
return channel;
}
/**
* @param channel
* the Ajax channel to use. Pass {@code null} to use the default channel with name
* <em>0</em> and queueing type.
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setChannel(final AjaxChannel channel)
{
this.channel = channel;
return this;
}
/**
* @return the name(s) of the event(s) which will trigger the Ajax call
*/
public String[] getEventNames()
{
return eventNames;
}
/**
* @param eventNames
* the names of the events which will trigger the Ajax call
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setEventNames(String... eventNames)
{
Args.notNull(eventNames, "eventNames");
this.eventNames = eventNames;
return this;
}
/**
* @return the id of the for that should be submitted
*/
public String getFormId()
{
return formId;
}
/**
* @param formId
* the id of the for that should be submitted
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setFormId(final String formId)
{
this.formId = formId;
return this;
}
/**
* @return the input name of the button/link that submits the form
*/
public String getSubmittingComponentName()
{
return submittingComponentName;
}
/**
* @param submittingComponentName
* the input name of the button/link that submits the form
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setSubmittingComponentName(String submittingComponentName)
{
this.submittingComponentName = submittingComponentName;
return this;
}
/**
* @return a flag indicating whether the Ajax response should be processed by Wicket (i.e. to
* replace components, execute scripts, etc.). Default: {@code true}.
*/
public boolean isWicketAjaxResponse()
{
return wicketAjaxResponse;
}
/**
* @param wicketAjaxResponse
* a flag indicating whether the Ajax response should be processed by Wicket (i.e. to
* replace components, execute scripts, etc.).
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setWicketAjaxResponse(final boolean wicketAjaxResponse)
{
this.wicketAjaxResponse = wicketAjaxResponse;
return this;
}
/**
* Returns the type of the data in the Ajax response. For example: 'xml', 'json', 'html', etc.
* See the documentation of jQuery.ajax() method for more information.
*
* @return the type of the data in the Ajax response.
*/
public String getDataType()
{
return dataType;
}
/**
* @param dataType
* the type of the data in the Ajax response.
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setDataType(final String dataType)
{
this.dataType = Args.notEmpty(dataType, "dataType");
return this;
}
/**
* @return the settings to use when throttling is needed.
*/
public ThrottlingSettings getThrottlingSettings()
{
return throttlingSettings;
}
/**
* @param throttlingSettings
* the settings to use when throttling is needed. Pass {@code null} to disable
* throttling.
* @return {@code this} object for chaining
*/
public AjaxRequestAttributes setThrottlingSettings(ThrottlingSettings throttlingSettings)
{
this.throttlingSettings = throttlingSettings;
return this;
}
/**
* @return whether to collect (submit) the name/value pairs for all HTML form elements
* children of the HTML element with the JavaScript listener
*/
public boolean isSerializeRecursively() {
return serializeRecursively;
}
/**
* @param serializeRecursively
* a flag indicating whether to collect (submit) the name/value pairs for all HTML form elements
* children of the HTML element with the JavaScript listener
*/
public AjaxRequestAttributes setSerializeRecursively(final boolean serializeRecursively) {
this.serializeRecursively = serializeRecursively;
return this;
}
}