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 2013/08/01 17:32:28 UTC

git commit: WICKET-5299 Extract the main logic for Wicket Ajax functionality in a replaceable strategy

Updated Branches:
  refs/heads/5299-ajax-strategy [created] 30603f4aa


WICKET-5299 Extract the main logic for Wicket Ajax functionality in a replaceable strategy


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

Branch: refs/heads/5299-ajax-strategy
Commit: 30603f4aa882dc0d80ed3e29c844ef6c104c522b
Parents: 3b288e3
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Thu Aug 1 17:31:30 2013 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Thu Aug 1 17:31:30 2013 +0200

----------------------------------------------------------------------
 .../java/org/apache/wicket/Application.java     |   2 +-
 .../ajax/AbstractDefaultAjaxBehavior.java       | 320 +++---------------
 .../apache/wicket/ajax/AjaxEventBehavior.java   |  15 +-
 .../wicket/ajax/strategies/IAjaxStrategy.java   |  42 +++
 .../ajax/strategies/Wicket6AjaxStrategy.java    | 326 +++++++++++++++++++
 .../ajax/strategies/Wicket7AjaxStrategy.java    |  69 ++++
 .../wicket/protocol/http/WebApplication.java    |  27 ++
 .../apache/wicket/settings/IAjaxSettings.java   |  13 +
 .../wicket/settings/def/AjaxSettings.java       |  31 ++
 9 files changed, 562 insertions(+), 283 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/Application.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/Application.java b/wicket-core/src/main/java/org/apache/wicket/Application.java
index 5cbbdde..c80ae85 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Application.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Application.java
@@ -1330,7 +1330,7 @@ public abstract class Application implements UnboundListener, IEventSink
 	/**
 	 *
 	 */
-	private void checkSettingsAvailable()
+	protected final void checkSettingsAvailable()
 	{
 		if (!settingsAccessible)
 		{

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/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 85f950c..dc79c85 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
@@ -19,19 +19,13 @@ package org.apache.wicket.ajax;
 import java.util.List;
 
 import org.apache.wicket.Component;
-import org.apache.wicket.Page;
-import org.apache.wicket.WicketRuntimeException;
-import org.apache.wicket.ajax.attributes.AjaxAttributeName;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
-import org.apache.wicket.ajax.attributes.AjaxRequestAttributes.Method;
 import org.apache.wicket.ajax.attributes.CallbackParameter;
 import org.apache.wicket.ajax.attributes.IAjaxCallListener;
-import org.apache.wicket.ajax.attributes.ThrottlingSettings;
-import org.apache.wicket.ajax.json.JSONArray;
 import org.apache.wicket.ajax.json.JSONException;
 import org.apache.wicket.ajax.json.JSONObject;
-import org.apache.wicket.ajax.json.JsonFunction;
-import org.apache.wicket.ajax.json.JsonUtils;
+import org.apache.wicket.ajax.strategies.IAjaxStrategy;
+import org.apache.wicket.ajax.strategies.Wicket7AjaxStrategy;
 import org.apache.wicket.behavior.AbstractAjaxBehavior;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
@@ -43,7 +37,6 @@ 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.
@@ -62,15 +55,6 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	public static final ResourceReference INDICATOR = new PackageResourceReference(
 		AbstractDefaultAjaxBehavior.class, "indicator.gif");
 
-	private static final String DYNAMIC_PARAMETER_FUNCTION_TEMPLATE = "function(attrs){%s}";
-	private static final String PRECONDITION_FUNCTION_TEMPLATE = "function(attrs){%s}";
-	private static final String COMPLETE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, textStatus){%s}";
-	private static final String FAILURE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, errorMessage, textStatus){%s}";
-	private static final String SUCCESS_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, data, textStatus){%s}";
-	private static final String AFTER_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}";
-	private static final String BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, settings){%s}";
-	private static final String BEFORE_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}";
-
 	/**
 	 * Subclasses should call super.onBind()
 	 * 
@@ -183,220 +167,32 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 		return renderAjaxAttributes(component, attributes);
 	}
 
+	public final CharSequence renderAjaxAttributes()
+	{
+		AjaxRequestAttributes attributes = getAttributes();
+		return renderAjaxAttributes(getComponent(), attributes);
+	}
+
 	/**
 	 * 
 	 * @param component
 	 * @param attributes
 	 * @return the attributes as string in JSON format
 	 */
