You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2019/10/29 14:07:02 UTC

[wicket] 02/04: WICKET-6703 Ajax using header-contribution for evaluations too

This is an automated email from the ASF dual-hosted git repository.

svenmeier pushed a commit to branch WICKET-6703-replace-eval-with-domEval
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit cb4a7d3bf43338db134d9605060397a84cffe218
Author: Sven Meier <sv...@apache.org>
AuthorDate: Mon Oct 28 10:15:16 2019 +0100

    WICKET-6703 Ajax using header-contribution for evaluations too
---
 .../org/apache/wicket/ajax/AjaxRequestHandler.java |   6 +-
 .../wicket/ajax/res/js/wicket-ajax-jquery.js       | 165 +++++++--------------
 .../markup/head/filter/CspNonceHeaderResponse.java |   2 +-
 .../org/apache/wicket/page/PartialPageUpdate.java  |  67 ++++++---
 .../apache/wicket/page/XmlPartialPageUpdate.java   |  54 +------
 .../filter/AjaxServerAndClientTimeFilter.java      |  59 ++++----
 .../apache/wicket/TestDetachPageAjaxResult.html    |   7 +-
 .../AjaxHeaderContributionPage2_ajax_expected.html |  14 +-
 .../AjaxHeaderContributionPage_ajax_expected.html  |  14 +-
 .../ajax/DomReadyOrderPage_ajax_expected.html      |   7 +-
 .../SimpleTestPageExpectedResult-1.html            |   7 +-
 .../markup/head/filter/CspNoncePageExpected.html   |   2 +-
 12 files changed, 181 insertions(+), 223 deletions(-)

diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java
index 1dad048..230aead 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java
@@ -153,15 +153,13 @@ public class AjaxRequestHandler implements AjaxRequestTarget
 					final Map<String, Component> components = Collections
 						.unmodifiableMap(markupIdToComponent);
 
-					// create response that will be used by listeners to append
-					// javascript
+					// create response that will be used by listeners to append javascript
 					final AjaxRequestTarget.IJavaScriptResponse jsresponse = new AjaxRequestTarget.IJavaScriptResponse()
 					{
 						@Override
 						public void addJavaScript(String script)
 						{
-							writeNormalEvaluations(response,
-								Collections.<CharSequence> singleton(script));
+							writeEvaluations(response, Collections.<CharSequence> singleton(script));
 						}
 					};
 
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
index 018fc4b..a960c55 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
@@ -850,35 +850,23 @@
 				}
 
 				var steps = context.steps;
-
-				// go through the ajax response and execute all priority-invocations first
-				for (var i = 0; i < root.childNodes.length; ++i) {
-					var childNode = root.childNodes[i];
-					if (childNode.tagName === "header-contribution") {
-						this.processHeaderContribution(context, childNode);
-					} else if (childNode.tagName === "priority-evaluate") {
-						this.processEvaluation(context, childNode);
-					}
-				}
-
-				// go through the ajax response and for every action (component, js evaluation, header contribution)
-				// ad the proper closure to steps
 				var stepIndexOfLastReplacedComponent = -1;
-				for (var c = 0; c < root.childNodes.length; ++c) {
-					var node = root.childNodes[c];
 
-					if (node.tagName === "component") {
+				// go through the ajax response and execute all items
+				for (var i = 0; i < root.childNodes.length; ++i) {
+					var node = root.childNodes[i];
+					
+					if (node.tagName === "header-contribution") {
+						this.processHeaderContribution(context, node);
+					} else if (node.tagName === "component") {
 						if (stepIndexOfLastReplacedComponent === -1) {
 							this.processFocusedComponentMark(context);
 						}
 						stepIndexOfLastReplacedComponent = steps.length;
 						this.processComponent(context, node);
-					} else if (node.tagName === "evaluate") {
-						this.processEvaluation(context, node);
 					} else if (node.tagName === "redirect") {
 						this.processRedirect(context, node);
 					}
-
 				}
 				if (stepIndexOfLastReplacedComponent !== -1) {
 					this.processFocusedComponentReplaceCheck(steps, stepIndexOfLastReplacedComponent);
@@ -952,63 +940,6 @@
 			});
 		},
 
