You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2012/03/13 11:12:41 UTC

git commit: WICKET-3367 Rewrite all JavaScript inline event handlers to be proper attached event handlers

Updated Branches:
  refs/heads/master 4b3db1c5b -> 06d225ee6


WICKET-3367 Rewrite all JavaScript inline event handlers to be proper attached event handlers

Refactoring in the new AjaxRequestAttributes:
- move preconditions in IAjaxCallListener
- drop JavaScriptFunctionBody and its specializations. Those were just CharSequence anyway.
- from now on only IAjaxCallListener can contribute to the IHeaderResponse
- add helper methods to AjaxCallListener (the default impl of IAjaxCallListener)


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/06d225ee
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/06d225ee
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/06d225ee

Branch: refs/heads/master
Commit: 06d225ee6de08ce60576bb9dd1a751dfcc0acb8f
Parents: 4b3db1c
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Tue Mar 13 12:10:13 2012 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Tue Mar 13 12:10:13 2012 +0200

----------------------------------------------------------------------
 .../wicket/ajax/AbstractDefaultAjaxBehavior.java   |   66 ++----
 .../wicket/ajax/attributes/AjaxCallListener.java   |  112 +++++++++-
 .../ajax/attributes/AjaxRequestAttributes.java     |  184 ++++++--------
 .../wicket/ajax/attributes/IAjaxCallListener.java  |   12 +-
 .../ajax/attributes/JavaScriptAfterHandler.java    |   33 ---
 .../ajax/attributes/JavaScriptBeforeHandler.java   |   33 ---
 .../ajax/attributes/JavaScriptFailureHandler.java  |   33 ---
 .../ajax/attributes/JavaScriptFunctionBody.java    |   55 -----
 .../ajax/attributes/JavaScriptPrecondition.java    |   40 ---
 .../ajax/attributes/JavaScriptSuccessHandler.java  |   33 ---
 .../html/IComponentAwareHeaderContributor.java     |    6 +-
 .../wicket/examples/ajax/builtin/LinksPage.java    |    2 -
 .../ajax/markup/html/AjaxEditableLabel.java        |   10 +-
 .../markup/html/AjaxEditableMultiLineLabel.java    |   15 +-
 14 files changed, 227 insertions(+), 407 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
index d113da1..25dae76 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
@@ -27,7 +27,6 @@ import org.apache.wicket.ajax.attributes.AjaxCallListener;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes.Method;
 import org.apache.wicket.ajax.attributes.IAjaxCallListener;
-import org.apache.wicket.ajax.attributes.JavaScriptPrecondition;
 import org.apache.wicket.ajax.attributes.ThrottlingSettings;
 import org.apache.wicket.ajax.json.JSONException;
 import org.apache.wicket.ajax.json.JSONObject;
@@ -42,6 +41,7 @@ import org.apache.wicket.request.resource.PackageResourceReference;
 import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.resource.CoreLibrariesContributor;
 import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.time.Duration;
 
 /**
  * The base class for Wicket's default AJAX implementation.
@@ -91,7 +91,7 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	}
 
 	/**
-	 * Renders header contribution by JavaScriptFunctionBody instances which additionally implement
+	 * Renders header contribution by IAjaxCallListener instances which additionally implement
 	 * IComponentAwareHeaderContributor interface.
 	 * 
 	 * @param component
@@ -99,7 +99,7 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	 * @param response
 	 *            the current header response
 	 */
-	private void renderExtraHeaderContributors(Component component, IHeaderResponse response)
+	private void renderExtraHeaderContributors(final Component component, final IHeaderResponse response)
 	{
 		AjaxRequestAttributes attributes = getAttributes();
 
@@ -112,12 +112,6 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 				contributor.renderHead(component, response);
 			}
 		}
-
-		List<JavaScriptPrecondition> preconditions = attributes.getPreconditions();
-		for (JavaScriptPrecondition precondition : preconditions)
-		{
-			precondition.renderHead(component, response);
-		}
 	}
 
 	/**
@@ -147,31 +141,12 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	 * 
 	 * @param attributes
 	 */