-	protected final CharSequence renderAjaxAttributes(final Component component,
-		AjaxRequestAttributes attributes)
+	protected final JSONObject getAjaxAttributes(final Component component, AjaxRequestAttributes attributes)
 	{
-		JSONObject attributesJson = new JSONObject();
-
-		try
-		{
-			attributesJson.put(AjaxAttributeName.URL.jsonName(), getCallbackUrl());
-			Method method = attributes.getMethod();
-			if (Method.POST == method)
-			{
-				attributesJson.put(AjaxAttributeName.METHOD.jsonName(), method);
-			}
-
-			if (component instanceof Page == false)
-			{
-				String componentId = component.getMarkupId();
-				attributesJson.put(AjaxAttributeName.MARKUP_ID.jsonName(), componentId);
-			}
-
-			String formId = attributes.getFormId();
-			if (Strings.isEmpty(formId) == false)
-			{
-				attributesJson.put(AjaxAttributeName.FORM_ID.jsonName(), formId);
-			}
-
-			if (attributes.isMultipart())
-			{
-				attributesJson.put(AjaxAttributeName.IS_MULTIPART.jsonName(), true);
-			}
-
-			String submittingComponentId = attributes.getSubmittingComponentName();
-			if (Strings.isEmpty(submittingComponentId) == false)
-			{
-				attributesJson.put(AjaxAttributeName.SUBMITTING_COMPONENT_NAME.jsonName(),
-					submittingComponentId);
-			}
-
-			String indicatorId = findIndicatorId();
-			if (Strings.isEmpty(indicatorId) == false)
-			{
-				attributesJson.put(AjaxAttributeName.INDICATOR_ID.jsonName(), indicatorId);
-			}
-
-			for (IAjaxCallListener ajaxCallListener : attributes.getAjaxCallListeners())
-			{
-				if (ajaxCallListener != null)
-				{
-					CharSequence beforeHandler = ajaxCallListener.getBeforeHandler(component);
-					appendListenerHandler(beforeHandler, attributesJson,
-						AjaxAttributeName.BEFORE_HANDLER.jsonName(),
-						BEFORE_HANDLER_FUNCTION_TEMPLATE);
-
-					CharSequence beforeSendHandler = ajaxCallListener
-						.getBeforeSendHandler(component);
-					appendListenerHandler(beforeSendHandler, attributesJson,
-						AjaxAttributeName.BEFORE_SEND_HANDLER.jsonName(),
-						BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE);
-
-					CharSequence afterHandler = ajaxCallListener.getAfterHandler(component);
-					appendListenerHandler(afterHandler, attributesJson,
-						AjaxAttributeName.AFTER_HANDLER.jsonName(), AFTER_HANDLER_FUNCTION_TEMPLATE);
-
-					CharSequence successHandler = ajaxCallListener.getSuccessHandler(component);
-					appendListenerHandler(successHandler, attributesJson,
-						AjaxAttributeName.SUCCESS_HANDLER.jsonName(),
-						SUCCESS_HANDLER_FUNCTION_TEMPLATE);
-
-					CharSequence failureHandler = ajaxCallListener.getFailureHandler(component);
-					appendListenerHandler(failureHandler, attributesJson,
-						AjaxAttributeName.FAILURE_HANDLER.jsonName(),
-						FAILURE_HANDLER_FUNCTION_TEMPLATE);
-
-					CharSequence completeHandler = ajaxCallListener.getCompleteHandler(component);
-					appendListenerHandler(completeHandler, attributesJson,
-						AjaxAttributeName.COMPLETE_HANDLER.jsonName(),
-						COMPLETE_HANDLER_FUNCTION_TEMPLATE);
-
-					CharSequence precondition = ajaxCallListener.getPrecondition(component);
-					appendListenerHandler(precondition, attributesJson,
-						AjaxAttributeName.PRECONDITION.jsonName(), PRECONDITION_FUNCTION_TEMPLATE);
-				}
-			}
-
-			JSONArray extraParameters = JsonUtils.asArray(attributes.getExtraParameters());
-
-			if (extraParameters.length() > 0)
-			{
-				attributesJson.put(AjaxAttributeName.EXTRA_PARAMETERS.jsonName(), extraParameters);
-			}
-
-			List<CharSequence> dynamicExtraParameters = attributes.getDynamicExtraParameters();
-			if (dynamicExtraParameters != null)
-			{
-				for (CharSequence dynamicExtraParameter : dynamicExtraParameters)
-				{
-					String func = String.format(DYNAMIC_PARAMETER_FUNCTION_TEMPLATE,
-						dynamicExtraParameter);
-					JsonFunction function = new JsonFunction(func);
-					attributesJson.append(AjaxAttributeName.DYNAMIC_PARAMETER_FUNCTION.jsonName(),
-						function);
-				}
-			}
-
-			if (attributes.isAsynchronous() == false)
-			{
-				attributesJson.put(AjaxAttributeName.IS_ASYNC.jsonName(), false);
-			}
-
-			String[] eventNames = attributes.getEventNames();
-			if (eventNames.length == 1)
-			{
-				attributesJson.put(AjaxAttributeName.EVENT_NAME.jsonName(), eventNames[0]);
-			}
-			else
-			{
-				for (String eventName : eventNames)
-				{
-					attributesJson.append(AjaxAttributeName.EVENT_NAME.jsonName(), eventName);
-				}
-			}
-
-			AjaxChannel channel = attributes.getChannel();
-			if (channel != null)
-			{
-				attributesJson.put(AjaxAttributeName.CHANNEL.jsonName(), channel);
-			}
-
-			if (attributes.isPreventDefault())
-			{
-				attributesJson.put(AjaxAttributeName.IS_PREVENT_DEFAULT.jsonName(), true);
-			}
-
-			if (AjaxRequestAttributes.EventPropagation.STOP
-				.equals(attributes.getEventPropagation()))
-			{
-				attributesJson.put(AjaxAttributeName.EVENT_PROPAGATION.jsonName(), "stop");
-			}
-			else if (AjaxRequestAttributes.EventPropagation.STOP_IMMEDIATE.equals(attributes
-				.getEventPropagation()))
-			{
-				attributesJson.put(AjaxAttributeName.EVENT_PROPAGATION.jsonName(), "stopImmediate");
-			}
-
-			Duration requestTimeout = attributes.getRequestTimeout();
-			if (requestTimeout != null)
-			{
-				attributesJson.put(AjaxAttributeName.REQUEST_TIMEOUT.jsonName(),
-					requestTimeout.getMilliseconds());
-			}
-
-			boolean wicketAjaxResponse = attributes.isWicketAjaxResponse();
-			if (wicketAjaxResponse == false)
-			{
-				attributesJson.put(AjaxAttributeName.IS_WICKET_AJAX_RESPONSE.jsonName(), false);
-			}
-
-			String dataType = attributes.getDataType();
-			if (AjaxRequestAttributes.XML_DATA_TYPE.equals(dataType) == false)
-			{
-				attributesJson.put(AjaxAttributeName.DATATYPE.jsonName(), dataType);
-			}
-
-			ThrottlingSettings throttlingSettings = attributes.getThrottlingSettings();
-			if (throttlingSettings != null)
-			{
-				JSONObject throttlingSettingsJson = new JSONObject();
-				throttlingSettingsJson.put(AjaxAttributeName.THROTTLING_ID.jsonName(),
-					throttlingSettings.getId());
-				throttlingSettingsJson.put(AjaxAttributeName.THROTTLING_DELAY.jsonName(),
-					throttlingSettings.getDelay().getMilliseconds());
-				if (throttlingSettings.getPostponeTimerOnUpdate())
-				{
-					throttlingSettingsJson.put(
-						AjaxAttributeName.THROTTLING_POSTPONE_ON_UPDATE.jsonName(), true);
-				}
-				attributesJson.put(AjaxAttributeName.THROTTLING.jsonName(), throttlingSettingsJson);
-			}
-
-			postprocessConfiguration(attributesJson, component);
-		}
-		catch (JSONException e)
-		{
-			throw new WicketRuntimeException(e);
-		}
-
-		String attributesAsJson = attributesJson.toString();
-
-		return attributesAsJson;
+		return getAjaxStrategy().getAjaxAttributes(this, component, attributes);
 	}
 