-		/**
-		 * Adds a closure that evaluates javascript code.
-		 * @param context {Object} - the object that brings the executer's steps and the attributes
-		 * @param node {XmlElement} - the <[priority-]evaluate> element with the script to evaluate
-		 */
-		processEvaluation: function (context, node) {
-
-			// get the javascript body
-			var text = Wicket.DOM.text(node);
-
-			// aliases to improve performance
-			var steps = context.steps;
-			var log = Wicket.Log;
-
-			var evaluate = function (script) {
-				return function(notify) {
-					
-					var suspension = {
-						suspended: 0,
-						
-						suspend: function() {
-							suspension.suspended++;
-						},
-						
-						release: function() {
-							suspension.suspended--;
-							if (suspension.suspended == 0) {
-								notify();
-							}
-						}
-					};
-					
-					try {
-						Wicket.Ajax._currentSuspension = suspension;
-						
-						// do the evaluation in global scope
-						window.eval(script);
-					} catch (exception) {
-						log.error("Ajax.Call.processEvaluation: Exception evaluating javascript: %s", text, exception);
-					} finally {
-						Wicket.Ajax.currentSuspension = undefined;
-					}
-					
-					// continue to next step
-					if (suspension.suspended === 0) {
-						// execution finished without suspension, just continue to next step
-						return FunctionsExecuter.DONE;
-					} else {
-						// suspended, signal asynchronous execution of next step
-						return FunctionsExecuter.ASYNC;
-					}
-				};
-			};
-			
-			steps.push(evaluate(text));
-		},
-
 		// Adds a closure that processes a header contribution
 		processHeaderContribution: function (context, node) {
 			var c = Wicket.Head.Contributor;
@@ -1937,20 +1868,17 @@
 							}
 						}
 
+						// convert the XML node to DOM node
+						var scriptDomNode = document.createElement("script");
+						var attrs = node.attributes;
+						for (var a = 0; a < attrs.length; a++) {
+							var attr = attrs[a];
+							scriptDomNode[attr.name] = attr.value;
+						}
+						
 						// determine whether it is external javascript (has src attribute set)
 						var src = node.getAttribute("src");
-
 						if (src !== null && src !== "") {
-
-							// convert the XML node to DOM node
-							var scriptDomNode = document.createElement("script");
-
-							var attrs = node.attributes;
-							for (var a = 0; a < attrs.length; a++) {
-								var attr = attrs[a];
-								scriptDomNode[attr.name] = attr.value;
-							}
-
 							var onScriptReady = function () {
 								notify();
 							};
@@ -1973,29 +1901,47 @@
 
 							return FunctionsExecuter.ASYNC;
 						} else {
-							// serialize the element content to string
-							var text = Wicket.DOM.serializeNodeChildren(node);
-							// get rid of prefix and suffix, they are not eval-d correctly
-							text = text.replace(/^\n\/\*<!\[CDATA\[\*\/\n/, "");
-							text = text.replace(/\n\/\*\]\]>\*\/\n$/, "");
-
-							var id = node.getAttribute("id");
-							var type = node.getAttribute("type");
-
-							if (typeof(id) === "string" && id.length > 0) {
-								// add javascript to document head
-								Wicket.Head.addJavascript(text, id, "", type);
-							} else {
-								try {
-									// do the evaluation in global scope
-									window.eval(text);
-								} catch (e) {
-									Wicket.Log.error("Wicket.Head.Contributor.processScript: %s", text, e);
+							var suspension = {
+								suspended: 0,
+										
+								suspend: function() {
+									suspension.suspended++;
+								},
+										
+								release: function() {
+									suspension.suspended--;
+									if (suspension.suspended == 0) {
+										notify();
+									}
 								}
+							};
+
+							try {
+								Wicket.Ajax._currentSuspension = suspension;
+
+								// serialize the element content to string
+								var text = Wicket.DOM.serializeNodeChildren(node);
+								// get rid of prefix and suffix, they are not eval-d correctly
+								text = text.replace(/^\n\/\*<!\[CDATA\[\*\/\n/, "");
+								text = text.replace(/\n\/\*\]\]>\*\/\n$/, "");
+								scriptDomNode.innerHTML = text;
+
+								var id = node.getAttribute("id");
+								Wicket.Head.addElement(scriptDomNode, typeof(id) !== "string" || id.length == 0);
+							} catch (exception) {
+								log.error("Ajax.Call.processEvaluation: Exception evaluating javascript: %s", text, exception);
+							} finally {
+								Wicket.Ajax.currentSuspension = undefined;
 							}
 
 							// continue to next step
-							return FunctionsExecuter.DONE;
+							if (suspension.suspended === 0) {
+								// execution finished without suspension, just continue to next step
+								return FunctionsExecuter.DONE;
+							} else {
+								// suspended, signal asynchronous execution of next step
+								return FunctionsExecuter.ASYNC;
+							}
 						}
 					});
 				},