-	private void updateAjaxAttributesBackwardCompatibility(AjaxRequestAttributes attributes)
+	private void updateAjaxAttributesBackwardCompatibility(final AjaxRequestAttributes attributes)
 	{
-		CharSequence preconditionScript = getPreconditionScript();
-		if (Strings.isEmpty(preconditionScript) == false)
-		{
-			JavaScriptPrecondition precondition = new JavaScriptPrecondition(preconditionScript);
-			attributes.getPreconditions().add(precondition);
-		}
-
-		AjaxCallListener backwardCompatibleAjaxCallListener = new AjaxCallListener()
-		{
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public CharSequence getSuccessHandler(Component component)
-			{
-				return AbstractDefaultAjaxBehavior.this.getSuccessScript();
-			}
-
-			@Override
-			public CharSequence getFailureHandler(Component component)
-			{
-				return AbstractDefaultAjaxBehavior.this.getFailureScript();
-			}
-		};
+		AjaxCallListener backwardCompatibleAjaxCallListener = new AjaxCallListener();
+		backwardCompatibleAjaxCallListener.onSuccess(getSuccessScript());
+		backwardCompatibleAjaxCallListener.onFailure(getFailureScript());
+		backwardCompatibleAjaxCallListener.onPrecondition(getPreconditionScript());
 		attributes.getAjaxCallListeners().add(backwardCompatibleAjaxCallListener);
 
 		AjaxChannel channel = getChannel();
@@ -292,15 +267,12 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 					{
 						attributesJson.append("coh", completeHandler);
 					}
-				}
-			}
 
-			for (JavaScriptPrecondition pre : attributes.getPreconditions())
-			{
-				String precondition = pre.toString();
-				if (Strings.isEmpty(precondition) == false)
-				{
-					attributesJson.append("pre", precondition);
+					CharSequence precondition = ajaxCallListener.getPrecondition(component);
+					if (Strings.isEmpty(precondition) == false)
+					{
+						attributesJson.append("pre", precondition);
+					}
 				}
 			}
 
@@ -320,12 +292,12 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 				attributesJson.put("ep", extraParameters);
 			}
 
-			List<CharSequence> urlArgumentMethods = attributes.getDynamicExtraParameters();
-			if (urlArgumentMethods != null)
+			List<CharSequence> dynamicExtraParameters = attributes.getDynamicExtraParameters();
+			if (dynamicExtraParameters != null)
 			{
-				for (CharSequence urlArgument : urlArgumentMethods)
+				for (CharSequence dynamicExtraParameter : dynamicExtraParameters)
 				{
-					attributesJson.append("dep", urlArgument);
+					attributesJson.append("dep", dynamicExtraParameter);
 				}
 			}
 
@@ -358,10 +330,10 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 				attributesJson.put("ad", true);
 			}
 
-			Integer requestTimeout = attributes.getRequestTimeout();
+			Duration requestTimeout = attributes.getRequestTimeout();
 			if (requestTimeout != null)
 			{
-				attributesJson.put("rt", requestTimeout);
+				attributesJson.put("rt", requestTimeout.getMilliseconds());
 			}
 
 			boolean wicketAjaxResponse = attributes.isWicketAjaxResponse();

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxCallListener.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxCallListener.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxCallListener.java
index d98bf6f..c69a1dc 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxCallListener.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxCallListener.java
@@ -17,41 +17,141 @@
 package org.apache.wicket.ajax.attributes;
 
 import org.apache.wicket.Component;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.html.IComponentAwareHeaderContributor;
+import org.apache.wicket.util.string.Strings;
 
 /**
  * An adapter for implementations of IAjaxCallListener.
  *
  * @since 6.0
  */