-	private void appendListenerHandler(final CharSequence handler, final JSONObject attributesJson,
-		final String propertyName, final String functionTemplate) throws JSONException
+	/**
+	 *
+	 * @param component
+	 * @param attributes
+	 * @return the attributes as string in JSON format
+	 */
+	protected final CharSequence renderAjaxAttributes(final Component component, AjaxRequestAttributes attributes)
 	{
-		if (Strings.isEmpty(handler) == false)
-		{
-			final JsonFunction function;
-			if (handler instanceof JsonFunction)
-			{
-				function = (JsonFunction)handler;
-			}
-			else
-			{
-				String func = String.format(functionTemplate, handler);
-				function = new JsonFunction(func);
-			}
-			attributesJson.append(propertyName, function);
-		}
+		return getAjaxAttributes(component, attributes).toString();
 	}
 
 	/**
@@ -404,13 +200,13 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	 * the Ajax call.
 	 * 
 	 * @param attributesJson
-	 *            the JSON object created by #renderAjaxAttributes()
+	 *            the JSON object created by #getAjaxAttributes()
 	 * @param component
 	 *            the component with the attached Ajax behavior
 	 * @throws JSONException
 	 *             thrown if an error occurs while modifying {@literal attributesJson} argument
 	 */
-	protected void postprocessConfiguration(JSONObject attributesJson, Component component)
+	public void postprocessConfiguration(JSONObject attributesJson, Component component)
 		throws JSONException
 	{
 	}