@@ -2044,17 +1990,20 @@
 			},
 
 			// Adds the element to page head
-			addElement: function (element) {
+			addElement: function (element, remove) {
 				var headItems = document.querySelector('head meta[name="wicket.header.items"]');
 				if (headItems) {
 					headItems.parentNode.insertBefore(element, headItems);
 				} else {
 					var head = document.querySelector("head");
-
 					if (head) {
 						head.appendChild(element);
 					}
 				}
+
+				if (remove) {
+					element.parentNode.removeChild(element);
+				}
 			},
 
 			// Returns true, if the page head contains element that has attribute with
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java b/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java
index 6376518..ec72315 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java
@@ -88,6 +88,6 @@ public class CspNonceHeaderResponse extends DecoratingHeaderResponse
 	 */
 	protected String getContentSecurityPolicy(String nonce)
 	{
-		return String.format("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1$s'; style-src 'nonce-%1$s';", nonce);
+		return String.format("script-src 'strict-dynamic' 'nonce-%1$s'; style-src 'nonce-%1$s';", nonce);
 	}
 }
diff --git a/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java b/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java
index 2e026bd..efefafb 100644
--- a/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java
+++ b/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java
@@ -25,12 +25,16 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import javax.servlet.http.Cookie;
+
+import org.apache.wicket.Application;
 import org.apache.wicket.Component;
 import org.apache.wicket.Page;
+import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.feedback.FeedbackDelay;
 import org.apache.wicket.markup.head.HeaderItem;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.IWrappedHeaderItem;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.markup.head.OnEventHeaderItem;
 import org.apache.wicket.markup.head.OnLoadHeaderItem;
@@ -45,6 +49,7 @@ import org.apache.wicket.request.IRequestCycle;
 import org.apache.wicket.request.Response;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.http.WebResponse;
+import org.apache.wicket.response.StringResponse;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.string.AppendingStringBuffer;
@@ -52,16 +57,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * A partial update of a page that collects components and header contributions to be written to the client in a specific
- * String-based format (XML, JSON, * ...).
+ * A partial update of a page that collects components and header contributions to be written to the
+ * client in a specific String-based format (XML, JSON, * ...).
  * <p>
  * The elements of such response are:
  * <ul>
- * <li>priority-evaluate - an item of the prepend JavaScripts</li>
  * <li>component - the markup of the updated component</li>
