Updated Branches: refs/heads/wicket-6.x 84a3b04f3 -> ae9f4fe4a
WICKET-5439 backported from 7.x, but still update the hosting component on restart as before; WICKET-5464 don't stop onRemove, just clear the timer Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/ae9f4fe4 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/ae9f4fe4 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/ae9f4fe4 Branch: refs/heads/wicket-6.x Commit: ae9f4fe4afddbe9cc8804c7710cb336a2e0d6034 Parents: 84a3b04 Author: svenmeier <[email protected]> Authored: Wed Jan 8 21:15:06 2014 +0100 Committer: svenmeier <[email protected]> Committed: Wed Jan 8 21:15:06 2014 +0100 ---------------------------------------------------------------------- .../wicket/ajax/AbstractAjaxTimerBehavior.java | 107 +++++-- .../wicket/ajax/AjaxTimerBehaviorTest.java | 292 +++++++++++-------- 2 files changed, 255 insertions(+), 144 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/ae9f4fe4/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java index f4acfc8..8582f43 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java @@ -22,7 +22,6 @@ import org.apache.wicket.core.util.string.JavaScriptUtils; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.markup.head.OnLoadHeaderItem; -import org.apache.wicket.request.http.WebRequest; import org.apache.wicket.util.time.Duration; /** @@ -43,7 +42,10 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav private boolean stopped = false; - private boolean headRendered = false; + /** + * Is the timeout present in JavaScript already. + */ + private boolean hasTimeout = false; /** * Construct. @@ -86,15 +88,19 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav { super.renderHead(component, response); - response.render(JavaScriptHeaderItem.forScript("if (typeof(Wicket.TimerHandles) === 'undefined') {Wicket.TimerHandles = {}}", + response.render(JavaScriptHeaderItem.forScript( + "if (typeof(Wicket.TimerHandles) === 'undefined') {Wicket.TimerHandles = {}}", WICKET_TIMERS_ID)); - WebRequest request = (WebRequest) component.getRequest(); + if (component.getRequestCycle().find(AjaxRequestTarget.class) == null) + { + // complete page is rendered, so timeout has to be rendered again + hasTimeout = false; + } - if (!isStopped() && (!headRendered || !request.isAjax())) + if (isStopped() == false) { - headRendered = true; - response.render(OnLoadHeaderItem.forScript(getJsTimeoutCall(updateInterval))); + addTimeout(response); } } @@ -134,10 +140,16 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav if (shouldTrigger()) { - target.getHeaderResponse().render( - OnLoadHeaderItem.forScript(getJsTimeoutCall(updateInterval))); + // re-add timeout + hasTimeout = false; + + addTimeout(target.getHeaderResponse()); + + return; } } + + clearTimeout(target.getHeaderResponse()); } /** @@ -172,29 +184,77 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav /** * Re-enables the timer if already stopped - * + * * @param target + * may be null */ public final void restart(final AjaxRequestTarget target) { - if (isStopped()) + if (stopped == true) { stopped = false; - headRendered = false; - target.add(getComponent()); + + if (target != null) + { + addTimeout(target.getHeaderResponse()); + + onRestart(target); + } + } + } + + /** + * Called when this timer is restarted adds this component to the target on + * restart. <br> + * Note: This method will be removed in Wicket 7.x, thus the hosting + * component will no longer be updated on each restart. + * + * @param target + * current target + */ + protected void onRestart(AjaxRequestTarget target) + { + target.add(getComponent()); + } + + private void addTimeout(IHeaderResponse headerResponse) + { + if (hasTimeout == false) + { + hasTimeout = true; + + headerResponse.render(OnLoadHeaderItem.forScript(getJsTimeoutCall(updateInterval))); + } + } + + private void clearTimeout(IHeaderResponse headerResponse) + { + if (hasTimeout) + { + hasTimeout = false; + + String timeoutHandle = getTimeoutHandle(); + headerResponse.render(OnLoadHeaderItem.forScript("clearTimeout(" + timeoutHandle + + "); delete " + timeoutHandle + ";")); } } /** - * Stops the timer + * Stops the timer. + * + * @param target + * may be null */ public final void stop(final AjaxRequestTarget target) { - if (headRendered && stopped == false) + if (stopped == false) { stopped = true; - String timeoutHandle = getTimeoutHandle(); - target.prependJavaScript("clearTimeout("+timeoutHandle+"); delete "+timeoutHandle+";"); + + if (target != null) + { + clearTimeout(target.getHeaderResponse()); + } } } @@ -204,8 +264,17 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav AjaxRequestTarget target = component.getRequestCycle().find(AjaxRequestTarget.class); if (target != null) { - stop(target); + clearTimeout(target.getHeaderResponse()); + } + } + + @Override + protected void onUnbind() + { + AjaxRequestTarget target = getComponent().getRequestCycle().find(AjaxRequestTarget.class); + if (target != null) + { + clearTimeout(target.getHeaderResponse()); } - super.detach(component); } } http://git-wip-us.apache.org/repos/asf/wicket/blob/ae9f4fe4/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxTimerBehaviorTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxTimerBehaviorTest.java b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxTimerBehaviorTest.java index 351c149..8adb45d 100644 --- a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxTimerBehaviorTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxTimerBehaviorTest.java @@ -16,9 +16,7 @@ */ package org.apache.wicket.ajax; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import org.apache.wicket.Component; import org.apache.wicket.MockPageWithLinkAndComponent; import org.apache.wicket.WicketTestCase; import org.apache.wicket.ajax.markup.html.AjaxLink; @@ -47,13 +45,14 @@ public class AjaxTimerBehaviorTest extends WicketTestCase * Tests timer behavior in a component added to an AjaxRequestTarget */ @Test - public void addToAjaxUpdate() + public void addedInAjaxSetsTimout() { Duration dur = Duration.seconds(20); - final MyAjaxSelfUpdatingTimerBehavior timer = new MyAjaxSelfUpdatingTimerBehavior(dur); + final AjaxSelfUpdatingTimerBehavior timer = new AjaxSelfUpdatingTimerBehavior(dur); final MockPageWithLinkAndComponent page = new MockPageWithLinkAndComponent(); - page.add(new WebComponent(MockPageWithLinkAndComponent.COMPONENT_ID).setOutputMarkupId(true)); + page.add(new WebComponent(MockPageWithLinkAndComponent.COMPONENT_ID) + .setOutputMarkupId(true)); page.add(new AjaxLink<Void>(MockPageWithLinkAndComponent.LINK_ID) @@ -75,8 +74,12 @@ public class AjaxTimerBehaviorTest extends WicketTestCase tester.startPage(page); tester.clickLink(MockPageWithLinkAndComponent.LINK_ID); - validate(timer, false); + // first render sets timeout + assertMatches("setTimeout", 1); + + tester.executeBehavior(timer); + assertMatches("setTimeout", 1); } @@ -84,10 +87,10 @@ public class AjaxTimerBehaviorTest extends WicketTestCase * tests timer behavior in a WebPage. */ @Test - public void addToWebPage() + public void pageRenderSetsTimeout() { Duration dur = Duration.seconds(20); - final MyAjaxSelfUpdatingTimerBehavior timer = new MyAjaxSelfUpdatingTimerBehavior(dur); + final AjaxSelfUpdatingTimerBehavior timer = new AjaxSelfUpdatingTimerBehavior(dur); final MockPageWithLinkAndComponent page = new MockPageWithLinkAndComponent(); Label label = new Label(MockPageWithLinkAndComponent.COMPONENT_ID, "Hello"); page.add(label); @@ -106,21 +109,150 @@ public class AjaxTimerBehaviorTest extends WicketTestCase tester.startPage(page); - validate(timer, true); + assertMatches("setTimeout", 1); + + tester.clickLink(MockPageWithLinkAndComponent.LINK_ID); + + assertMatches("setTimeout", 1); + + tester.executeBehavior(timer); + + assertMatches("setTimeout", 1); + } + + /** + * tests timer behavior in a WebPage. + */ + @Test + public void ajaxUpdateDoesNotSetTimeout() + { + Duration dur = Duration.seconds(20); + final AjaxSelfUpdatingTimerBehavior timer = new AjaxSelfUpdatingTimerBehavior(dur); + final MockPageWithLinkAndComponent page = new MockPageWithLinkAndComponent(); + final Label label = new Label(MockPageWithLinkAndComponent.COMPONENT_ID, "Hello"); + page.add(label); + page.add(new AjaxLink<Void>(MockPageWithLinkAndComponent.LINK_ID) + { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) + { + target.add(label); + } + }); + label.setOutputMarkupId(true); + label.add(timer); + + tester.startPage(page); + + assertMatches("setTimeout", 1); + + tester.clickLink(MockPageWithLinkAndComponent.LINK_ID); + + // ajax update does not set timeout + assertMatches("setTimeout", 0); + + tester.executeBehavior(timer); + + assertMatches("setTimeout", 1); + } + + + /** + */ + @Test + public void setVisibleSetsTimeout() + { + Duration dur = Duration.seconds(20); + final AjaxSelfUpdatingTimerBehavior timer = new AjaxSelfUpdatingTimerBehavior(dur); + final MockPageWithLinkAndComponent page = new MockPageWithLinkAndComponent(); + final Label label = new Label(MockPageWithLinkAndComponent.COMPONENT_ID, "Hello"); + page.add(label); + page.add(new AjaxLink<Void>(MockPageWithLinkAndComponent.LINK_ID) + { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) + { + } + }); + label.setOutputMarkupId(true); + label.setVisible(false); + label.add(timer); + + tester.startPage(page); + + assertMatches("setTimeout", 0); tester.clickLink(MockPageWithLinkAndComponent.LINK_ID); - validate(timer, true); + assertMatches("setTimeout", 0); + + label.setVisible(true); + tester.startPage(page); + + // no visible, so timeout is set + assertMatches("setTimeout", 1); } /** - * Validates the response, then makes sure the timer injects itself again when called. - * Tests {@link AbstractAjaxTimerBehavior#restart(AjaxRequestTarget)} method + */ + @Test + public void setDisabledClearsTimeout() + { + final AbstractAjaxTimerBehavior timer = new AbstractAjaxTimerBehavior(Duration.seconds(20)) + { + private boolean enabled = true; + @Override + protected void onTimer(AjaxRequestTarget target) + { + enabled = false; + } + + @Override + public boolean isEnabled(Component component) + { + return enabled; + } + }; + final MockPageWithLinkAndComponent page = new MockPageWithLinkAndComponent(); + final Label label = new Label(MockPageWithLinkAndComponent.COMPONENT_ID, "Hello"); + page.add(label); + page.add(new Link<Void>(MockPageWithLinkAndComponent.LINK_ID) + { + private static final long serialVersionUID = 1L; + + @Override + public void onClick() + { + } + }); + label.setOutputMarkupId(true); + label.add(timer); + + tester.startPage(page); + + assertMatches("setTimeout", 1); + + tester.executeBehavior(timer); + + assertMatches("clearTimeout", 1); + assertMatches("setTimeout", 0); + } + + /** + * Validates the response, then makes sure the timer injects itself again + * when called. Tests + * {@link AbstractAjaxTimerBehavior#restart(AjaxRequestTarget)} method + * * WICKET-1525, WICKET-2152 */ - public void testRestartMethod() + @Test + public void restartResultsInAddTimeout() { final Integer labelInitialValue = Integer.valueOf(0); @@ -190,6 +322,11 @@ public class AjaxTimerBehaviorTest extends WicketTestCase // restart the timer tester.clickLink(MockPageWithLinkAndComponent.LINK_ID); + assertMatches("setTimeout", 1); + // label is updated automatically (this will no longer be the case in + // Wicket 7.x) + assertMatches("wicket:id=\"component\"", 1); + // increment to 2 tester.executeBehavior(timerBehavior); @@ -198,128 +335,33 @@ public class AjaxTimerBehaviorTest extends WicketTestCase } /** - * Validates the reponse, then makes sure the timer injects itself again when called. + * Validates the reponse, then makes sure the timer injects itself again + * when called. * * @param timer - * @param inBodyOnLoad + * @param wasAjax */ - private void validate(MyAjaxSelfUpdatingTimerBehavior timer, boolean inBodyOnLoad) + private void assertMatches(String string, int count) { String document = tester.getLastResponseAsString(); - String updateScript = timer.getUpdateScript(); - - if (inBodyOnLoad) - { - String bodyOnLoadUpdateScript = "Wicket.Event.add(window, \"load\", function(event) { \n" + - updateScript + ";\n;});"; - validateTimerScript(document, bodyOnLoadUpdateScript); - } - else - { - updateScript = updateScript.replaceAll("]", "]^"); - validateTimerScript(document, updateScript); - } - - tester.executeBehavior(timer); - - if (inBodyOnLoad) - { - updateScript = timer.getUpdateScript(); - updateScript = updateScript.replaceAll("]", "]^"); - } - - // Validate the document - document = tester.getLastResponseAsString(); - validateTimerScript(document, updateScript); - } - - /** - * Checks that the timer javascript is in the document once and only once - * - * @param document - * the response from the Application - * @param updateScript - * the timer script - */ - private void validateTimerScript(String document, String updateScript) - { log.debug(document); - String quotedRegex; - quotedRegex = quote(updateScript); - Pattern pat = Pattern.compile(quotedRegex, Pattern.DOTALL); - Matcher mat = pat.matcher(document); - int count = 0; - while (mat.find()) + int found = 0; + int lastIndex = 0; + while (true) { - ++count; - } - // make sure there is only one match - assertEquals("There should be 1 and only 1 script in the markup for this behavior," + - "but " + count + " were found", 1, count); - } + lastIndex = document.indexOf(string, lastIndex); - // quick fix for JDK 5 method - private static final String quote(String s) - { - int slashEIndex = s.indexOf("\\E"); - if (slashEIndex == -1) - { - return "\\Q" + s + "\\E"; - } - - StringBuilder sb = new StringBuilder(s.length() * 2); - sb.append("\\Q"); - slashEIndex = 0; - int current = 0; - while ((slashEIndex = s.indexOf("\\E", current)) != -1) - { - sb.append(s.substring(current, slashEIndex)); - current = slashEIndex + 2; - sb.append("\\E\\\\E\\Q"); - } - sb.append(s.substring(current, s.length())); - sb.append("\\E"); - return sb.toString(); - } - - static class MyAjaxSelfUpdatingTimerBehavior extends AjaxSelfUpdatingTimerBehavior - { - - /** - * - */ - private static final long serialVersionUID = 1L; - private final Duration duration; - String updateScript; - - /** - * Construct. - * - * @param updateInterval - */ - public MyAjaxSelfUpdatingTimerBehavior(Duration updateInterval) - { - super(updateInterval); - duration = updateInterval; - } - - @Override - protected void onComponentRendered() - { - super.onComponentRendered(); - updateScript = getJsTimeoutCall(duration); - } + if (lastIndex == -1) + { + break; + } - /** - * @return Update script - */ - public String getUpdateScript() - { - return updateScript; + found++; + lastIndex += string.length(); } - + assertEquals(count, found); } -} +} \ No newline at end of file