@@ -433,8 +229,9 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	// accept the component as parameter
 	protected CharSequence getCallbackScript(final Component component)
 	{
-		CharSequence ajaxAttributes = renderAjaxAttributes(component);
-		return "Wicket.Ajax.ajax(" + ajaxAttributes + ");";
+		AjaxRequestAttributes attributes = getAttributes();
+		JSONObject ajaxAttributes = getAjaxAttributes(component, attributes);
+		return getAjaxStrategy().getCallbackScript(component, ajaxAttributes);
 	}
 
 	/**
@@ -455,24 +252,7 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	 */
 	public CharSequence getCallbackFunction(CallbackParameter... extraParameters)
 	{
-		StringBuilder sb = new StringBuilder();
-		sb.append("function (");
-		boolean first = true;
-		for (CallbackParameter curExtraParameter : extraParameters)
-		{
-			if (curExtraParameter.getFunctionParameterName() != null)
-			{
-				if (!first)
-					sb.append(',');
-				else
-					first = false;
-				sb.append(curExtraParameter.getFunctionParameterName());
-			}
-		}
-		sb.append(") {\n");
-		sb.append(getCallbackFunctionBody(extraParameters));
-		sb.append("}\n");
-		return sb;
+		return getAjaxStrategy().getCallbackFunction(getAttributes(), extraParameters);
 	}
 
 	/**
@@ -486,39 +266,7 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	 */
 	public CharSequence getCallbackFunctionBody(CallbackParameter... extraParameters)
 	{
-		AjaxRequestAttributes attributes = getAttributes();
-		attributes.setEventNames();
-		CharSequence attrsJson = renderAjaxAttributes(getComponent(), attributes);
-		StringBuilder sb = new StringBuilder();
-		sb.append("var attrs = ");
-		sb.append(attrsJson);
-		sb.append(";\n");
-		sb.append("var params = {");
-		boolean first = true;
-		for (CallbackParameter curExtraParameter : extraParameters)
-		{
-			if (curExtraParameter.getAjaxParameterName() != null)
-			{
-				if (!first)
-					sb.append(',');
-				else
-					first = false;
-				sb.append('\'').append(curExtraParameter.getAjaxParameterName()).append("': ")
-					.append(curExtraParameter.getAjaxParameterCode());
-			}
-		}
-		sb.append("};\n");
-		if (attributes.getExtraParameters().isEmpty())
-		{
-			sb.append("attrs.").append(AjaxAttributeName.EXTRA_PARAMETERS).append(" = params;\n");
-		}
-		else
-		{
-			sb.append("attrs.").append(AjaxAttributeName.EXTRA_PARAMETERS).append(" = Wicket.merge(attrs.")
-					.append(AjaxAttributeName.EXTRA_PARAMETERS).append(", params);\n");
-		}
-		sb.append("Wicket.Ajax.ajax(attrs);\n");
-		return sb;
+		return getAjaxStrategy().getCallbackFunctionBody(getAttributes(), extraParameters);
 	}
 
 	/**
@@ -527,7 +275,9 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 	 * 
 	 * @return markup id or <code>null</code> if no indicator found
 	 */