- * <li>evaluate - an item of the onDomReady and append JavaScripts</li>
- * <li>header-contribution - all HeaderItems which have been contributed in
- * components' and their behaviors' #renderHead(Component, IHeaderResponse)</li>
+ * <li>header-contribution - all HeaderItems which have been contributed in any{@link Component#renderHead(IHeaderResponse)},
+ * {@link Behavior#renderHead(Component, IHeaderResponse)} or JavaScript explicitly added via {@link #appendJavaScript(CharSequence)}
+ * or {@link #prependJavaScript(CharSequence)}</li>
  * </ul>
  */
 public abstract class PartialPageUpdate
@@ -155,21 +159,21 @@ public abstract class PartialPageUpdate
 
 			onBeforeRespond(response);
 
+			// queue up prepend javascripts. unlike other steps these are executed out of order so that
+			// components can contribute them from inside their onbeforerender methods.
+			writeEvaluations(response, prependJavaScripts);
+
 			// process added components
 			writeComponents(response, encoding);
 
 			onAfterRespond(response);
 
-			// queue up prepend javascripts. unlike other steps these are executed out of order so that
-			// components can contribute them from inside their onbeforerender methods.
-			writePriorityEvaluations(response, prependJavaScripts);
-
 			// execute the dom ready javascripts as first javascripts
 			// after component replacement
 			List<CharSequence> evaluationScripts = new ArrayList<>();
 			evaluationScripts.addAll(domReadyJavaScripts);
 			evaluationScripts.addAll(appendJavaScripts);
-			writeNormalEvaluations(response, evaluationScripts);
+			writeEvaluations(response, evaluationScripts);
 
 			writeFooter(response, encoding);
 		} finally {
@@ -212,16 +216,33 @@ public abstract class PartialPageUpdate
 	 * @param js
 	 *      the JavaScript to evaluate
 	 */
-	protected abstract void writePriorityEvaluations(Response response, Collection<CharSequence> js);
+	protected void writeEvaluations(final Response response, Collection<CharSequence> scripts)
+	{
+		if (scripts.size() > 0)
+		{
+			StringBuilder combinedScript = new StringBuilder(1024);
+			for (CharSequence script : scripts)
+			{
+				combinedScript.append("(function(){").append(script).append("})();");
+			}
+
+			StringResponse stringResponse = new StringResponse();
+			IHeaderResponse headerResponse = Application.get().decorateHeaderResponse(new HeaderResponse()
+			{
+				@Override
+				protected Response getRealResponse()
+				{
+					return stringResponse;
+				}
+			});
+			
+			headerResponse.render(JavaScriptHeaderItem.forScript(combinedScript, null));
+			headerResponse.close();
+			
+			writeHeaderContribution(response, stringResponse.getBuffer());
+		}
+	}
 
-	/**
-	 *
-	 * @param response
-	 *      the response to write to
-	 * @param js
-	 *      the JavaScript to evaluate
-	 */
-	protected abstract void writeNormalEvaluations(Response response, Collection<CharSequence> js);
 
 	/**
 	 * Processes components added to the target. This involves attaching components, rendering
@@ -281,7 +302,7 @@ public abstract class PartialPageUpdate
 			cycle.setResponse(oldResponse);
 
 			// write the XML tags and we're done
-			writeHeaderContribution(response);
+			writeHeaderContribution(response, headerBuffer.getContents());
 			headerRendering = false;
 		}
 	}
@@ -358,7 +379,7 @@ public abstract class PartialPageUpdate
 	 * @param response
 	 *      the response to write to
 	 */
-	protected abstract void writeHeaderContribution(Response response);
+	protected abstract void writeHeaderContribution(Response response, CharSequence contents);
 
 	@Override
 	public boolean equals(Object o)
@@ -575,7 +596,7 @@ public abstract class PartialPageUpdate
 			requestCycle.setResponse(oldResponse);
 		}
 
-		writeHeaderContribution(response);
+		writeHeaderContribution(response, headerBuffer.getContents());
 		headerRendering = false;
 	}
 
diff --git a/wicket-core/src/main/java/org/apache/wicket/page/XmlPartialPageUpdate.java b/wicket-core/src/main/java/org/apache/wicket/page/XmlPartialPageUpdate.java
index 0af4342..20c12d7 100644
--- a/wicket-core/src/main/java/org/apache/wicket/page/XmlPartialPageUpdate.java
+++ b/wicket-core/src/main/java/org/apache/wicket/page/XmlPartialPageUpdate.java
@@ -20,6 +20,7 @@ import java.util.Collection;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.Page;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.request.Response;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.http.WebResponse;
@@ -102,9 +103,8 @@ public class XmlPartialPageUpdate extends PartialPageUpdate
 	}
 
 	@Override
