This is an automated email from the ASF dual-hosted git repository. svenmeier pushed a commit to branch wicket-9.x in repository https://gitbox.apache.org/repos/asf/wicket.git
The following commit(s) were added to refs/heads/wicket-9.x by this push: new 23c1584 WICKET-6902 allow prepend and append 23c1584 is described below commit 23c1584636d374ee380a8f5b9fb25aef969ee3f8 Author: Sven Meier <svenme...@apache.org> AuthorDate: Sat Jul 17 00:18:02 2021 +0200 WICKET-6902 allow prepend and append up-to including #onAfterRespond() --- .../org/apache/wicket/ajax/AjaxRequestHandler.java | 12 +---- .../org/apache/wicket/ajax/AjaxRequestTarget.java | 45 +++++++++++++---- .../org/apache/wicket/page/PartialPageUpdate.java | 22 +++++++- .../apache/wicket/ajax/AjaxRequestHandlerTest.java | 58 ++++++++++++++++------ 4 files changed, 98 insertions(+), 39 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 78699bf..fd54daa 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 @@ -145,19 +145,9 @@ public class AjaxRequestHandler extends AbstractPartialPageRequestHandler implem final Map<String, Component> components = Collections .unmodifiableMap(markupIdToComponent); - // create response that will be used by listeners to append javascript - final AjaxRequestTarget.IJavaScriptResponse jsresponse = new AjaxRequestTarget.IJavaScriptResponse() - { - @Override - public void addJavaScript(String script) - { - writeEvaluations(response, Collections.<CharSequence> singleton(script)); - } - }; - for (AjaxRequestTarget.IListener listener : listeners) { - listener.onAfterRespond(components, jsresponse); + listener.onAfterRespond(components, AjaxRequestHandler.this); } } } diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java index 6c874dc..2e1efb6 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java @@ -38,35 +38,54 @@ public interface AjaxRequestTarget extends IPartialPageRequestHandler, ILoggable interface IListener { /** - * Triggered before ajax request target begins its response cycle + * Triggered before the target begins writing components. * * @param map * modifiable map (markupId -> component) of components already added to the target * @param target * the target itself. Could be used to add components or to append/prepend - * javascript + * JavaScript * */ default void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) {} /** - * Triggered after ajax request target is done with its response cycle. At this point only - * additional javascript can be output to the response using the provided - * {@link AjaxRequestTarget.IJavaScriptResponse} object + * Triggered after the target has written components. At this point only + * additional JavaScript can be added to the response. * - * NOTE: During this stage of processing any calls to target that manipulate the response - * (adding components, javascript) will have no effect + * NOTE: During this stage of processing any calls that manipulate components will result in + * an exception. * * @param map * read-only map:markupId->component of components already added to the target * @param response - * response object that can be used to output javascript + * response object that can be used to output JavaScript + * + * @deprecated implement {@link #onAfterRespond(Map, AjaxRequestTarget)} instead */ + @Deprecated default void onAfterRespond(Map<String, Component> map, AjaxRequestTarget.IJavaScriptResponse response) {} /** + * Triggered after the target has written components. At this point only + * additional JavaScript can be added to the response. + * + * NOTE: During this stage of processing any calls that manipulate components will result in + * an exception. After notification of all listeners no JavaScript can be added any longer. + * + * @param map + * read-only map:markupId->component of components already added to the target + * @param target + * the target itself. Could be used to append/prepend JavaScript + */ + default void onAfterRespond(Map<String, Component> map, AjaxRequestTarget target) + { + onAfterRespond(map, script -> target.appendJavaScript(script)); + } + + /** * Triggered for every Ajax behavior. Can be used to configure common settings. * * @param behavior @@ -80,19 +99,23 @@ public interface AjaxRequestTarget extends IPartialPageRequestHandler, ILoggable } /** - * An ajax javascript response that allows users to add javascript to be executed on the client + * An ajax JavaScript response that allows users to add JavaScript to be executed on the client * side * * @author ivaynberg + * + * @deprecated use {@link AjaxRequestTargetprependJavaScript(CharSequence)} and + * {@link AjaxRequestTarget#appendJavaScript(CharSequence)} instead */ + @Deprecated @FunctionalInterface interface IJavaScriptResponse { /** - * Adds more javascript to the ajax response that will be executed on the client side + * Adds more JavaScript to the ajax response that will be executed on the client side * * @param script - * javascript + * JavaScript */ void addJavaScript(String script); } 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 1712dc8..f95c959 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 @@ -104,6 +104,12 @@ public abstract class PartialPageUpdate protected transient boolean componentsFrozen; /** + * A flag that indicates that javascripts cannot be added anymore. + * See https://issues.apache.org/jira/browse/WICKET-6902 + */ + protected transient boolean javascriptsFrozen; + + /** * Buffer of response body. */ protected final ResponseBuffer bodyBuffer; @@ -161,12 +167,14 @@ public abstract class PartialPageUpdate // process added components writeComponents(response, encoding); + onAfterRespond(response); + + javascriptsFrozen = true; + // queue up prepend javascripts. unlike other steps these are executed out of order so that // components can contribute them from during rendering. writePriorityEvaluations(response, prependJavaScripts); - onAfterRespond(response); - // execute the dom ready javascripts as first javascripts // after component replacement List<CharSequence> evaluationScripts = new ArrayList<>(); @@ -493,6 +501,11 @@ public abstract class PartialPageUpdate { Args.notNull(javascript, "javascript"); + if (javascriptsFrozen) + { + throw new IllegalStateException("A partial update of the page is being rendered, JavaScript can no longer be added"); + } + appendJavaScripts.add(javascript); } @@ -505,6 +518,11 @@ public abstract class PartialPageUpdate public final void prependJavaScript(CharSequence javascript) { Args.notNull(javascript, "javascript"); + + if (javascriptsFrozen) + { + throw new IllegalStateException("A partial update of the page is being rendered, JavaScript can no longer be added"); + } prependJavaScripts.add(javascript); } diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java index 66cc73d..f2c1236 100644 --- a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java @@ -21,14 +21,15 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; + import java.io.IOException; import java.lang.reflect.Constructor; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; + import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; import org.apache.wicket.MockPageWithLink; @@ -38,6 +39,9 @@ import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.IMarkupResourceStreamProvider; import org.apache.wicket.markup.html.WebComponent; import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.request.IRequestHandler; +import org.apache.wicket.request.cycle.IRequestCycleListener; +import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.util.encoding.UrlEncoder; import org.apache.wicket.util.resource.IResourceStream; import org.apache.wicket.util.resource.StringResourceStream; @@ -260,20 +264,24 @@ class AjaxRequestHandlerTest extends WicketTestCase } /** - * @see <a href="https://issues.apache.org/jira/browse/WICKET-3263">WICKET-3263</a> + * WICKET-3263<br> + * WICKET-6902 */ @Test void globalAjaxRequestTargetListeners() { - final ValidatingAjaxRequestTargetListener listener = new ValidatingAjaxRequestTargetListener(); - + JavaScriptPrependerAppender listener = new JavaScriptPrependerAppender(); + tester.getApplication().getAjaxRequestTargetListeners().add(listener); + tester.getApplication().getRequestCycleListeners().add(listener); tester.startPage(TestEventPage.class); tester.clickLink(MockPageWithLinkAndComponent.LINK_ID, true); - assertTrue(listener.onBeforeRespondExecuted); - assertTrue(listener.onAfterRespondExecuted); + tester.assertContains("BEFORE_RESPOND_PREPEND"); + tester.assertContains("BEFORE_RESPOND_APPEND"); + tester.assertContains("AFTER_RESPOND_PREPEND"); + tester.assertContains("AFTER_RESPOND_APPEND"); } /** @@ -396,23 +404,43 @@ class AjaxRequestHandlerTest extends WicketTestCase } } - private static class ValidatingAjaxRequestTargetListener implements AjaxRequestTarget.IListener + /** + * Listener to AjaxRequestTarget and RequestCycle to test prepending and appending of + * JavaScript. + */ + private static class JavaScriptPrependerAppender implements AjaxRequestTarget.IListener, IRequestCycleListener { - boolean onBeforeRespondExecuted = false; - boolean onAfterRespondExecuted = false; - @Override public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) { - onBeforeRespondExecuted = true; - + target.prependJavaScript("BEFORE_RESPOND_PREPEND"); + target.appendJavaScript("BEFORE_RESPOND_APPEND"); } @Override - public void onAfterRespond(Map<String, Component> map, - AjaxRequestTarget.IJavaScriptResponse response) + public void onAfterRespond(Map<String, Component> map, AjaxRequestTarget target) { - onAfterRespondExecuted = true; + target.prependJavaScript("AFTER_RESPOND_PREPEND"); + target.appendJavaScript("AFTER_RESPOND_APPEND"); + } + + @Override + public void onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler) { + if (handler instanceof AjaxRequestHandler) { + try { + ((AjaxRequestHandler) handler).appendJavaScript("FAIL"); + + fail("appendJavaScript should not be allowed at this state"); + } catch (IllegalStateException javascriptFrozen) { + } + + try { + ((AjaxRequestHandler) handler).prependJavaScript("FAIL"); + + fail("prependJavaScript should not be allowed at this state"); + } catch (IllegalStateException javascriptFrozen) { + } + } } }