Updated Branches: refs/heads/WICKET-5297-ajax-repaint-with-animation 00cbf54d8 -> 881f1a9b7
WICKET-5297 Animate ajax DOM manipulation smoothly Re-order automatically any Effect JavaScript so the one with the longest duration is executed last and has notify=true, so any following JavaScripts should wait for it. Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/881f1a9b Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/881f1a9b Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/881f1a9b Branch: refs/heads/WICKET-5297-ajax-repaint-with-animation Commit: 881f1a9b7e0ece194cb23f4b945773effbe56f4e Parents: 00cbf54 Author: Martin Tzvetanov Grigorov <mgrigo...@apache.org> Authored: Tue Oct 1 16:58:19 2013 +0200 Committer: Martin Tzvetanov Grigorov <mgrigo...@apache.org> Committed: Tue Oct 1 16:58:19 2013 +0200 ---------------------------------------------------------------------- .../apache/wicket/ajax/AjaxRequestHandler.java | 59 +++++++++++++++++- .../org/apache/wicket/ajax/XmlAjaxResponse.java | 24 +++++++- .../ajax/effects/DisplayNoneBehavior.java | 16 +++++ .../org/apache/wicket/ajax/effects/Effect.java | 65 +++++++++++++++++--- .../org/apache/wicket/ajax/effects/Effects.java | 21 ++++++- 5 files changed, 171 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/881f1a9b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java ---------------------------------------------------------------------- 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 3c6faf1..ba67bb8 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 @@ -18,6 +18,7 @@ package org.apache.wicket.ajax; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -28,6 +29,7 @@ import org.apache.wicket.Application; import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; import org.apache.wicket.Page; +import org.apache.wicket.ajax.effects.Effect; import org.apache.wicket.core.request.handler.PageProvider; import org.apache.wicket.core.request.handler.RenderPageRequestHandler; import org.apache.wicket.core.request.handler.logger.PageLogData; @@ -169,11 +171,66 @@ public class AjaxRequestHandler implements AjaxRequestTarget listenersFrozen = false; } - }; + + addListener(new EffectsListener()); + } + + /** + * A listener that reorders any Effect prepend/append JavaScripts. + * It also sets notify = true to the last effect. This way any other JavaScripts + * should wait the effect to finish to be executed. + */ + private class EffectsListener extends AbstractListener + { + @Override + public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) + { + super.onBeforeRespond(map, target); + + Collections.sort(responseObject.prependJavaScripts, new EffectComparator()); + notifyLast(responseObject.prependJavaScripts); + + Collections.sort(responseObject.appendJavaScripts, new EffectComparator()); + notifyLast(responseObject.appendJavaScripts); + } + + private void notifyLast(List<CharSequence> effects) + { + if (effects != null && effects.isEmpty() == false) + { + for (int i = effects.size() - 1; i >= 0; i--) + { + CharSequence sequence = effects.get(i); + if (sequence instanceof Effect) + { + ((Effect) sequence).setNotify(true); + break; + } + } + } + } } /** + * Used to re-order the Effect append/prepend JavaScripts + */ + private static class EffectComparator implements Comparator<CharSequence> + { + @Override + public int compare(CharSequence o1, CharSequence o2) + { + if (o1 instanceof Effect && o2 instanceof Effect) + { + Effect e1 = (Effect) o1; + Effect e2 = (Effect) o2; + return e1.getDuration().compareTo(e2.getDuration()); + } + return 0; + } + }; + + /** * @see org.apache.wicket.core.request.handler.IPageRequestHandler#getPage() */ @Override http://git-wip-us.apache.org/repos/asf/wicket/blob/881f1a9b/wicket-core/src/main/java/org/apache/wicket/ajax/XmlAjaxResponse.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/XmlAjaxResponse.java b/wicket-core/src/main/java/org/apache/wicket/ajax/XmlAjaxResponse.java index 80c056e..b59e4e9 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/XmlAjaxResponse.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/XmlAjaxResponse.java @@ -17,6 +17,7 @@ package org.apache.wicket.ajax; import java.util.Collection; +import java.util.regex.Pattern; import org.apache.wicket.Component; import org.apache.wicket.Page; @@ -43,6 +44,8 @@ public abstract class XmlAjaxResponse extends AbstractAjaxResponse { private static final Logger LOG = LoggerFactory.getLogger(XmlAjaxResponse.class); + private static final Pattern EVALUATION_WITH_NOTIFY = Pattern.compile("^[a-zA-Z_]\\w*\\|(.|\\n)*;$"); + /** * The name of the root element in the produced XML document. */ @@ -190,7 +193,6 @@ public abstract class XmlAjaxResponse extends AbstractAjaxResponse protected void writeNormalEvaluations(final Response response, final Collection<CharSequence> scripts) { writeEvaluations(response, "evaluate", scripts); - } @Override @@ -206,9 +208,25 @@ public abstract class XmlAjaxResponse extends AbstractAjaxResponse StringBuilder combinedScript = new StringBuilder(1024); for (CharSequence script : scripts) { - combinedScript.append("(function(){").append(script).append("})();"); + String s = script.toString(); + if (EVALUATION_WITH_NOTIFY.matcher(s).matches()) + { + if (combinedScript.length() > 0) + { + writeEvaluation(elementName, response, combinedScript); + combinedScript.setLength(0); + writeEvaluation(elementName, response, "(function(){" + s + "})();"); + } + } + else + { + combinedScript.append("(function(){").append(s).append("})();"); + } + } + if (combinedScript.length() > 0) + { + writeEvaluation(elementName, response, combinedScript); } - writeEvaluation(elementName, response, combinedScript); } } http://git-wip-us.apache.org/repos/asf/wicket/blob/881f1a9b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/DisplayNoneBehavior.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/effects/DisplayNoneBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/DisplayNoneBehavior.java index d62e8c1..33fa552 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/effects/DisplayNoneBehavior.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/DisplayNoneBehavior.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.wicket.ajax.effects; import org.apache.wicket.Component; http://git-wip-us.apache.org/repos/asf/wicket/blob/881f1a9b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effect.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effect.java b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effect.java index 2110631..2f179c2 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effect.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effect.java @@ -1,6 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.wicket.ajax.effects; -import org.apache.wicket.Component; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.time.Duration; @@ -8,7 +23,7 @@ import org.apache.wicket.util.time.Duration; * An effect is responsible to render the JavaScript that should be * used to show the animation effect. */ -public class Effect +public class Effect implements CharSequence { /** * The default duration of all effects which do not specify @@ -28,13 +43,15 @@ public class Effect */ private Duration duration; + private String componentMarkupId; + /** * A flag indicating whether the animation should suspend * the execution of other Ajax response evaluations. * By default effects notify when they are finished and other * evaluations can be executed. */ - private boolean notify = true; + private boolean notify = false; /** * Constructor. @@ -88,23 +105,31 @@ public class Effect return this; } + public String getComponentMarkupId() + { + return componentMarkupId; + } + + public Effect setComponentMarkupId(String componentMarkupId) + { + this.componentMarkupId = componentMarkupId; + return this; + } + /** * Constructs JavaScript like: Wicket.Effect['name']('componentMarkupId', duration) * - * @param component * @return the JavaScript used to execute the effect */ - public CharSequence toJavaScript(Component component) + private CharSequence toJavaScript() { - Args.notNull(component, "component"); - StringBuilder js = new StringBuilder(); if (isNotify()) { js.append("notify|"); } js.append("Wicket.Effect['").append(name).append("']"); - js.append("('").append(component.getMarkupId()).append("', ") + js.append("('").append(getComponentMarkupId()).append("', ") .append(getDuration().getMilliseconds()); if (isNotify()) { @@ -114,4 +139,28 @@ public class Effect return js; } + + @Override + public int length() + { + return toJavaScript().length(); + } + + @Override + public char charAt(int index) + { + return toJavaScript().charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) + { + return toJavaScript().subSequence(start, end); + } + + @Override + public String toString() + { + return toJavaScript().toString(); + } } http://git-wip-us.apache.org/repos/asf/wicket/blob/881f1a9b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effects.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effects.java b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effects.java index c40ffad..a45a98a 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effects.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/effects/Effects.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.wicket.ajax.effects; import org.apache.wicket.Component; @@ -45,11 +61,12 @@ public class Effects component.add(new DisplayNoneBehavior()); - target.prependJavaScript(hide.toJavaScript(component)); + String markupId = component.getMarkupId(); + target.prependJavaScript(hide.setComponentMarkupId(markupId)); target.add(component); - target.appendJavaScript(show.toJavaScript(component)); + target.appendJavaScript(show.setComponentMarkupId(markupId)); } /*