-	protected void writeHeaderContribution(Response response)
+	protected void writeHeaderContribution(Response response, CharSequence contents)
 	{
-		CharSequence contents = headerBuffer.getContents();
 		if (Strings.isEmpty(contents) == false)
 		{
 			response.write("<header-contribution>");
@@ -118,56 +118,6 @@ public class XmlPartialPageUpdate extends PartialPageUpdate
 		}
 	}
 
-	@Override
-	protected void writeNormalEvaluations(final Response response, final Collection<CharSequence> scripts)
-	{
-		writeEvaluations(response, "evaluate", scripts);
-
-	}
-
-	@Override
-	protected void writePriorityEvaluations(Response response, Collection<CharSequence> scripts)
-	{
-		writeEvaluations(response, "priority-evaluate", scripts);
-	}
-
-	private void writeEvaluations(final Response response, String elementName, Collection<CharSequence> scripts)
-	{
-		if (scripts.size() > 0)
-		{
-			StringBuilder combinedScript = new StringBuilder(1024);
-			for (CharSequence script : scripts)
-			{
-				combinedScript.append("(function(){").append(script).append("})();");
-			}
-			writeEvaluation(elementName, response, combinedScript);
-		}
-	}
-
-	/**
-	* @param invocation
-	*            type of invocation tag, usually {@literal evaluate} or
-	*            {@literal priority-evaluate}
-	* @param response
-	* @param js
-	*/
-	private void writeEvaluation(final String invocation, final Response response, final CharSequence js)
-	{
-		response.write("<");
-		response.write(invocation);
-		response.write(">");
-
-		response.write("<![CDATA[");
-		response.write(encode(js));
-		response.write("]]>");
-
-		response.write("</");
-		response.write(invocation);
-		response.write(">");
-
-		bodyBuffer.reset();
-	}
-
 	protected CharSequence encode(CharSequence str)
 	{
 		return Strings.replaceAll(str, "]]>", "]]]]><![CDATA[>"); 
diff --git a/wicket-core/src/main/java/org/apache/wicket/response/filter/AjaxServerAndClientTimeFilter.java b/wicket-core/src/main/java/org/apache/wicket/response/filter/AjaxServerAndClientTimeFilter.java
index 618a39b..8db3b90 100644
--- a/wicket-core/src/main/java/org/apache/wicket/response/filter/AjaxServerAndClientTimeFilter.java
+++ b/wicket-core/src/main/java/org/apache/wicket/response/filter/AjaxServerAndClientTimeFilter.java
@@ -17,13 +17,12 @@
 package org.apache.wicket.response.filter;
 
 import java.util.HashMap;
-import java.util.Map;
 
 import org.apache.wicket.Application;
+import org.apache.wicket.core.util.string.JavaScriptUtils;
+import org.apache.wicket.model.Model;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.util.string.AppendingStringBuffer;
-import org.apache.wicket.core.util.string.JavaScriptUtils;
-import org.apache.wicket.util.string.interpolator.MapVariableInterpolator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,32 +67,38 @@ public class AjaxServerAndClientTimeFilter implements IResponseFilter
 		long timeTaken = System.currentTimeMillis() - RequestCycle.get().getStartTime();
 		if (headIndex != -1 && bodyIndex != -1)
 		{
-			AppendingStringBuffer endScript = new AppendingStringBuffer(150);
-			endScript.append("\n").append(JavaScriptUtils.SCRIPT_OPEN_TAG);
-			endScript.append("\nwindow.defaultStatus='");
-			endScript.append(getStatusString(timeTaken, "ServerAndClientTimeFilter.statustext"));
-			endScript.append("';\n").append(JavaScriptUtils.SCRIPT_CLOSE_TAG).append("\n");
-			responseBuffer.insert(bodyIndex - 1, endScript);
-			responseBuffer.insert(headIndex + 6, "\n" + JavaScriptUtils.SCRIPT_OPEN_TAG +
-				"\nvar clientTimeVariable = new Date().getTime();\n" +
-				JavaScriptUtils.SCRIPT_CLOSE_TAG + "\n");
+			responseBuffer.insert(bodyIndex, scriptTag("window.defaultStatus=" + getStatusString(timeTaken, "ServerAndClientTimeFilter.statustext") + ";"));
+			responseBuffer.insert(headIndex + 6, scriptTag("clientTimeVariable = new Date().getTime();"));
 		}
 		else if (ajaxStart != -1 && ajaxEnd != -1)
 		{
-			AppendingStringBuffer startScript = new AppendingStringBuffer(250);
-			startScript.append("<evaluate><![CDATA[window.defaultStatus='");
-			startScript.append(getStatusString(timeTaken,
-				"ajax.ServerAndClientTimeFilter.statustext"));
-			startScript.append("';]]></evaluate>");
-			responseBuffer.insert(ajaxEnd, startScript.toString());
-			responseBuffer.insert(ajaxStart + 15,
-				"<priority-evaluate><![CDATA[clientTimeVariable = new Date().getTime();]]></priority-evaluate>");
+			responseBuffer.insert(ajaxEnd, headerContribution("window.defaultStatus=" + getStatusString(timeTaken, "ajax.ServerAndClientTimeFilter.statustext") + ";"));
+			responseBuffer.insert(ajaxStart + 15, headerContribution("clientTimeVariable = new Date().getTime();"));
 		}
 		log.info(timeTaken + "ms server time taken for request " +
 			RequestCycle.get().getRequest().getUrl() + " response size: " + responseBuffer.length());
 		return responseBuffer;
 	}
 