-public class AjaxCallListener implements IAjaxCallListener
+public class AjaxCallListener implements IAjaxCallListener, IComponentAwareHeaderContributor
 {
+	private StringBuilder success;
+	private StringBuilder failure;
+	private StringBuilder before;
+	private StringBuilder after;
+	private StringBuilder complete;
+	private StringBuilder precondition;
+
+	public AjaxCallListener onBefore(final CharSequence before)
+	{
+		if (Strings.isEmpty(before) == false)
+		{
+			if (this.before == null)
+			{
+				this.before = new StringBuilder();
+			}
+			this.before.append(before);
+		}
+		return this;
+	}
+
+	public AjaxCallListener onAfter(final CharSequence after)
+	{
+		if (Strings.isEmpty(after) == false)
+		{
+			if (this.after == null)
+			{
+				this.after = new StringBuilder();
+			}
+			this.after.append(after);
+		}
+		return this;
+	}
+
+	public AjaxCallListener onSuccess(final CharSequence success)
+	{
+		if (Strings.isEmpty(success) == false)
+		{
+			if (this.success == null)
+			{
+				this.success = new StringBuilder();
+			}
+			this.success.append(success);
+		}
+		return this;
+	}
+
+
+	public AjaxCallListener onFailure(final CharSequence failure)
+	{
+		if (Strings.isEmpty(failure) == false)
+		{
+			if (this.failure == null)
+			{
+				this.failure = new StringBuilder();
+			}
+			this.failure.append(failure);
+		}
+		return this;
+	}
+
+	public AjaxCallListener onComplete(final CharSequence complete)
+	{
+		if (Strings.isEmpty(complete) == false)
+		{
+			if (this.complete == null)
+			{
+				this.complete = new StringBuilder();
+			}
+			this.complete.append(complete);
+		}
+		return this;
+	}
+
+	public AjaxCallListener onPrecondition(final CharSequence precondition)
+	{
+		if (Strings.isEmpty(precondition) == false)
+		{
+			if (this.precondition == null)
+			{
+				this.precondition = new StringBuilder();
+			}
+			this.precondition.append(precondition);
+		}
+		return this;
+	}
+
 	@Override
 	public CharSequence getSuccessHandler(Component component)
 	{
-		return null;
+		return success;
 	}
 
 	@Override
 	public CharSequence getFailureHandler(Component component)
 	{
-		return null;
+		return failure;
 	}
 
 	@Override
 	public CharSequence getBeforeHandler(Component component)
 	{
-		return null;
+		return before;
 	}
 
 	@Override
 	public CharSequence getAfterHandler(Component component)
 	{
-		return null;
+		return after;
 	}
 
 	@Override
 	public CharSequence getCompleteHandler(Component component)
 	{
-		return null;
+		return complete;
+	}
+
+	@Override
+	public CharSequence getPrecondition(Component component)
+	{
+		return precondition;
+	}
+
+	@Override
+	public void renderHead(Component component, IHeaderResponse response)
+	{
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxRequestAttributes.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxRequestAttributes.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxRequestAttributes.java
index d15e653..b9cdb02 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxRequestAttributes.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/AjaxRequestAttributes.java
@@ -23,12 +23,11 @@ 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.
  * 
- * <hr>
- *
  * @author Matej Knopp
  */
 public final class AjaxRequestAttributes
@@ -54,8 +53,11 @@ public final class AjaxRequestAttributes
 	public static final String XML_DATA_TYPE = "xml";
 
 	private boolean multipart = false;
+
 	private Method method = Method.GET;
-	private Integer requestTimeout;
+
+	private Duration requestTimeout;
+
 	private boolean allowDefault = false;
 
 	/**
@@ -83,9 +85,11 @@ public final class AjaxRequestAttributes
 	private String dataType = XML_DATA_TYPE;
 
 	private List<IAjaxCallListener> ajaxCallListeners;
-	private List<JavaScriptPrecondition> preconditions;
+
 	private Map<String, Object> extraParameters;
+
 	private List<CharSequence> dynamicExtraParameters;
+
 	private AjaxChannel channel;
 
 	/**
@@ -136,13 +140,12 @@ public final class AjaxRequestAttributes
 	}
 
 	/**
-	 * Returns whether the Ajax request should be a <code>POST</code> regardless of whether a form
-	 * is being submitted.
+	 * 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 <code>true</code> if the request should be post, <code>false</code> otherwise.
+	 * @return the type of the Ajax request. Default: {@linkplain Method#GET}
 	 */
 	public Method getMethod()
 	{
@@ -150,16 +153,16 @@ public final class AjaxRequestAttributes
 	}
 
 	/**
-	 * Determines whether the Ajax request should be a <code>POST</code> regardless of whether a
-	 * form is being submitted.
+	 * 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
-	 * @return this object
+	 *      the type of the Ajax request
+	 * @return {@code this} object for chaining
 	 */
-	public AjaxRequestAttributes setMethod(Method method)
+	public AjaxRequestAttributes setMethod(final Method method)
 	{
 		this.method = Args.notNull(method, "method");
 		return this;
@@ -170,9 +173,9 @@ public final class AjaxRequestAttributes
 	 * communication and not the processing afterwards. Can be <code>null</code> in which case the
 	 * default request timeout will be used.
 	 * 
-	 * @return request timeout in milliseconds or <code>null<code> for default timeout
+	 * @return request timeout or <code>null<code> for default timeout. Default: no timeout.
 	 */
-	public Integer getRequestTimeout()
+	public Duration getRequestTimeout()
 	{
 		return requestTimeout;
 	}
@@ -185,70 +188,15 @@ public final class AjaxRequestAttributes
 	 * @param requestTimeout
 	 * @return this object
 	 */
-	public AjaxRequestAttributes setRequestTimeout(Integer requestTimeout)
+	public AjaxRequestAttributes setRequestTimeout(final Duration requestTimeout)
 	{
 		this.requestTimeout = requestTimeout;
 		return this;
 	}
 
 	/**
-	 * Array of javascript functions that are invoked before the request executes. The functions
-	 * will get a <code>RequestQueueItem</code> instance passed as fist argument and have to return
-	 * a boolean value. If any of these functions returns <code>false</code> the request is
-	 * canceled.
-	 * <p>
-	 * Example of single function:
-	 * 
-	 * <pre>
-	 *    function(requestQueueItem) 
-	 *    { 
-	 *      if (someCondition()) 
-	 *      {
-	 *         return true; 
-	 *      } 
-	 *      else 
-	 *      {
-	 *         return false;
-	 *      }
-	 *    }
-	 * </pre>
-	 * 
-	 * Preconditions can also be asynchronous (with the rest of the queue waiting until precondition
-	 * finishes). An example of asynchronous precondition:
-	 * 
-	 * <pre>
-	 *    function(requestQueueItem, makeAsync, asyncReturn) 
-	 *    { 
-	 *      makeAsync(); // let the queue know that this precondition is asynchronous
-	 *      var f = function()
-	 *      {
-	 *        if (someCondition())
-	 *        {
-	 *          asyncReturn(true); // return the precondition value
-	 *        }
-	 *        else
-	 *        {
-	 *          asyncReturn(false); // return the precondition value
-	 *        }
-	 *      };
-	 *      window.setTimeout(f, 1000); // postpone the actual check 1000 millisecond. The queue will wait.
-	 *    }
-	 * </pre>
-	 * 
-	 * @return List<JavaScriptPrecondition>
-	 */
-	public List<JavaScriptPrecondition> getPreconditions()
-	{
-		if (preconditions == null)
-		{
-			preconditions = new ArrayList<JavaScriptPrecondition>();
-		}
-		return preconditions;
-	}
-
-	/**
-	 *
-	 * @return List<IAjaxCallListener>
+	 * @return a list of {@link IAjaxCallListener}s which will be notified during the
+	 *  the execution of the Ajax call.
 	 */
 	public List<IAjaxCallListener> getAjaxCallListeners()
 	{
@@ -263,7 +211,7 @@ public final class AjaxRequestAttributes
 	 * Map that contains additional (static) URL parameters. These will be appended to the request
 	 * URL. This is simpler alternative to {@link #getDynamicExtraParameters()}
 	 * 
-	 * @return Map with additional URL arguments
+	 * @return a map with additional URL arguments
 	 */
 	public Map<String, Object> getExtraParameters()
 	{
@@ -275,18 +223,33 @@ public final class AjaxRequestAttributes
 	}
 
 	/**
-	 * Array of JavaScript functions that produce additional URL arguments. Each of the functions
-	 * must return a <code>Map&lt;String, String&gt;</code> (Object).
-	 * <p>
-	 * Example of single function:
-	 * 
+	 * 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>
-	 *    function()
-	 *    {
-	 *    	return { 'param1': document.body.tagName }
-	 *    }
+	 *  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.
 	 */
 	public List<CharSequence> getDynamicExtraParameters()
@@ -302,10 +265,11 @@ public final class AjaxRequestAttributes
 	 * Only applies for event behaviors. Returns whether the behavior should allow the default event
 	 * handler to be invoked. For example if the behavior is attached to a link and
 	 * {@link #isAllowDefault()} returns <code>false</code> (which is default value), the link's URL
-	 * will not be followed. If {@link #isAllowDefault()} returns <code>true</code>, the link URL
-	 * will be loaded (and the onclick handler fired if there is any).
+	 * 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>true</code>.
 	 * 
-	 * @return <code>true</code> if the default event handler should be invoked, <code>false</code>
+	 * @return {@code true} if the default event handler should be invoked, {@code false}
 	 *         otherwise.
 	 */
 	public boolean isAllowDefault()
@@ -320,7 +284,8 @@ public final class AjaxRequestAttributes
 	 * @see #isAllowDefault()
 	 * 
 	 * @param allowDefault
-	 * @return this object
+	 * @return {@code this} object for chaining
+	 * @see #isAllowDefault()
 	 */
 	public AjaxRequestAttributes setAllowDefault(boolean allowDefault)
 	{
@@ -331,7 +296,7 @@ public final class AjaxRequestAttributes
 	/**
 	 * @param async
 	 *            a flag whether to do asynchronous Ajax call or not
-	 * @return this object
+	 * @return {@code this} object for chaining
 	 */
 	public AjaxRequestAttributes setAsynchronous(final boolean async)
 	{
@@ -357,16 +322,18 @@ public final class AjaxRequestAttributes
 
 	/**
 	 * @param channel
-	 * @return this object
+	 *      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(AjaxChannel channel)
+	public AjaxRequestAttributes setChannel(final AjaxChannel channel)
 	{
 		this.channel = channel;
 		return this;
 	}
 
 	/**
-	 * @return the name of the event that will trigger the Ajax call
+	 * @return the name(s) of the event(s) which will trigger the Ajax call
 	 */
 	public String[] getEventNames()
 	{
@@ -376,7 +343,7 @@ public final class AjaxRequestAttributes
 	/**
 	 * @param eventNames
 	 *            the names of the events which will trigger the Ajax call
-	 * @return this object
+	 * @return {@code this} object for chaining
 	 */
 	public AjaxRequestAttributes setEventNames(String... eventNames)
 	{
@@ -396,16 +363,16 @@ public final class AjaxRequestAttributes
 	/**
 	 * @param formId
 	 *            the id of the for that should be submitted
-	 * @return this object
+	 * @return {@code this} object for chaining
 	 */
-	public AjaxRequestAttributes setFormId(String formId)
+	public AjaxRequestAttributes setFormId(final String formId)
 	{
 		this.formId = formId;
 		return this;
 	}
 
 	/**
-	 * @return the input name of the button/link that submitted the form
+	 * @return the input name of the button/link that submits the form
 	 */
 	public String getSubmittingComponentName()
 	{
@@ -414,8 +381,8 @@ public final class AjaxRequestAttributes
 
 	/**
 	 * @param submittingComponentName
-	 *            the input name of the button/link that submitted the form
-	 * @return this object
+	 *            the input name of the button/link that submits the form
+	 * @return {@code this} object for chaining
 	 */
 	public AjaxRequestAttributes setSubmittingComponentName(String submittingComponentName)
 	{
@@ -424,25 +391,31 @@ public final class AjaxRequestAttributes
 	}
 
 	/**
-	 * @return
+	 * @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()
+	public boolean isWicketAjaxResponse()
 	{
 		return wicketAjaxResponse;
 	}
 
 	/**
 	 * @param wicketAjaxResponse
-	 * @return this object
+	 *      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(Boolean wicketAjaxResponse)
+	public AjaxRequestAttributes setWicketAjaxResponse(final boolean wicketAjaxResponse)
 	{
 		this.wicketAjaxResponse = wicketAjaxResponse;
 		return this;
 	}
 
 	/**
-	 * @return
+	 * 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()
 	{
@@ -451,11 +424,12 @@ public final class AjaxRequestAttributes
 
 	/**
 	 * @param dataType
-	 * @return
+	 *      the type of the data in the Ajax response.
+	 * @return {@code this} object for chaining
 	 */
-	public AjaxRequestAttributes setDataType(String dataType)
+	public AjaxRequestAttributes setDataType(final String dataType)
 	{
-		this.dataType = dataType;
+		this.dataType = Args.notEmpty(dataType, "dataType");
 		return this;
 	}
 
@@ -470,7 +444,7 @@ public final class AjaxRequestAttributes
 	/**
 	 * @param throttlingSettings
 	 *      the settings to use when throttling is needed. Pass {@code null} to disable throttling.
-	 * @return this object
+	 * @return {@code this} object for chaining
 	 */
 	public AjaxRequestAttributes setThrottlingSettings(ThrottlingSettings throttlingSettings)
 	{

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/IAjaxCallListener.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/IAjaxCallListener.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/IAjaxCallListener.java
index 7750715..5fef9fa 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/IAjaxCallListener.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/IAjaxCallListener.java
@@ -17,7 +17,6 @@
 package org.apache.wicket.ajax.attributes;
 
 import org.apache.wicket.Component;
-import org.apache.wicket.util.io.IClusterable;
 
 /**
  * Interface used to listen at the most important points when Wicket performs an Ajax callback.
@@ -30,7 +29,7 @@ import org.apache.wicket.util.io.IClusterable;
  *
  * @since 6.0
  */
-public interface IAjaxCallListener extends IClusterable
+public interface IAjaxCallListener
 {
 	/**
 	 * The JavaScript that will be executed after successful return of the Ajax call.
@@ -109,4 +108,13 @@ public interface IAjaxCallListener extends IClusterable
 	 *      and unsuccessful return of the Ajax call.
 	 */
 	CharSequence getCompleteHandler(Component component);
+
+	/**
+	 * A JavaScript function that is invoked before the request executes.
+	 * If it returns {@code false} then the execution of the Ajax call will
+	 * be cancelled.
+	 *
+	 * @return
+	 */
+	CharSequence getPrecondition(Component component);
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptAfterHandler.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptAfterHandler.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptAfterHandler.java
deleted file mode 100644
index c953df6..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptAfterHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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;
-
-/**
- *
- */
-public class JavaScriptAfterHandler extends JavaScriptFunctionBody
-{
-	/**
-	 * Constructor.
-	 *
-	 * @param functionBody
-	 */
-	public JavaScriptAfterHandler(final CharSequence functionBody)
-	{
-		super(functionBody);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptBeforeHandler.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptBeforeHandler.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptBeforeHandler.java
deleted file mode 100644
index 4df4b78..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptBeforeHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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;
-
-/**
- *
- */
-public class JavaScriptBeforeHandler extends JavaScriptFunctionBody
-{
-	/**
-	 * Constructor.
-	 *
-	 * @param functionBody
-	 */
-	public JavaScriptBeforeHandler(final CharSequence functionBody)
-	{
-		super(functionBody);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFailureHandler.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFailureHandler.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFailureHandler.java
deleted file mode 100644
index a580ac5..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFailureHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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;
-
-/**
- *
- */
-public class JavaScriptFailureHandler extends JavaScriptFunctionBody
-{
-	/**
-	 * Constructor.
-	 *
-	 * @param functionBody
-	 */
-	public JavaScriptFailureHandler(final CharSequence functionBody)
-	{
-		super(functionBody);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFunctionBody.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFunctionBody.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFunctionBody.java
deleted file mode 100644
index 4e7fcc4..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptFunctionBody.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 org.apache.wicket.Component;
-import org.apache.wicket.util.io.IClusterable;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.html.IComponentAwareHeaderContributor;
-
-/**
- * A base class for classes which contribute one way or another JavaScript
- * to the AjaxRequestAttributes.
- * Such classes can contribute to the header response by overriding #renderHead(Component, IHeaderResponse)
- * method.
- */
-public class JavaScriptFunctionBody implements IComponentAwareHeaderContributor, IClusterable
-{
-	private final CharSequence functionBody;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param functionBody
-	 *      the body of JavaScript function which will be evaluated in the browser
-	 */
-	public JavaScriptFunctionBody(final CharSequence functionBody)
-	{
-		this.functionBody = functionBody;
-	}
-
-	@Override
-	public String toString()
-	{
-		return functionBody.toString();
-	}
-
-	@Override
-	public void renderHead(Component component, IHeaderResponse response)
-	{
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptPrecondition.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptPrecondition.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptPrecondition.java
deleted file mode 100644
index 3ac6266..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptPrecondition.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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;
-
-/**
- * The JavaScript that will be executed before the Ajax call and will decide whether the Ajax
- * should be aborted.
- * The script will be executed in a function that receives the following parameters:
- * <ol>
- *     <li>attrs - the AjaxRequestAttributes as JSON</li>
- *     <li>jqXHR - the jQuery XMLHttpRequest object</li>
- *     <li>settings - the settings used for the jQuery.ajax() call</li>
- * </ol>
- */
-public class JavaScriptPrecondition extends JavaScriptFunctionBody
-{
-	/**
-	 * Constructor.
-	 *
-	 * @param functionBody
-	 */
-	public JavaScriptPrecondition(final CharSequence functionBody)
-	{
-		super(functionBody);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptSuccessHandler.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptSuccessHandler.java b/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptSuccessHandler.java
deleted file mode 100644
index 7628d05..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/attributes/JavaScriptSuccessHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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;
-
-/**
- *
- */
-public class JavaScriptSuccessHandler extends JavaScriptFunctionBody
-{
-	/**
-	 * Constructor.
-	 *
-	 * @param functionBody
-	 */
-	public JavaScriptSuccessHandler(final CharSequence functionBody)
-	{
-		super(functionBody);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-core/src/main/java/org/apache/wicket/markup/html/IComponentAwareHeaderContributor.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/IComponentAwareHeaderContributor.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/IComponentAwareHeaderContributor.java
index 0282dda..9f12ee4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/IComponentAwareHeaderContributor.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/IComponentAwareHeaderContributor.java
@@ -22,14 +22,12 @@ import org.apache.wicket.util.io.IClusterable;
 
 /**
  * An interface to be implemented by {@link org.apache.wicket.behavior.Behavior}s,
- * {@link org.apache.wicket.ajax.attributes.IAjaxCallListener}s or
- * {@link org.apache.wicket.ajax.attributes.JavaScriptFunctionBody}s which wish to
- * contribute to the header section of the page.
+ * {@link org.apache.wicket.ajax.attributes.IAjaxCallListener}s.
  * 
  * Example:
  * 
  * <pre>
- * class MyAjaxCallDecorator implements IAjaxCallListener, IHeaderContributor
+ * class MyAjaxCallDecorator implements IAjaxCallListener, IComponentAwareHeaderContributor
  * {
  *
  *  // IAjaxCallListener methods omitted for brevity

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LinksPage.java
----------------------------------------------------------------------
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LinksPage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LinksPage.java
index c3b637d..3055038 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LinksPage.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LinksPage.java
@@ -166,8 +166,6 @@ public class LinksPage extends BasePage
 				List<CharSequence> urlArgumentMethods = attributes.getDynamicExtraParameters();
 				urlArgumentMethods.add("return {'htmlname': document.documentElement.tagName};");
 				urlArgumentMethods.add("return {'bodyname': document.body.tagName};");
-
-// attributes.getPreconditions().add(0, "return false;");
 			}
 		});
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
----------------------------------------------------------------------
diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
index bb2d60e..b1c5493 100644
--- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
@@ -23,8 +23,9 @@ import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
 import org.apache.wicket.ajax.AjaxEventBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxCallListener;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
-import org.apache.wicket.ajax.attributes.JavaScriptPrecondition;
+import org.apache.wicket.core.util.string.JavaScriptUtils;
 import org.apache.wicket.feedback.FeedbackMessage;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupStream;
@@ -37,7 +38,6 @@ import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.IObjectClassAwareModel;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.util.convert.IConverter;
-import org.apache.wicket.core.util.string.JavaScriptUtils;
 import org.apache.wicket.validation.IValidator;
 
 /**
@@ -331,9 +331,9 @@ public class AjaxEditableLabel<T> extends Panel
 					+ "ret=false;"
 					+ "if(evtType==='blur' || (evtType==='keyup' && (kc===27 || kc===13))) ret = true;"
 					+ "return ret;";
-				JavaScriptPrecondition javaScriptPrecondition = new JavaScriptPrecondition(
-					precondition);
-				attributes.getPreconditions().add(javaScriptPrecondition);
+				AjaxCallListener ajaxCallListener = new AjaxCallListener();
+				ajaxCallListener.onPrecondition(precondition);
+				attributes.getAjaxCallListeners().add(ajaxCallListener);
 
 			}
 		});

http://git-wip-us.apache.org/repos/asf/wicket/blob/06d225ee/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableMultiLineLabel.java
----------------------------------------------------------------------
diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableMultiLineLabel.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableMultiLineLabel.java
index ceeb91b..541b248 100644
--- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableMultiLineLabel.java
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableMultiLineLabel.java
@@ -16,13 +16,11 @@
  */
 package org.apache.wicket.extensions.ajax.markup.html;
 
-import java.util.List;
-
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.attributes.AjaxCallListener;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes.Method;
-import org.apache.wicket.ajax.attributes.JavaScriptPrecondition;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.html.basic.MultiLineLabel;
@@ -181,7 +179,7 @@ public class AjaxEditableMultiLineLabel<T> extends AjaxEditableLabel<T>
 				super.updateAjaxAttributes(attributes);
 				attributes.setMethod(Method.POST);
 				attributes.setEventNames("blur", "keyup");
-				CharSequence dynamicExtraParameters =
+				CharSequence dynamicExtraParameters = 
 						"var result = [], " +
 								"kc=Wicket.Event.keyCode(event)," +
 								"evtType=attrs.event.type;" +
@@ -191,8 +189,7 @@ public class AjaxEditableMultiLineLabel<T> extends AjaxEditableLabel<T>
 								"}" +
 								"else if (evtType==='blur') { result = Wicket.Form.serializeElement(attrs.c); result.push( { name: 'save', value: true } ); }" +
 								"return result;";
-				List<CharSequence> dynamicParameters = attributes.getDynamicExtraParameters();
-				dynamicParameters.add(dynamicExtraParameters);
+				attributes.getDynamicExtraParameters().add(dynamicExtraParameters);
 
 				CharSequence precondition =
 						"var kc=Wicket.Event.keyCode(event),"+
@@ -200,9 +197,9 @@ public class AjaxEditableMultiLineLabel<T> extends AjaxEditableLabel<T>
 								"ret=false;"+
 								"if(evtType==='blur' || (evtType==='keyup' && (kc===27))) ret = true;"+
 								"return ret;";
-				JavaScriptPrecondition javaScriptPrecondition = new JavaScriptPrecondition(precondition);
-				List<JavaScriptPrecondition> preconditions = attributes.getPreconditions();
-				preconditions.add(javaScriptPrecondition);
+				AjaxCallListener ajaxCallListener = new AjaxCallListener();
+				ajaxCallListener.onPrecondition(precondition);
+				attributes.getAjaxCallListeners().add(ajaxCallListener);
 			}
 		});
 		return editor;