-	protected String findIndicatorId()
+	// TODO: REVIEW: changed to public to be able to access it from IAjaxStrategy
+	// an option is to pass it as parameter to org.apache.wicket.ajax.strategies.IAjaxStrategy.getAjaxAttributes()
+	public String findIndicatorId()
 	{
 		if (getComponent() instanceof IAjaxIndicatorAware)
 		{
@@ -566,6 +316,20 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
 		respond(target);
 	}
 
+	protected IAjaxStrategy getAjaxStrategy()
+	{
+		IAjaxStrategy ajaxStrategy;
+		if (WebApplication.exists())
+		{
+			ajaxStrategy = WebApplication.get().getAjaxSettings().getAjaxStrategy();
+		}
+		else
+		{
+			ajaxStrategy = new Wicket7AjaxStrategy();
+		}
+		return ajaxStrategy;
+	}
+
 	/**
 	 * @param target
 	 *            The AJAX target

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxEventBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxEventBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxEventBehavior.java
index 0cee432..48e205b 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxEventBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxEventBehavior.java
@@ -18,8 +18,8 @@ package org.apache.wicket.ajax;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.util.lang.Args;
 
 /**
@@ -80,9 +80,7 @@ public abstract class AjaxEventBehavior extends AbstractDefaultAjaxBehavior
 
 		if (component.isEnabledInHierarchy())
 		{
-			CharSequence js = getCallbackScript(component);
-
-			response.render(OnDomReadyHeaderItem.forScript(js.toString()));
+			getAjaxStrategy().renderHead(this, response);
 		}
 	}
 
@@ -130,4 +128,13 @@ public abstract class AjaxEventBehavior extends AbstractDefaultAjaxBehavior
 	 *      the current request handler
 	 */
 	protected abstract void onEvent(final AjaxRequestTarget target);
+
+	@Override
+	protected void onComponentTag(ComponentTag tag)
+	{
+		super.onComponentTag(tag);
+
+		getAjaxStrategy().onComponentTag(this, tag);
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/IAjaxStrategy.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/IAjaxStrategy.java b/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/IAjaxStrategy.java
new file mode 100644
index 0000000..9ce584c
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/IAjaxStrategy.java
@@ -0,0 +1,42 @@
+package org.apache.wicket.ajax.strategies;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.ajax.attributes.CallbackParameter;
+import org.apache.wicket.ajax.json.JSONException;
+import org.apache.wicket.ajax.json.JSONObject;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.head.IHeaderResponse;
+
+/**
+ *
+ */
+public interface IAjaxStrategy
+{
+	final String DYNAMIC_PARAMETER_FUNCTION_TEMPLATE = "function(attrs){%s}";
+	final String PRECONDITION_FUNCTION_TEMPLATE = "function(attrs){%s}";
+	final String COMPLETE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, textStatus){%s}";
+	final String FAILURE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, errorMessage, textStatus){%s}";
+	final String SUCCESS_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, data, textStatus){%s}";
+	final String AFTER_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}";
+	final String BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, settings){%s}";
+	final String BEFORE_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}";
+
+	
+	void renderHead(final AjaxEventBehavior behavior, final IHeaderResponse response);
+
+	void onComponentTag(final AjaxEventBehavior behavior, final ComponentTag tag);
+
+	JSONObject getAjaxAttributes(AbstractDefaultAjaxBehavior behavior, Component component, AjaxRequestAttributes attributes);
+
+	void postprocessConfiguration(AbstractDefaultAjaxBehavior behavior, JSONObject attributesJson,
+	                              Component component) throws JSONException;
+
+	CharSequence getCallbackScript(final Component component, JSONObject ajaxAttributes);
+
+	CharSequence getCallbackFunction(AjaxRequestAttributes attributes, CallbackParameter... extraParameters);
+
+	CharSequence getCallbackFunctionBody(AjaxRequestAttributes attributes, CallbackParameter... extraParameters);
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket6AjaxStrategy.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket6AjaxStrategy.java b/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket6AjaxStrategy.java
new file mode 100644
index 0000000..6df17b0
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket6AjaxStrategy.java
@@ -0,0 +1,326 @@
+package org.apache.wicket.ajax.strategies;
+
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxChannel;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.attributes.AjaxAttributeName;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.ajax.attributes.CallbackParameter;
+import org.apache.wicket.ajax.attributes.IAjaxCallListener;
+import org.apache.wicket.ajax.attributes.ThrottlingSettings;
+import org.apache.wicket.ajax.json.JSONArray;
+import org.apache.wicket.ajax.json.JSONException;
+import org.apache.wicket.ajax.json.JSONObject;
+import org.apache.wicket.ajax.json.JsonFunction;
+import org.apache.wicket.ajax.json.JsonUtils;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.time.Duration;
+
+/**
+ *
+ */
+public class Wicket6AjaxStrategy implements IAjaxStrategy
+{
+	public void renderHead(final AjaxEventBehavior behavior, final IHeaderResponse response)
+	{
+		CharSequence js = behavior.getCallbackScript();
+
+		response.render(OnDomReadyHeaderItem.forScript(js.toString()));
+	}
+
+	public void onComponentTag(final AjaxEventBehavior behavior, final ComponentTag tag)
+	{
+	}
+
+	/**
+	 * @return the attributes as string in JSON format
+	 */
+	@Override
+	public final JSONObject getAjaxAttributes(AbstractDefaultAjaxBehavior behavior, Component component, AjaxRequestAttributes attributes)
+	{
+		JSONObject attributesJson = new JSONObject();
+
+		try
+		{
+			attributesJson.put(AjaxAttributeName.URL.jsonName(), behavior.getCallbackUrl());
+			AjaxRequestAttributes.Method method = attributes.getMethod();
+			if (AjaxRequestAttributes.Method.POST == method)
+			{
+				attributesJson.put(AjaxAttributeName.METHOD.jsonName(), method);
+			}
+
+			if (component instanceof Page == false)
+			{
+				String componentId = component.getMarkupId();
+				attributesJson.put(AjaxAttributeName.MARKUP_ID.jsonName(), componentId);
+			}
+
+			String formId = attributes.getFormId();
+			if (Strings.isEmpty(formId) == false)
+			{
+				attributesJson.put(AjaxAttributeName.FORM_ID.jsonName(), formId);
+			}
+
+			if (attributes.isMultipart())
+			{
+				attributesJson.put(AjaxAttributeName.IS_MULTIPART.jsonName(), true);
+			}
+
+			String submittingComponentId = attributes.getSubmittingComponentName();
+			if (Strings.isEmpty(submittingComponentId) == false)
+			{
+				attributesJson.put(AjaxAttributeName.SUBMITTING_COMPONENT_NAME.jsonName(),
+						submittingComponentId);
+			}
+
+			String indicatorId = behavior.findIndicatorId();
+			if (Strings.isEmpty(indicatorId) == false)
+			{
+				attributesJson.put(AjaxAttributeName.INDICATOR_ID.jsonName(), indicatorId);
+			}
+
+			for (IAjaxCallListener ajaxCallListener : attributes.getAjaxCallListeners())
+			{
+				if (ajaxCallListener != null)
+				{
+					CharSequence beforeHandler = ajaxCallListener.getBeforeHandler(component);
+					appendListenerHandler(beforeHandler, attributesJson,
+							AjaxAttributeName.BEFORE_HANDLER.jsonName(),
+							BEFORE_HANDLER_FUNCTION_TEMPLATE);
+
+					CharSequence beforeSendHandler = ajaxCallListener
+							.getBeforeSendHandler(component);
+					appendListenerHandler(beforeSendHandler, attributesJson,
+							AjaxAttributeName.BEFORE_SEND_HANDLER.jsonName(),
+							BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE);
+
+					CharSequence afterHandler = ajaxCallListener.getAfterHandler(component);
+					appendListenerHandler(afterHandler, attributesJson,
+							AjaxAttributeName.AFTER_HANDLER.jsonName(), AFTER_HANDLER_FUNCTION_TEMPLATE);
+
+					CharSequence successHandler = ajaxCallListener.getSuccessHandler(component);
+					appendListenerHandler(successHandler, attributesJson,
+							AjaxAttributeName.SUCCESS_HANDLER.jsonName(),
+							SUCCESS_HANDLER_FUNCTION_TEMPLATE);
+
+					CharSequence failureHandler = ajaxCallListener.getFailureHandler(component);
+					appendListenerHandler(failureHandler, attributesJson,
+							AjaxAttributeName.FAILURE_HANDLER.jsonName(),
+							FAILURE_HANDLER_FUNCTION_TEMPLATE);
+
+					CharSequence completeHandler = ajaxCallListener.getCompleteHandler(component);
+					appendListenerHandler(completeHandler, attributesJson,
+							AjaxAttributeName.COMPLETE_HANDLER.jsonName(),
+							COMPLETE_HANDLER_FUNCTION_TEMPLATE);
+
+					CharSequence precondition = ajaxCallListener.getPrecondition(component);
+					appendListenerHandler(precondition, attributesJson,
+							AjaxAttributeName.PRECONDITION.jsonName(), PRECONDITION_FUNCTION_TEMPLATE);
+				}
+			}
+
+			JSONArray extraParameters = JsonUtils.asArray(attributes.getExtraParameters());
+
+			if (extraParameters.length() > 0)
+			{
+				attributesJson.put(AjaxAttributeName.EXTRA_PARAMETERS.jsonName(), extraParameters);
+			}
+
+			List<CharSequence> dynamicExtraParameters = attributes.getDynamicExtraParameters();
+			if (dynamicExtraParameters != null)
+			{
+				for (CharSequence dynamicExtraParameter : dynamicExtraParameters)
+				{
+					String func = String.format(DYNAMIC_PARAMETER_FUNCTION_TEMPLATE,
+							dynamicExtraParameter);
+					JsonFunction function = new JsonFunction(func);
+					attributesJson.append(AjaxAttributeName.DYNAMIC_PARAMETER_FUNCTION.jsonName(),
+							function);
+				}
+			}
+
+			if (attributes.isAsynchronous() == false)
+			{
+				attributesJson.put(AjaxAttributeName.IS_ASYNC.jsonName(), false);
+			}
+
+			String[] eventNames = attributes.getEventNames();
+			if (eventNames.length == 1)
+			{
+				attributesJson.put(AjaxAttributeName.EVENT_NAME.jsonName(), eventNames[0]);
+			}
+			else
+			{
+				for (String eventName : eventNames)
+				{
+					attributesJson.append(AjaxAttributeName.EVENT_NAME.jsonName(), eventName);
+				}
+			}
+
+			AjaxChannel channel = attributes.getChannel();
+			if (channel != null)
+			{
+				attributesJson.put(AjaxAttributeName.CHANNEL.jsonName(), channel);
+			}
+
+			if (attributes.isPreventDefault())
+			{
+				attributesJson.put(AjaxAttributeName.IS_PREVENT_DEFAULT.jsonName(), true);
+			}
+
+			if (AjaxRequestAttributes.EventPropagation.STOP
+					.equals(attributes.getEventPropagation()))
+			{
+				attributesJson.put(AjaxAttributeName.EVENT_PROPAGATION.jsonName(), "stop");
+			}
+			else if (AjaxRequestAttributes.EventPropagation.STOP_IMMEDIATE.equals(attributes
+					.getEventPropagation()))
+			{
+				attributesJson.put(AjaxAttributeName.EVENT_PROPAGATION.jsonName(), "stopImmediate");
+			}
+
+			Duration requestTimeout = attributes.getRequestTimeout();
+			if (requestTimeout != null)
+			{
+				attributesJson.put(AjaxAttributeName.REQUEST_TIMEOUT.jsonName(),
+						requestTimeout.getMilliseconds());
+			}
+
+			boolean wicketAjaxResponse = attributes.isWicketAjaxResponse();
+			if (wicketAjaxResponse == false)
+			{
+				attributesJson.put(AjaxAttributeName.IS_WICKET_AJAX_RESPONSE.jsonName(), false);
+			}
+
+			String dataType = attributes.getDataType();
+			if (AjaxRequestAttributes.XML_DATA_TYPE.equals(dataType) == false)
+			{
+				attributesJson.put(AjaxAttributeName.DATATYPE.jsonName(), dataType);
+			}
+
+			ThrottlingSettings throttlingSettings = attributes.getThrottlingSettings();
+			if (throttlingSettings != null)
+			{
+				JSONObject throttlingSettingsJson = new JSONObject();
+				throttlingSettingsJson.put(AjaxAttributeName.THROTTLING_ID.jsonName(),
+						throttlingSettings.getId());
+				throttlingSettingsJson.put(AjaxAttributeName.THROTTLING_DELAY.jsonName(),
+						throttlingSettings.getDelay().getMilliseconds());
+				if (throttlingSettings.getPostponeTimerOnUpdate())
+				{
+					throttlingSettingsJson.put(
+							AjaxAttributeName.THROTTLING_POSTPONE_ON_UPDATE.jsonName(), true);
+				}
+				attributesJson.put(AjaxAttributeName.THROTTLING.jsonName(), throttlingSettingsJson);
+			}
+
+			postprocessConfiguration(behavior, attributesJson, component);
+		}
+		catch (JSONException e)
+		{
+			throw new WicketRuntimeException(e);
+		}
+
+		return attributesJson;
+	}
+
+	@Override
+	public void postprocessConfiguration(AbstractDefaultAjaxBehavior behavior, JSONObject attributesJson,
+		Component component) throws JSONException
+	{
+		behavior.postprocessConfiguration(attributesJson, component);
+	}
+
+	@Override
+	public CharSequence getCallbackScript(Component component, JSONObject ajaxAttributes)
+	{
+		return "Wicket.Ajax.ajax(" + ajaxAttributes + ");";
+	}
+
+	@Override
+	public CharSequence getCallbackFunction(AjaxRequestAttributes attributes, CallbackParameter... extraParameters)
+	{
+		StringBuilder sb = new StringBuilder();
+		sb.append("function (");
+		boolean first = true;
+		for (CallbackParameter curExtraParameter : extraParameters)
+		{
+			if (curExtraParameter.getFunctionParameterName() != null)
+			{
+				if (!first)
+					sb.append(',');
+				else
+					first = false;
+				sb.append(curExtraParameter.getFunctionParameterName());
+			}
+		}
+		sb.append(") {\n");
+		sb.append(getCallbackFunctionBody(attributes, extraParameters));
+		sb.append("}\n");
+		return sb;
+	}
+
+	@Override
+	public CharSequence getCallbackFunctionBody(AjaxRequestAttributes attributes, CallbackParameter... extraParameters)
+	{
+		attributes.setEventNames();
+		StringBuilder sb = new StringBuilder();
+		sb.append("var attrs = ");
+		sb.append(attributes);
+		sb.append(";\n");
+		sb.append("var params = {");
+		boolean first = true;
+		for (CallbackParameter curExtraParameter : extraParameters)
+		{
+			if (curExtraParameter.getAjaxParameterName() != null)
+			{
+				if (!first)
+					sb.append(',');
+				else
+					first = false;
+				sb.append('\'').append(curExtraParameter.getAjaxParameterName()).append("': ")
+						.append(curExtraParameter.getAjaxParameterCode());
+			}
+		}
+		sb.append("};\n");
+		if (attributes.getExtraParameters().isEmpty())
+		{
+			sb.append("attrs.").append(AjaxAttributeName.EXTRA_PARAMETERS).append(" = params;\n");
+		}
+		else
+		{
+			sb.append("attrs.").append(AjaxAttributeName.EXTRA_PARAMETERS).append(" = Wicket.merge(attrs.")
+					.append(AjaxAttributeName.EXTRA_PARAMETERS).append(", params);\n");
+		}
+		sb.append("Wicket.Ajax.ajax(attrs);\n");
+		return sb;
+	}
+
+	private void appendListenerHandler(final CharSequence handler, final JSONObject attributesJson,
+		final String propertyName, final String functionTemplate) throws JSONException
+	{
+		if (Strings.isEmpty(handler) == false)
+		{
+			final JsonFunction function;
+			if (handler instanceof JsonFunction)
+			{
+				function = (JsonFunction)handler;
+			}
+			else
+			{
+				String func = String.format(functionTemplate, handler);
+				function = new JsonFunction(func);
+			}
+			attributesJson.append(propertyName, function);
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket7AjaxStrategy.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket7AjaxStrategy.java b/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket7AjaxStrategy.java
new file mode 100644
index 0000000..9dfff9b
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/strategies/Wicket7AjaxStrategy.java
@@ -0,0 +1,69 @@
+package org.apache.wicket.ajax.strategies;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.attributes.AjaxAttributeName;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.ajax.attributes.CallbackParameter;
+import org.apache.wicket.ajax.json.JSONException;
+import org.apache.wicket.ajax.json.JSONObject;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.head.IHeaderResponse;
+
+/**
+ *
+ */
+public class Wicket7AjaxStrategy implements IAjaxStrategy
+{
+	@Override
+	public void renderHead(AjaxEventBehavior behavior, IHeaderResponse response)
+	{
+	}
+
+	@Override
+	public void onComponentTag(AjaxEventBehavior behavior, ComponentTag tag)
+	{
+		CharSequence ajaxAttributes = behavior.renderAjaxAttributes();
+		tag.put("data-w-" + behavior.getEvent(), ajaxAttributes);
+	}
+
+	@Override
+	public JSONObject getAjaxAttributes(AbstractDefaultAjaxBehavior behavior, Component component, AjaxRequestAttributes attributes)
+	{
+		return null;
+	}
+
+	@Override
+	public void postprocessConfiguration(AbstractDefaultAjaxBehavior behavior, JSONObject attributesJson, Component component) throws JSONException
+	{
+		attributesJson.remove(AjaxAttributeName.BEFORE_HANDLER.jsonName());
+		attributesJson.remove(AjaxAttributeName.PRECONDITION.jsonName());
+		attributesJson.remove(AjaxAttributeName.BEFORE_SEND_HANDLER.jsonName());
+		attributesJson.remove(AjaxAttributeName.SUCCESS_HANDLER.jsonName());
+		attributesJson.remove(AjaxAttributeName.FAILURE_HANDLER.jsonName());
+		attributesJson.remove(AjaxAttributeName.COMPLETE_HANDLER.jsonName());
+		attributesJson.remove(AjaxAttributeName.AFTER_HANDLER.jsonName());
+
+		attributesJson.remove(AjaxAttributeName.MARKUP_ID.jsonName());
+	}
+
+	@Override
+	public CharSequence getCallbackScript(Component component, JSONObject ajaxAttributes)
+	{
+		return null;
+	}
+
+	@Override
+	public CharSequence getCallbackFunction(AjaxRequestAttributes attributes, CallbackParameter... extraParameters)
+	{
+		return null;
+	}
+
+	@Override
+	public CharSequence getCallbackFunctionBody(AjaxRequestAttributes attributes, CallbackParameter... extraParameters)
+	{
+		return null;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
index ba69791..72a8351 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
@@ -69,6 +69,9 @@ import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.resource.bundles.ResourceBundleReference;
 import org.apache.wicket.session.HttpSessionStore;
 import org.apache.wicket.session.ISessionStore;
+import org.apache.wicket.settings.IAjaxSettings;
+import org.apache.wicket.settings.IResourceSettings;
+import org.apache.wicket.settings.def.AjaxSettings;
 import org.apache.wicket.util.IContextProvider;
 import org.apache.wicket.util.IProvider;
 import org.apache.wicket.util.crypt.CharEncoding;
@@ -146,6 +149,8 @@ public abstract class WebApplication extends Application
 	 */
 	private RuntimeConfigurationType configurationType;
 
+	private IAjaxSettings ajaxSettings;
+
 	/**
 	 * Covariant override for easy getting the current {@link WebApplication} without having to cast
 	 * it.
@@ -981,4 +986,26 @@ public abstract class WebApplication extends Application
 		}
 		return filterFactoryManager;
 	}
+
+	/**
+	 * @return Application's resources related settings
+	 */
+	public final IAjaxSettings getAjaxSettings()
+	{
+		checkSettingsAvailable();
+		if (ajaxSettings == null)
+		{
+			ajaxSettings = new AjaxSettings(this);
+		}
+		return ajaxSettings;
+	}
+
+	/**
+	 *
+	 * @param ajaxSettings
+	 */
+	public final void setAjaxSettings(final IAjaxSettings ajaxSettings)
+	{
+		this.ajaxSettings = ajaxSettings;
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/settings/IAjaxSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/IAjaxSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/IAjaxSettings.java
new file mode 100644
index 0000000..c8c33d9
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/IAjaxSettings.java
@@ -0,0 +1,13 @@
+package org.apache.wicket.settings;
+
+import org.apache.wicket.ajax.strategies.IAjaxStrategy;
+
+/**
+ *
+ */
+public interface IAjaxSettings
+{
+	IAjaxStrategy getAjaxStrategy();
+
+	void setAjaxStrategy(IAjaxStrategy ajaxStrategy);
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/30603f4a/wicket-core/src/main/java/org/apache/wicket/settings/def/AjaxSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/def/AjaxSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/def/AjaxSettings.java
new file mode 100644
index 0000000..5ad0556
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/def/AjaxSettings.java
@@ -0,0 +1,31 @@
+package org.apache.wicket.settings.def;
+
+import org.apache.wicket.ajax.strategies.IAjaxStrategy;
+import org.apache.wicket.ajax.strategies.Wicket6AjaxStrategy;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.settings.IAjaxSettings;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ *
+ */
+public class AjaxSettings implements IAjaxSettings
+{
+	private IAjaxStrategy ajaxStrategy = new Wicket6AjaxStrategy();
+
+	public AjaxSettings(WebApplication application)
+	{
+	}
+
+	@Override
+	public IAjaxStrategy getAjaxStrategy()
+	{
+		return ajaxStrategy;
+	}
+
+	@Override
+	public void setAjaxStrategy(IAjaxStrategy ajaxStrategy)
+	{
+		this.ajaxStrategy = Args.notNull(ajaxStrategy, "ajaxStrategy");
+	}
+}