+	private String scriptTag(String script)
+	{
+		AppendingStringBuffer buffer = new AppendingStringBuffer(250);
+		buffer.append("\n");
+		buffer.append(JavaScriptUtils.SCRIPT_OPEN_TAG);
+		buffer.append(script);
+		buffer.append(JavaScriptUtils.SCRIPT_CLOSE_TAG).append("\n");
+		return buffer.toString();
+	}
+	
+	private String headerContribution(String script)
+	{
+		AppendingStringBuffer buffer = new AppendingStringBuffer(250);
+		buffer.append("<header-contribution><![CDATA[<head xmlns:wicket=\"http://wicket.apache.org\">");
+		buffer.append(script);
+		buffer.append("</head>]]></header-contribution>");
+		return buffer.toString();
+	}
+
 	/**
 	 * Returns a locale specific status message about the server and client time.
 	 * 
@@ -105,14 +110,14 @@ public class AjaxServerAndClientTimeFilter implements IResponseFilter
 	 */
 	private String getStatusString(long timeTaken, String resourceKey)
 	{
-		final String txt = Application.get()
+		final HashMap<String, String> map = new HashMap<String, String>(4);
+		map.put("servertime", ((double)timeTaken) / 1000 + "s");
+		map.put("clienttime", "' + (new Date().getTime() - clientTimeVariable)/1000 +  's");
+
+		return Application.get()
 			.getResourceSettings()
 			.getLocalizer()
-			.getString(resourceKey, null,
-				"Server parsetime: ${servertime}, Client parsetime: ${clienttime}");
-		final Map<String, String> map = new HashMap<String, String>(4);
-		map.put("clienttime", "' + (new Date().getTime() - clientTimeVariable)/1000 +  's");
-		map.put("servertime", ((double)timeTaken) / 1000 + "s");
-		return MapVariableInterpolator.interpolate(txt, map);
+			.getString(resourceKey, null, Model.of(map),
+				"'Server parsetime: ${servertime}, Client parsetime: ${clienttime}'");
 	}
 }
\ No newline at end of file
diff --git a/wicket-core/src/test/java/org/apache/wicket/TestDetachPageAjaxResult.html b/wicket-core/src/test/java/org/apache/wicket/TestDetachPageAjaxResult.html
index 973720e..ecda0eb 100644
--- a/wicket-core/src/test/java/org/apache/wicket/TestDetachPageAjaxResult.html
+++ b/wicket-core/src/test/java/org/apache/wicket/TestDetachPageAjaxResult.html
@@ -10,4 +10,9 @@ Wicket.Log.enabled=true;
 Wicket.Ajax.baseUrl="wicket/bookmarkable/org.apache.wicket.TestDetachPage?0-1.0-comp";
 /*]]]]><![CDATA[>*/
 </script>
-</head>]]></header-contribution><evaluate><![CDATA[(function(){Wicket.Ajax.ajax({"u":"./org.apache.wicket.TestDetachPage?0-1.0-comp","c":"comp1","e":"click"});})();]]></evaluate></ajax-response>
\ No newline at end of file
+</head>]]></header-contribution><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){Wicket.Ajax.ajax({"u":"./org.apache.wicket.TestDetachPage?0-1.0-comp","c":"comp1","e":"click"});})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution></ajax-response>
\ No newline at end of file
diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage2_ajax_expected.html b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage2_ajax_expected.html
index 7dbede2..08ef620 100644
--- a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage2_ajax_expected.html
+++ b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage2_ajax_expected.html
@@ -1,4 +1,9 @@
-<?xml version="1.0" encoding="UTF-8"?><ajax-response><component id="test12" ><![CDATA[<span wicket:id="test1" id="test12"><wicket:panel>
+<?xml version="1.0" encoding="UTF-8"?><ajax-response><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){prepend();})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution><component id="test12" ><![CDATA[<span wicket:id="test1" id="test12"><wicket:panel>
 test
 </wicket:panel></span>]]></component><component id="test23" ><![CDATA[<span wicket:id="test2" id="test23"><wicket:panel>
 test
@@ -18,4 +23,9 @@ test
 
 <link href="../../test2"/>
 <script type="text/javascript" src="../../javascripturlB"></script>
-</head>]]></header-contribution><priority-evaluate><![CDATA[(function(){prepend();})();]]></priority-evaluate><evaluate><![CDATA[(function(){domReady();})();(function(){domReadyB();})();(function(){append();})();(function(){onLoad();})();(function(){onLoadB();})();]]></evaluate></ajax-response>
\ No newline at end of file
+</head>]]></header-contribution><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){domReady();})();(function(){domReadyB();})();(function(){append();})();(function(){onLoad();})();(function(){onLoadB();})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution></ajax-response>
\ No newline at end of file
diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage_ajax_expected.html b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage_ajax_expected.html
index ab1020a..dc3d8af 100644
--- a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage_ajax_expected.html
+++ b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxHeaderContributionPage_ajax_expected.html
@@ -1,4 +1,9 @@
-<?xml version="1.0" encoding="UTF-8"?><ajax-response><component id="test12" ><![CDATA[<span wicket:id="test1" id="test12"><wicket:panel>
+<?xml version="1.0" encoding="UTF-8"?><ajax-response><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){prepend();})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution><component id="test12" ><![CDATA[<span wicket:id="test1" id="test12"><wicket:panel>
 test
 </wicket:panel></span>]]></component><component id="test23" ><![CDATA[<span wicket:id="test2" id="test23"><wicket:panel>
 test
@@ -9,4 +14,9 @@ test
 <script type="text/javascript" src="../../javascripturl"></script>
 <script type="text/javascript" src="../resource/org.apache.wicket.resource.JQueryResourceReference/jquery/jquery-3.4.1.js"></script>
 <script type="text/javascript" src="../resource/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/res/js/wicket-ajax-jquery.js"></script>
-</head>]]></header-contribution><priority-evaluate><![CDATA[(function(){prepend();})();]]></priority-evaluate><evaluate><![CDATA[(function(){domReady();})();(function(){append();})();(function(){onLoad();})();]]></evaluate></ajax-response>
\ No newline at end of file
+</head>]]></header-contribution><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){domReady();})();(function(){append();})();(function(){onLoad();})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution></ajax-response>
\ No newline at end of file
diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/DomReadyOrderPage_ajax_expected.html b/wicket-core/src/test/java/org/apache/wicket/ajax/DomReadyOrderPage_ajax_expected.html
index 9791e9c..93b9b8c 100644
--- a/wicket-core/src/test/java/org/apache/wicket/ajax/DomReadyOrderPage_ajax_expected.html
+++ b/wicket-core/src/test/java/org/apache/wicket/ajax/DomReadyOrderPage_ajax_expected.html
@@ -10,4 +10,9 @@ Wicket.Log.enabled=true;
 Wicket.Ajax.baseUrl="wicket/bookmarkable/org.apache.wicket.ajax.DomReadyOrderPage?0-1.0-test";
 /*]]]]><![CDATA[>*/
 </script>
-</head>]]></header-contribution><evaluate><![CDATA[(function(){Wicket.Ajax.ajax({"u":"./org.apache.wicket.ajax.DomReadyOrderPage?0-1.0-test","c":"test1","e":"click","pd":true});})();(function(){test1();})();(function(){test2();})();]]></evaluate></ajax-response>
\ No newline at end of file
+</head>]]></header-contribution><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){Wicket.Ajax.ajax({"u":"./org.apache.wicket.ajax.DomReadyOrderPage?0-1.0-test","c":"test1","e":"click","pd":true});})();(function(){test1();})();(function(){test2();})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution></ajax-response>
\ No newline at end of file
diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/componentMap/SimpleTestPageExpectedResult-1.html b/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/componentMap/SimpleTestPageExpectedResult-1.html
index 279ac72..ba09269 100644
--- a/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/componentMap/SimpleTestPageExpectedResult-1.html
+++ b/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/componentMap/SimpleTestPageExpectedResult-1.html
@@ -10,4 +10,9 @@ Wicket.Log.enabled=true;
 Wicket.Ajax.baseUrl="wicket/bookmarkable/org.apache.wicket.ajax.markup.html.componentMap.SimpleTestPage?0-1.0-testPanel-baseSpan-linja1";
 /*]]]]><![CDATA[>*/
 </script>
-</head>]]></header-contribution><evaluate><![CDATA[(function(){Wicket.Timer.set('linja11.0', function(){Wicket.Ajax.ajax({"u":"./org.apache.wicket.ajax.markup.html.componentMap.SimpleTestPage?0-1.0-testPanel-baseSpan-linja1","c":"linja11"});}, 2000);})();]]></evaluate></ajax-response>
\ No newline at end of file
+</head>]]></header-contribution><header-contribution><![CDATA[<head xmlns:wicket="http://wicket.apache.org"><script type="text/javascript">
+/*<![CDATA[*/
+(function(){Wicket.Timer.set('linja11.0', function(){Wicket.Ajax.ajax({"u":"./org.apache.wicket.ajax.markup.html.componentMap.SimpleTestPage?0-1.0-testPanel-baseSpan-linja1","c":"linja11"});}, 2000);})();
+/*]]]]><![CDATA[>*/
+</script>
+</head>]]></header-contribution></ajax-response>
\ No newline at end of file
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html b/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html
index 63c9d08..2c44fc9 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html
@@ -1,5 +1,5 @@
 <html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
-    <head><meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-eval' 'strict-dynamic' 'nonce-NONCE'; style-src 'nonce-NONCE';" />
+    <head><meta http-equiv="Content-Security-Policy" content="script-src 'strict-dynamic' 'nonce-NONCE'; style-src 'nonce-NONCE';" />
 <script type="text/javascript" src="../resource/org.apache.wicket.resource.JQueryResourceReference/jquery/jquery-3.4.1.js" nonce="NONCE"></script>
 <script type="text/javascript" src="../resource/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/res/js/wicket-ajax-jquery.js" nonce="NONCE"></script>
 <script type="text/javascript" id="wicket-ajax-debug-enable" nonce="NONCE">