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 2012/01/13 14:47:16 UTC
[1/2] git commit: WICKET-4326 Make AjaxRequestTarget an interface and
move the impl to AjaxRequestHandler
Updated Branches:
refs/heads/master 2989237bf -> c2b44cca9
WICKET-4326
Make AjaxRequestTarget an interface and move the impl to AjaxRequestHandler
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/c2b44cca
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/c2b44cca
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/c2b44cca
Branch: refs/heads/master
Commit: c2b44cca9b37d58bc8e23eea6e62e1dcfb330719
Parents: 2989237
Author: martin-g <mg...@apache.org>
Authored: Sat Jan 7 11:25:52 2012 +0200
Committer: martin-g <mg...@apache.org>
Committed: Fri Jan 13 15:45:22 2012 +0200
----------------------------------------------------------------------
.../src/main/java/org/apache/wicket/Behaviors.java | 3 +-
.../wicket/ajax/AbstractAjaxTimerBehavior.java | 8 +-
.../org/apache/wicket/ajax/AjaxEventBehavior.java | 8 +-
.../org/apache/wicket/ajax/AjaxRequestHandler.java | 1129 +++++++++++++
.../org/apache/wicket/ajax/AjaxRequestTarget.java | 1258 +--------------
.../ajax/AjaxRequestTargetListenerCollection.java | 2 +-
.../wicket/ajax/AjaxSelfUpdatingTimerBehavior.java | 2 +-
.../AjaxFormChoiceComponentUpdatingBehavior.java | 6 +-
.../form/AjaxFormComponentUpdatingBehavior.java | 5 +-
.../wicket/ajax/markup/html/AjaxFallbackLink.java | 4 -
.../wicket/ajax/markup/html/form/AjaxButton.java | 8 -
.../wicket/ajax/markup/html/form/AjaxCheckBox.java | 2 +-
.../ajax/markup/html/form/AjaxFallbackButton.java | 2 +-
.../wicket/markup/head/ResourceAggregator.java | 8 +-
.../head/filter/FilteringHeaderResponse.java | 2 +-
.../org/apache/wicket/markup/html/image/Image.java | 4 +-
.../wicket/markup/html/image/NonCachingImage.java | 2 +-
.../wicket/markup/html/tree/AbstractTree.java | 10 +-
.../apache/wicket/markup/html/tree/BaseTree.java | 4 +-
.../protocol/http/AjaxEnclosureListener.java | 4 +-
.../wicket/protocol/http/WebApplication.java | 19 +-
.../apache/wicket/request/cycle/RequestCycle.java | 27 +
.../wicket/util/tester/BaseWicketTester.java | 17 +-
.../apache/wicket/util/tester/WicketTester.java | 5 +-
.../java/org/apache/wicket/MockPanelWithLink.java | 2 +-
...ResponseAtInterceptPageExceptionInAjaxTest.java | 7 -
.../apache/wicket/ajax/AjaxRequestHandlerTest.java | 361 +++++
.../apache/wicket/ajax/AjaxRequestTargetTest.java | 361 -----
.../wicket/markup/html/HeaderContributorTest.java | 4 +-
.../markup/html/TransparentWithAjaxUpdatePage.java | 2 +-
.../internal/TraditionalEnclosureAjaxPage.java | 1 -
.../AbstractTransformerBehaviorTest.java | 4 +-
.../wicket/request/handler/PageIdPoliticTest.java | 1 -
.../wicket/response/filter/ResponseFilterTest.java | 1 -
.../wicket/util/tester/WicketTesterTest.java | 1 -
.../wicket/extensions/yui/calendar/DatePicker.java | 7 +-
.../wicket/examples/ajax/builtin/EffectsPage.java | 2 +-
.../wicket/examples/ajax/builtin/GuestBook.java | 8 +-
.../wicket/examples/ajax/builtin/LinksPage.java | 4 +-
.../wicket/examples/ajax/builtin/TodoList.java | 2 +-
.../examples/ajax/builtin/tree/BaseTreePage.java | 1 -
.../examples/resourcedecoration/HomePage.java | 2 +-
.../apache/wicket/examples/source/SourcesPage.java | 34 +-
.../org/apache/wicket/examples/StartExamples.java | 2 +
.../ajax/markup/html/AjaxEditableLabel.java | 14 +-
.../ajax/markup/html/AjaxIndicatorAppender.java | 2 +-
.../ajax/markup/html/AjaxLazyLoadPanel.java | 4 +-
.../autocomplete/AbstractAutoCompleteBehavior.java | 2 +-
.../ajax/markup/html/modal/ModalWindow.java | 16 +-
.../data/sort/AjaxFallbackOrderByLink.java | 2 +-
.../repeater/data/table/AjaxNavigationToolbar.java | 2 +-
.../captcha/kittens/KittenCaptchaPanel.java | 29 +-
.../markup/html/tree/DefaultAbstractTree.java | 2 +-
.../wicket/extensions/rating/RatingPanel.java | 2 +-
.../apache/wicket/proxy/util/InterfaceObject.java | 1 -
55 files changed, 1720 insertions(+), 1702 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/Behaviors.java b/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
index eb7e25d..2936d8a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.behavior.InvalidBehaviorIdException;
import org.apache.wicket.model.IDetachable;
@@ -129,7 +128,7 @@ final class Behaviors implements IDetachable
* THIS IS WICKET INTERNAL ONLY. DO NOT USE IT.
*
* Traverses all behaviors and calls detachModel() on them. This is needed to cleanup behavior
- * after render. This method is necessary for {@link AjaxRequestTarget} to be able to cleanup
+ * after render. This method is necessary for {@link org.apache.wicket.ajax.AjaxRequestTarget} to be able to cleanup
* component's behaviors after header contribution has been done (which is separated from
* component render).
*/
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/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 eb765df..e6fd084 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
@@ -52,11 +52,7 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav
*/
public AbstractAjaxTimerBehavior(final Duration updateInterval)
{
- if (updateInterval == null || updateInterval.getMilliseconds() <= 0)
- {
- throw new IllegalArgumentException("Invalid update interval");
- }
- this.updateInterval = updateInterval;
+ setUpdateInterval(updateInterval);
}
/**
@@ -132,7 +128,7 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav
/**
*
- * @see org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#respond(org.apache.wicket.ajax.AjaxRequestTarget)
+ * @see org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#respond(AjaxRequestTarget)
*/
@Override
protected final void respond(final AjaxRequestTarget target)
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/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 c385a90..a011cb8 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
@@ -17,14 +17,10 @@
package org.apache.wicket.ajax;
import org.apache.wicket.Component;
-import org.apache.wicket.IClusterable;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
-import org.apache.wicket.ajax.attributes.ThrottlingSettings;
-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;
-import org.apache.wicket.util.time.Duration;
/**
* An ajax behavior that is attached to a certain client-side (usually javascript) event, such as
@@ -99,7 +95,7 @@ public abstract class AjaxEventBehavior extends AbstractDefaultAjaxBehavior
js.append(");");
- AjaxRequestTarget target = AjaxRequestTarget.get();
+ AjaxRequestTarget target = getComponent().getRequestCycle().find(AjaxRequestTarget.class);
if (target == null)
{
response.render(OnDomReadyHeaderItem.forScript(js.toString()));
@@ -130,7 +126,7 @@ public abstract class AjaxEventBehavior extends AbstractDefaultAjaxBehavior
/**
*
- * @see org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#respond(org.apache.wicket.ajax.AjaxRequestTarget)
+ * @see org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#respond(AjaxRequestTarget)
*/
@Override
protected final void respond(final AjaxRequestTarget target)
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/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
new file mode 100644
index 0000000..cb95e09
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java
@@ -0,0 +1,1129 @@
+/*
+ * 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;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.Page;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.head.internal.HeaderResponse;
+import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
+import org.apache.wicket.markup.parser.filter.HtmlHeaderSectionHandler;
+import org.apache.wicket.markup.repeater.AbstractRepeater;
+import org.apache.wicket.request.IRequestCycle;
+import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.request.component.IRequestablePage;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.handler.PageProvider;
+import org.apache.wicket.request.handler.RenderPageRequestHandler;
+import org.apache.wicket.request.handler.logger.PageLogData;
+import org.apache.wicket.request.http.WebRequest;
+import org.apache.wicket.request.http.WebResponse;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.markup.head.HeaderItem;
+import org.apache.wicket.markup.head.OnLoadHeaderItem;
+import org.apache.wicket.response.StringResponse;
+import org.apache.wicket.response.filter.IResponseFilter;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.lang.Generics;
+import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.visit.IVisit;
+import org.apache.wicket.util.visit.IVisitor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A request target that produces ajax response envelopes used on the client side to update
+ * component markup as well as evaluate arbitrary javascript.
+ * <p>
+ * A component whose markup needs to be updated should be added to this target via
+ * AjaxRequestTarget#add(Component) method. Its body will be rendered and added to the
+ * envelope when the target is processed, and refreshed on the client side when the ajax response is
+ * received.
+ * <p>
+ * It is important that the component whose markup needs to be updated contains an id attribute in
+ * the generated markup that is equal to the value retrieved from Component#getMarkupId(). This can
+ * be accomplished by either setting the id attribute in the html template, or using an attribute
+ * modifier that will add the attribute with value Component#getMarkupId() to the tag ( such as
+ * MarkupIdSetter )
+ * <p>
+ * Any javascript that needs to be evaluated on the client side can be added using
+ * AjaxRequestTarget#append/prependJavaScript(String). For example, this feature can be useful when
+ * it is desirable to link component update with some javascript effects.
+ * <p>
+ * The target provides a listener interface {@link AjaxRequestTarget.IListener} that can be used to add code that
+ * responds to various target events by adding listeners via
+ * {@link #addListener(AjaxRequestTarget.IListener)}
+ *
+ * @since 1.2
+ *
+ * @author Igor Vaynberg (ivaynberg)
+ * @author Eelco Hillenius
+ */
+public class AjaxRequestHandler implements AjaxRequestTarget
+{
+
+ /**
+ * Response that uses an encoder to encode its contents
+ *
+ * @author Igor Vaynberg (ivaynberg)
+ */
+ private static final class AjaxResponse extends Response
+ {
+ private final AppendingStringBuffer buffer = new AppendingStringBuffer(256);
+
+ private boolean escaped = false;
+
+ private final Response originalResponse;
+
+ /**
+ * Construct.
+ *
+ * @param originalResponse
+ */
+ private AjaxResponse(Response originalResponse)
+ {
+ this.originalResponse = originalResponse;
+ }
+
+ /**
+ * @see org.apache.wicket.request.Response#encodeURL(CharSequence)
+ */
+ @Override
+ public String encodeURL(CharSequence url)
+ {
+ return originalResponse.encodeURL(url);
+ }
+
+ /**
+ * @return contents of the response
+ */
+ public CharSequence getContents()
+ {
+ return buffer;
+ }
+
+ /**
+ * @return true if any escaping has been performed, false otherwise
+ */
+ public boolean isContentsEncoded()
+ {
+ return escaped;
+ }
+
+ /**
+ * @see org.apache.wicket.request.Response#write(CharSequence)
+ */
+ @Override
+ public void write(CharSequence cs)
+ {
+ String string = cs.toString();
+ if (needsEncoding(string))
+ {
+ string = encode(string);
+ escaped = true;
+ buffer.append(string);
+ }
+ else
+ {
+ buffer.append(cs);
+ }
+ }
+
+ /**
+ * Resets the response to a clean state so it can be reused to save on garbage.
+ */
+ @Override
+ public void reset()
+ {
+ buffer.clear();
+ escaped = false;
+ }
+
+ @Override
+ public void write(byte[] array)
+ {
+ throw new UnsupportedOperationException("Cannot write binary data.");
+ }
+
+ @Override
+ public void write(byte[] array, int offset, int length)
+ {
+ throw new UnsupportedOperationException("Cannot write binary data.");
+ }
+
+ @Override
+ public Object getContainerResponse()
+ {
+ return originalResponse.getContainerResponse();
+ }
+ }
+
+ private static final Logger log = LoggerFactory.getLogger(AjaxRequestHandler.class);
+
+ private final List<CharSequence> appendJavaScripts = Generics.newArrayList();
+
+ private final List<CharSequence> domReadyJavaScripts = Generics.newArrayList();
+
+ /**
+ * Create a response for component body and javascript that will escape output to make it safe
+ * to use inside a CDATA block
+ */
+ private final AjaxResponse encodingBodyResponse;
+
+ /**
+ * Response for header contribution that will escape output to make it safe to use inside a
+ * CDATA block
+ */
+ private final AjaxResponse encodingHeaderResponse;
+
+ /** the component instances that will be rendered */
+ private final Map<String, Component> markupIdToComponent = new LinkedHashMap<String, Component>();
+
+ /** */
+ private final List<CharSequence> prependJavaScripts = Generics.newArrayList();
+
+ /** a list of listeners */
+ private List<AjaxRequestTarget.IListener> listeners = null;
+
+ /** */
+ private final Set<ITargetRespondListener> respondListeners = new HashSet<ITargetRespondListener>();
+
+ /** The associated Page */
+ private final Page page;
+
+ /** see https://issues.apache.org/jira/browse/WICKET-3564 */
+ private transient boolean componentsFrozen;
+ private transient boolean listenersFrozen;
+ private transient boolean respondersFrozen;
+
+ private PageLogData logData;
+
+ /**
+ * Constructor
+ *
+ * @param page
+ */
+ public AjaxRequestHandler(Page page)
+ {
+ this.page = Args.notNull(page, "page");
+ Response response = page.getResponse();
+ encodingBodyResponse = new AjaxResponse(response);
+ encodingHeaderResponse = new AjaxResponse(response);
+ }
+
+ /**
+ * @see org.apache.wicket.request.handler.IPageRequestHandler#getPage()
+ */
+ @Override
+ public Page getPage()
+ {
+ return page;
+ }
+
+ private void assertNotFrozen(boolean frozen, Class<?> clazz)
+ {
+ if (frozen)
+ {
+ throw new IllegalStateException(clazz.getSimpleName() + "s can no " +
+ " longer be added");
+ }
+ }
+
+ private void assertListenersNotFrozen()
+ {
+ assertNotFrozen(listenersFrozen, AjaxRequestTarget.IListener.class);
+ }
+
+ private void assertComponentsNotFrozen()
+ {
+ assertNotFrozen(componentsFrozen, Component.class);
+ }
+
+ private void assertRespondersNotFrozen()
+ {
+ assertNotFrozen(respondersFrozen, ITargetRespondListener.class);
+ }
+
+ @Override
+ public void addListener(AjaxRequestTarget.IListener listener) throws IllegalStateException
+ {
+ Args.notNull(listener, "listener");
+ assertListenersNotFrozen();
+
+ if (listeners == null)
+ {
+ listeners = new LinkedList<AjaxRequestTarget.IListener>();
+ }
+
+ if (!listeners.contains(listener))
+ {
+ listeners.add(listener);
+ }
+ }
+
+ @Override
+ public final void addChildren(MarkupContainer parent, Class<?> childCriteria)
+ {
+ Args.notNull(parent, "parent");
+ Args.notNull(childCriteria, "childCriteria");
+
+ parent.visitChildren(childCriteria, new IVisitor<Component, Void>()
+ {
+ @Override
+ public void component(final Component component, final IVisit<Void> visit)
+ {
+ add(component);
+ visit.dontGoDeeper();
+ }
+ });
+ }
+
+ @Override
+ public void add(Component... components)
+ {
+ for (final Component component : components)
+ {
+ Args.notNull(component, "component");
+
+ if (component.getOutputMarkupId() == false)
+ {
+ throw new IllegalArgumentException(
+ "cannot update component that does not have setOutputMarkupId property set to true. Component: " +
+ component.toString());
+ }
+ add(component, component.getMarkupId());
+ }
+ }
+
+ @Override
+ public final void add(final Component component, final String markupId)
+ throws IllegalArgumentException, IllegalStateException
+ {
+ Args.notEmpty(markupId, "markupId");
+ Args.notNull(component, "component");
+
+ if (component instanceof Page)
+ {
+ if (component != page)
+ {
+ throw new IllegalArgumentException("component cannot be a page");
+ }
+ }
+ else if (component instanceof AbstractRepeater)
+ {
+ throw new IllegalArgumentException(
+ "Component " +
+ component.getClass().getName() +
+ " has been added to the target. This component is a repeater and cannot be repainted via ajax directly. " +
+ "Instead add its parent or another markup container higher in the hierarchy.");
+ }
+
+ assertComponentsNotFrozen();
+
+ component.setMarkupId(markupId);
+ markupIdToComponent.put(markupId, component);
+ }
+
+ @Override
+ public final Collection<? extends Component> getComponents()
+ {
+ return Collections.unmodifiableCollection(markupIdToComponent.values());
+ }
+
+ @Override
+ public final void focusComponent(Component component)
+ {
+ if (component != null && component.getOutputMarkupId() == false)
+ {
+ throw new IllegalArgumentException(
+ "cannot update component that does not have setOutputMarkupId property set to true. Component: " +
+ component.toString());
+ }
+ final String id = component != null ? ("'" + component.getMarkupId() + "'") : "null";
+ appendJavaScript("Wicket.Focus.setFocusOnId(" + id + ");");
+ }
+
+ @Override
+ public final void appendJavaScript(CharSequence javascript)
+ {
+ Args.notNull(javascript, "javascript");
+
+ appendJavaScripts.add(javascript);
+ }
+
+ /**
+ * @see org.apache.wicket.request.handler.IPageRequestHandler#detach(org.apache.wicket.request.IRequestCycle)
+ */
+ @Override
+ public void detach(final IRequestCycle requestCycle)
+ {
+ if (logData == null)
+ logData = new PageLogData(page);
+
+ // detach the page if it was updated
+ if (markupIdToComponent.size() > 0)
+ {
+ final Component component = markupIdToComponent.values().iterator().next();
+ final Page page = component.findParent(Page.class);
+ if (page != null)
+ {
+ page.detach();
+ }
+ }
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof AjaxRequestHandler)
+ {
+ AjaxRequestHandler that = (AjaxRequestHandler)obj;
+ return markupIdToComponent.equals(that.markupIdToComponent) &&
+ prependJavaScripts.equals(that.prependJavaScripts) &&
+ appendJavaScripts.equals(that.appendJavaScripts);
+ }
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ int result = "AjaxRequestHandler".hashCode();
+ result += markupIdToComponent.hashCode() * 17;
+ result += prependJavaScripts.hashCode() * 17;
+ result += appendJavaScripts.hashCode() * 17;
+ return result;
+ }
+
+ @Override
+ public final void prependJavaScript(CharSequence javascript)
+ {
+ Args.notNull(javascript, "javascript");
+
+ prependJavaScripts.add(javascript);
+ }
+
+ @Override
+ public void registerRespondListener(ITargetRespondListener listener)
+ {
+ assertRespondersNotFrozen();
+ respondListeners.add(listener);
+ }
+
+ /**
+ * @see org.apache.wicket.request.handler.IPageRequestHandler#respond(org.apache.wicket.request.IRequestCycle)
+ */
+ @Override
+ public final void respond(final IRequestCycle requestCycle)
+ {
+ final RequestCycle rc = (RequestCycle)requestCycle;
+ final WebResponse response = (WebResponse)requestCycle.getResponse();
+
+ if (markupIdToComponent.values().contains(page))
+ {
+ // the page itself has been added to the request target, we simply issue a redirect
+ // back to the page
+ IRequestHandler handler = new RenderPageRequestHandler(new PageProvider(page));
+ final String url = rc.urlFor(handler).toString();
+ response.sendRedirect(url);
+ return;
+ }
+
+ respondersFrozen = true;
+
+ for (ITargetRespondListener listener : respondListeners)
+ {
+ listener.onTargetRespond(this);
+ }
+
+ final Application app = Application.get();
+
+ page.send(app, Broadcast.BREADTH, this);
+
+ // Determine encoding
+ final String encoding = app.getRequestCycleSettings().getResponseRequestEncoding();
+
+ // Set content type based on markup type for page
+ response.setContentType("text/xml; charset=" + encoding);
+
+ // Make sure it is not cached by a client
+ response.disableCaching();
+
+ try
+ {
+ final StringResponse bodyResponse = new StringResponse();
+ constructResponseBody(bodyResponse, encoding);
+ CharSequence filteredResponse = invokeResponseFilters(bodyResponse);
+ response.write(filteredResponse);
+ }
+ finally
+ {
+ // restore the original response
+ RequestCycle.get().setResponse(response);
+ }
+ }
+
+ /**
+ * Collects the response body (without the headers) so that it can be pre-processed before
+ * written down to the original response.
+ *
+ * @param bodyResponse
+ * the buffering response
+ * @param encoding
+ * the encoding that should be used to encode the body
+ */
+ private void constructResponseBody(final Response bodyResponse, final String encoding)
+ {
+ bodyResponse.write("<?xml version=\"1.0\" encoding=\"");
+ bodyResponse.write(encoding);
+ bodyResponse.write("\"?>");
+ bodyResponse.write("<ajax-response>");
+
+ // invoke onbeforerespond event on listeners
+ fireOnBeforeRespondListeners();
+
+ // process added components
+ respondComponents(bodyResponse);
+
+ fireOnAfterRespondListeners(bodyResponse);
+
+ // queue up prepend javascripts. unlike other steps these are executed out of order so that
+ // components can contribute them from inside their onbeforerender methods.
+ Iterator<CharSequence> it = prependJavaScripts.iterator();
+ while (it.hasNext())
+ {
+ CharSequence js = it.next();
+ respondPriorityInvocation(bodyResponse, js);
+ }
+
+
+ // execute the dom ready javascripts as first javascripts
+ // after component replacement
+ it = domReadyJavaScripts.iterator();
+ while (it.hasNext())
+ {
+ CharSequence js = it.next();
+ respondInvocation(bodyResponse, js);
+ }
+ it = appendJavaScripts.iterator();
+ while (it.hasNext())
+ {
+ CharSequence js = it.next();
+ respondInvocation(bodyResponse, js);
+ }
+
+ bodyResponse.write("</ajax-response>");
+ }
+
+ /**
+ * Runs the configured {@link IResponseFilter}s over the constructed Ajax response
+ *
+ * @param contentResponse
+ * the Ajax {@link Response} body
+ * @return filtered response
+ */
+ private AppendingStringBuffer invokeResponseFilters(final StringResponse contentResponse)
+ {
+ AppendingStringBuffer responseBuffer = new AppendingStringBuffer(
+ contentResponse.getBuffer());
+
+ List<IResponseFilter> responseFilters = Application.get()
+ .getRequestCycleSettings()
+ .getResponseFilters();
+
+ if (responseFilters != null)
+ {
+ for (IResponseFilter filter : responseFilters)
+ {
+ responseBuffer = filter.filter(responseBuffer);
+ }
+ }
+ return responseBuffer;
+ }
+
+ /**
+ * Freezes the {@link #listeners} before firing the event and un-freezes them afterwards to
+ * allow components to add more {@link AjaxRequestTarget.IListener}s for the second event.
+ */
+ private void fireOnBeforeRespondListeners()
+ {
+ listenersFrozen = true;
+
+ if (listeners != null)
+ {
+ final Map<String, Component> components = Collections.unmodifiableMap(markupIdToComponent);
+
+ for (AjaxRequestTarget.IListener listener : listeners)
+ {
+ listener.onBeforeRespond(components, this);
+ }
+ }
+
+ listenersFrozen = false;
+ }
+
+ /**
+ * Freezes the {@link #listeners}, and does not un-freeze them as the events will have been
+ * fired by now.
+ *
+ * @param response
+ */
+ private void fireOnAfterRespondListeners(final Response response)
+ {
+ listenersFrozen = true;
+
+ // invoke onafterresponse event on listeners
+ if (listeners != null)
+ {
+ final Map<String, Component> components = Collections.unmodifiableMap(markupIdToComponent);
+
+ // create response that will be used by listeners to append
+ // javascript
+ final IJavaScriptResponse jsresponse = new IJavaScriptResponse()
+ {
+ @Override
+ public void addJavaScript(String script)
+ {
+ respondInvocation(response, script);
+ }
+ };
+
+ for (AjaxRequestTarget.IListener listener : listeners)
+ {
+ listener.onAfterRespond(components, jsresponse);
+ }
+ }
+ }
+
+ /**
+ * Processes components added to the target. This involves attaching components, rendering
+ * markup into a client side xml envelope, and detaching them
+ *
+ * @param response
+ */
+ private void respondComponents(Response response)
+ {
+ componentsFrozen = true;
+ // TODO: We might need to call prepareRender on all components upfront
+
+ // process component markup
+ for (Map.Entry<String, Component> stringComponentEntry : markupIdToComponent.entrySet())
+ {
+ final Component component = stringComponentEntry.getValue();
+ // final String markupId = stringComponentEntry.getKey();
+
+ if (!containsAncestorFor(component))
+ {
+ respondComponent(response, component.getAjaxRegionMarkupId(), component);
+ }
+ }
+
+ if (header != null)
+ {
+ // some header responses buffer all calls to render*** until close is called.
+ // when they are closed, they do something (i.e. aggregate all JS resource urls to a
+ // single url), and then "flush" (by writing to the real response) before closing.
+ // to support this, we need to allow header contributions to be written in the close
+ // tag, which we do here:
+ headerRendering = true;
+ // save old response, set new
+ Response oldResponse = RequestCycle.get().setResponse(encodingHeaderResponse);
+ encodingHeaderResponse.reset();
+
+ // now, close the response (which may render things)
+ header.getHeaderResponse().close();
+
+ // revert to old response
+ RequestCycle.get().setResponse(oldResponse);
+
+ // write the XML tags and we're done
+ writeHeaderContribution(response);
+ headerRendering = false;
+ }
+ }
+
+ private void writeHeaderContribution(Response response)
+ {
+ if (encodingHeaderResponse.getContents().length() != 0)
+ {
+ response.write("<header-contribution");
+
+ if (encodingHeaderResponse.isContentsEncoded())
+ {
+ response.write(" encoding=\"");
+ response.write(getEncodingName());
+ response.write("\" ");
+ }
+
+ // we need to write response as CDATA and parse it on client,
+ // because konqueror crashes when there is a <script> element
+ response.write("><![CDATA[<head xmlns:wicket=\"http://wicket.apache.org\">");
+ response.write(encodingHeaderResponse.getContents());
+ response.write("</head>]]>");
+ response.write("</header-contribution>");
+ }
+ }
+
+ /**
+ * Checks if the target contains an ancestor for the given component
+ *
+ * @param component
+ * @return <code>true</code> if target contains an ancestor for the given component
+ */
+ private boolean containsAncestorFor(Component component)
+ {
+ Component cursor = component.getParent();
+ while (cursor != null)
+ {
+ if (markupIdToComponent.containsValue(cursor))
+ {
+ return true;
+ }
+ cursor = cursor.getParent();
+ }
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "[AjaxRequestHandler@" + hashCode() + " markupIdToComponent [" + markupIdToComponent +
+ "], prependJavaScript [" + prependJavaScripts + "], appendJavaScript [" +
+ appendJavaScripts + "]";
+ }
+
+ /**
+ * Encodes a string so it is safe to use inside CDATA blocks
+ *
+ * @param str
+ * @return encoded string
+ */
+ private static String encode(CharSequence str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ return Strings.replaceAll(str, "]", "]^").toString();
+ }
+
+ /**
+ * @return name of encoding used to possibly encode the contents of the CDATA blocks
+ */
+ protected String getEncodingName()
+ {
+ return "wicket1";
+ }
+
+ /**
+ *
+ * @param str
+ * @return true if string needs to be encoded, false otherwise
+ */
+ private static boolean needsEncoding(CharSequence str)
+ {
+ /*
+ * TODO Post 1.2: Ajax: we can improve this by keeping a buffer of at least 3 characters and
+ * checking that buffer so that we can narrow down escaping occurring only for ']]>'
+ * sequence, or at least for ]] if ] is the last char in this buffer.
+ *
+ * but this improvement will only work if we write first and encode later instead of working
+ * on fragments sent to write
+ */
+ return Strings.indexOf(str, ']') >= 0;
+ }
+
+ /**
+ *
+ * @param response
+ * @param markupId
+ * id of client-side dom element
+ * @param component
+ * component to render
+ */
+ private void respondComponent(final Response response, final String markupId,
+ final Component component)
+ {
+ if (component.getRenderBodyOnly() == true)
+ {
+ throw new IllegalStateException(
+ "Ajax render cannot be called on component that has setRenderBodyOnly enabled. Component: " +
+ component.toString());
+ }
+
+ component.setOutputMarkupId(true);
+
+ // substitute our encoding response for the real one so we can capture
+ // component's markup in a manner safe for transport inside CDATA block
+ encodingBodyResponse.reset();
+ RequestCycle.get().setResponse(encodingBodyResponse);
+
+ // Initialize temporary variables
+ final Page page = component.findParent(Page.class);
+ if (page == null)
+ {
+ // dont throw an exception but just ignore this component, somehow
+ // it got removed from the page.
+ log.debug("component: " + component + " with markupid: " + markupId +
+ " not rendered because it was already removed from page");
+ return;
+ }
+
+ page.startComponentRender(component);
+
+ try
+ {
+ component.prepareForRender();
+
+ // render any associated headers of the component
+ respondHeaderContribution(response, component);
+ }
+ catch (RuntimeException e)
+ {
+ try
+ {
+ component.afterRender();
+ }
+ catch (RuntimeException e2)
+ {
+ // ignore this one could be a result off.
+ }
+ // Restore original response
+ RequestCycle.get().setResponse(response);
+ encodingBodyResponse.reset();
+ throw e;
+ }
+
+ try
+ {
+ component.render();
+ }
+ catch (RuntimeException e)
+ {
+ RequestCycle.get().setResponse(response);
+ encodingBodyResponse.reset();
+ throw e;
+ }
+
+ page.endComponentRender(component);
+
+ // Restore original response
+ RequestCycle.get().setResponse(response);
+
+ response.write("<component id=\"");
+ response.write(markupId);
+ response.write("\" ");
+ if (encodingBodyResponse.isContentsEncoded())
+ {
+ response.write(" encoding=\"");
+ response.write(getEncodingName());
+ response.write("\" ");
+ }
+ response.write("><![CDATA[");
+ response.write(encodingBodyResponse.getContents());
+ response.write("]]></component>");
+
+ encodingBodyResponse.reset();
+ }
+
+ /**
+ * Header response for an ajax request.
+ *
+ * @author Matej Knopp
+ */
+ private class AjaxHeaderResponse extends HeaderResponse
+ {
+ @Override
+ public void render(HeaderItem item)
+ {
+ if (item instanceof OnLoadHeaderItem)
+ {
+ if (!wasItemRendered(item))
+ {
+ appendJavaScripts.add(((OnLoadHeaderItem)item).getJavaScript());
+ markItemRendered(item);
+ }
+ }
+ else if (item instanceof OnDomReadyHeaderItem)
+ {
+ if (!wasItemRendered(item))
+ {
+ domReadyJavaScripts.add(((OnDomReadyHeaderItem)item).getJavaScript());
+ markItemRendered(item);
+ }
+ }
+ else if (headerRendering)
+ super.render(item);
+ else
+ log.debug("Only methods that can be called on IHeaderResponse outside renderHead() are renderOnLoadJavaScript and renderOnDomReadyJavaScript");
+ }
+
+ /**
+ * Construct.
+ */
+ public AjaxHeaderResponse()
+ {
+ }
+
+ /**
+ *
+ * @see org.apache.wicket.markup.head.internal.HeaderResponse#getRealResponse()
+ */
+ @Override
+ protected Response getRealResponse()
+ {
+ return RequestCycle.get().getResponse();
+ }
+ }
+
+ // whether a header contribution is being rendered
+ private boolean headerRendering = false;
+ private HtmlHeaderContainer header = null;
+
+ private IHeaderResponse headerResponse;
+
+ @Override
+ public IHeaderResponse getHeaderResponse()
+ {
+ if (headerResponse == null)
+ {
+ // we don't need to decorate the header response here because this is called from
+ // within AjaxHtmlHeaderContainer, which decorates the response
+ headerResponse = new AjaxHeaderResponse();
+ }
+ return headerResponse;
+ }
+
+ /**
+ * Header container component for ajax header contributions
+ *
+ * @author Matej Knopp
+ */
+ private static class AjaxHtmlHeaderContainer extends HtmlHeaderContainer
+ {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct.
+ *
+ * @param id
+ * @param target
+ */
+ public AjaxHtmlHeaderContainer(String id, AjaxRequestHandler target)
+ {
+ super(id);
+ this.target = target;
+ }
+
+ /**
+ *
+ * @see org.apache.wicket.markup.html.internal.HtmlHeaderContainer#newHeaderResponse()
+ */
+ @Override
+ protected IHeaderResponse newHeaderResponse()
+ {
+ return target.getHeaderResponse();
+ }
+
+ private final transient AjaxRequestHandler target;
+ }
+
+ /**
+ *
+ * @param response
+ * @param component
+ */
+ private void respondHeaderContribution(final Response response, final Component component)
+ {
+ headerRendering = true;
+
+ // create the htmlheadercontainer if needed
+ if (header == null)
+ {
+ header = new AjaxHtmlHeaderContainer(HtmlHeaderSectionHandler.HEADER_ID, this);
+ final Page page = component.getPage();
+ page.addOrReplace(header);
+ }
+
+ // save old response, set new
+ Response oldResponse = RequestCycle.get().setResponse(encodingHeaderResponse);
+
+ encodingHeaderResponse.reset();
+
+ // render the head of component and all it's children
+
+ component.renderHead(header);
+
+ if (component instanceof MarkupContainer)
+ {
+ ((MarkupContainer)component).visitChildren(new IVisitor<Component, Void>()
+ {
+ @Override
+ public void component(final Component component, final IVisit<Void> visit)
+ {
+ if (component.isVisibleInHierarchy())
+ {
+ component.renderHead(header);
+ }
+ else
+ {
+ visit.dontGoDeeper();
+ }
+ }
+ });
+ }
+
+ // revert to old response
+ RequestCycle.get().setResponse(oldResponse);
+
+ writeHeaderContribution(response);
+
+ headerRendering = false;
+ }
+
+ private void respondInvocation(final Response response, final CharSequence js)
+ {
+ respondJavascriptInvocation("evaluate", response, js);
+ }
+
+ private void respondPriorityInvocation(final Response response, final CharSequence js)
+ {
+ respondJavascriptInvocation("priority-evaluate", response, js);
+ }
+
+
+ /**
+ * @param invocation
+ * type of invocation tag, usually {@literal evaluate} or
+ * {@literal priority-evaluate}
+ * @param response
+ * @param js
+ */
+ private void respondJavascriptInvocation(final String invocation, final Response response,
+ final CharSequence js)
+ {
+ boolean encoded = false;
+ CharSequence javascript = js;
+
+ // encode the response if needed
+ if (needsEncoding(js))
+ {
+ encoded = true;
+ javascript = encode(js);
+ }
+
+ response.write("<");
+ response.write(invocation);
+ if (encoded)
+ {
+ response.write(" encoding=\"");
+ response.write(getEncodingName());
+ response.write("\"");
+ }
+ response.write(">");
+
+ response.write("<![CDATA[");
+ response.write(javascript);
+ response.write("]]>");
+
+ response.write("</");
+ response.write(invocation);
+ response.write(">");
+
+ encodingBodyResponse.reset();
+ }
+
+ @Override
+ public String getLastFocusedElementId()
+ {
+ WebRequest request = (WebRequest)RequestCycle.get().getRequest();
+ String id = request.getHeader("Wicket-FocusedElementId");
+ return Strings.isEmpty(id) ? null : id;
+ }
+
+ /**
+ * @see org.apache.wicket.request.handler.IPageRequestHandler#getPageClass()
+ */
+ @Override
+ public Class<? extends IRequestablePage> getPageClass()
+ {
+ return page.getPageClass();
+ }
+
+ /**
+ * @see org.apache.wicket.request.handler.IPageRequestHandler#getPageId()
+ */
+ @Override
+ public Integer getPageId()
+ {
+ return page.getPageId();
+ }
+
+ /**
+ * @see org.apache.wicket.request.handler.IPageRequestHandler#getPageParameters()
+ */
+ @Override
+ public PageParameters getPageParameters()
+ {
+ return page.getPageParameters();
+ }
+
+ @Override
+ public final boolean isPageInstanceCreated()
+ {
+ return true;
+ }
+
+ @Override
+ public final Integer getRenderCount()
+ {
+ return page.getRenderCount();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public PageLogData getLogData()
+ {
+ return logData;
+ }
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java
----------------------------------------------------------------------
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 8904948..0ad5b51 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
@@ -17,1307 +17,199 @@
package org.apache.wicket.ajax;
import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
-import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
-import org.apache.wicket.event.Broadcast;
import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
-import org.apache.wicket.markup.head.internal.HeaderResponse;
-import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
-import org.apache.wicket.markup.parser.filter.HtmlHeaderSectionHandler;
-import org.apache.wicket.markup.repeater.AbstractRepeater;
import org.apache.wicket.request.ILoggableRequestHandler;
-import org.apache.wicket.request.IRequestCycle;
-import org.apache.wicket.request.IRequestHandler;
-import org.apache.wicket.request.Response;
-import org.apache.wicket.request.component.IRequestablePage;
-import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.handler.IPageRequestHandler;
-import org.apache.wicket.request.handler.PageProvider;
-import org.apache.wicket.request.handler.RenderPageRequestHandler;
-import org.apache.wicket.request.handler.logger.PageLogData;
-import org.apache.wicket.request.http.WebRequest;
-import org.apache.wicket.request.http.WebResponse;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-import org.apache.wicket.markup.head.HeaderItem;
-import org.apache.wicket.markup.head.OnLoadHeaderItem;
-import org.apache.wicket.response.StringResponse;
-import org.apache.wicket.response.filter.IResponseFilter;
-import org.apache.wicket.util.lang.Args;
-import org.apache.wicket.util.lang.Generics;
-import org.apache.wicket.util.string.AppendingStringBuffer;
-import org.apache.wicket.util.string.Strings;
-import org.apache.wicket.util.visit.IVisit;
-import org.apache.wicket.util.visit.IVisitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
- * A request target that produces ajax response envelopes used on the client side to update
- * component markup as well as evaluate arbitrary javascript.
- * <p>
- * A component whose markup needs to be updated should be added to this target via
- * AjaxRequestTarget#addComponent(Component) method. Its body will be rendered and added to the
- * envelope when the target is processed, and refreshed on the client side when the ajax response is
- * received.
- * <p>
- * It is important that the component whose markup needs to be updated contains an id attribute in
- * the generated markup that is equal to the value retrieved from Component#getMarkupId(). This can
- * be accomplished by either setting the id attribute in the html template, or using an attribute
- * modifier that will add the attribute with value Component#getMarkupId() to the tag ( such as
- * MarkupIdSetter )
- * <p>
- * Any javascript that needs to be evaluated on the client side can be added using
- * AjaxRequestTarget#append/prependJavaScript(String). For example, this feature can be useful when
- * it is desirable to link component update with some javascript effects.
- * <p>
- * The target provides a listener interface {@link IListener} that can be used to add code that
- * responds to various target events by adding listeners via
- * {@link #addListener(org.apache.wicket.ajax.AjaxRequestTarget.IListener)}
- *
- * @since 1.2
- *
- * @author Igor Vaynberg (ivaynberg)
- * @author Eelco Hillenius
+ *
+ * @since 6.0
*/
-public class AjaxRequestTarget implements IPageRequestHandler, ILoggableRequestHandler
+public interface AjaxRequestTarget extends IPageRequestHandler, ILoggableRequestHandler
{
/**
* An {@link AjaxRequestTarget} listener that can be used to respond to various target-related
* events
- *
+ *
*/
- public static interface IListener
+ interface IListener
{
/**
* Triggered before ajax request target begins its response cycle
- *
+ *
* @param map
* read-only 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
- *
+ *
*/
- public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target);
+ 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 IJavaScriptResponse} object
- *
+ * {@link AjaxRequestTarget.IJavaScriptResponse} object
+ *
* NOTE: During this stage of processing any calls to target that manipulate the response
* (adding components, javascript) will have no effect
- *
+ *
* @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
*/
- public void onAfterRespond(Map<String, Component> map, IJavaScriptResponse response);
+ void onAfterRespond(Map<String, Component> map, AjaxRequestTarget.IJavaScriptResponse response);
}
/**
* An ajax javascript response that allows users to add javascript to be executed on the client
* side
- *
+ *
* @author ivaynberg
*/
- public static interface IJavaScriptResponse
+ interface IJavaScriptResponse
{
/**
* Adds more javascript to the ajax response that will be executed on the client side
- *
+ *
* @param script
* javascript
*/
- public void addJavaScript(String script);
+ void addJavaScript(String script);
}
/**
- * Response that uses an encoder to encode its contents
- *
- * @author Igor Vaynberg (ivaynberg)
+ * Components can implement this interface to get a notification when AjaxRequestTarget begins
+ * to respond. This can be used to postpone adding components to AjaxRequestTarget until the
+ * response begins.
+ *
+ * @author Matej Knopp
*/
- private final class AjaxResponse extends Response
+ interface ITargetRespondListener
{
- private final AppendingStringBuffer buffer = new AppendingStringBuffer(256);
-
- private boolean escaped = false;
-
- private final Response originalResponse;
-
- /**
- * Construct.
- *
- * @param originalResponse
- */
- public AjaxResponse(Response originalResponse)
- {
- this.originalResponse = originalResponse;
- }
-
- /**
- * @see org.apache.wicket.request.Response#encodeURL(CharSequence)
- */
- @Override
- public String encodeURL(CharSequence url)
- {
- return originalResponse.encodeURL(url);
- }
-
- /**
- * @return contents of the response
- */
- public CharSequence getContents()
- {
- return buffer;
- }
-
- /**
- * @return true if any escaping has been performed, false otherwise
- */
- public boolean isContentsEncoded()
- {
- return escaped;
- }
-
- /**
- * @see org.apache.wicket.request.Response#write(CharSequence)
- */
- @Override
- public void write(CharSequence cs)
- {
- String string = cs.toString();
- if (needsEncoding(string))
- {
- string = encode(string);
- escaped = true;
- buffer.append(string);
- }
- else
- {
- buffer.append(cs);
- }
- }
-
/**
- * Resets the response to a clean state so it can be reused to save on garbage.
+ * Invoked when AjaxRequestTarget is about the respond.
+ *
+ * @param target
*/
- @Override
- public void reset()
- {
- buffer.clear();
- escaped = false;
- }
-
- @Override
- public void write(byte[] array)
- {
- throw new UnsupportedOperationException("Cannot write binary data.");
- }
-
- @Override
- public void write(byte[] array, int offset, int length)
- {
- throw new UnsupportedOperationException("Cannot write binary data.");
- }
-
- @Override
- public Object getContainerResponse()
- {
- return originalResponse.getContainerResponse();
- }
+ void onTargetRespond(AjaxRequestTarget target);
}
- private static final Logger log = LoggerFactory.getLogger(AjaxRequestTarget.class);
-
- private final List<CharSequence> appendJavaScripts = Generics.newArrayList();
-
- private final List<CharSequence> domReadyJavaScripts = Generics.newArrayList();
-
- /**
- * Create a response for component body and javascript that will escape output to make it safe
- * to use inside a CDATA block
- */
- private final AjaxResponse encodingBodyResponse;
-
- /**
- * Response for header contribution that will escape output to make it safe to use inside a
- * CDATA block
- */
- private final AjaxResponse encodingHeaderResponse;
-
- /** the component instances that will be rendered */
- private final Map<String, Component> markupIdToComponent = new LinkedHashMap<String, Component>();
-
- /** */
- private final List<CharSequence> prependJavaScripts = Generics.newArrayList();
-
- /** a list of listeners */
- private List<IListener> listeners = null;
-
- /** */
- private final Set<ITargetRespondListener> respondListeners = new HashSet<ITargetRespondListener>();
-
- /** The associated Page */
- private final Page page;
-
- /** see https://issues.apache.org/jira/browse/WICKET-3564 */
- private transient boolean componentsFrozen;
- private transient boolean listenersFrozen;
- private transient boolean respondersFrozen;
-
- private PageLogData logData;
-
- /**
- * Constructor
- *
- * @param page
- */
- public AjaxRequestTarget(Page page)
- {
- Args.notNull(page, "page");
- this.page = page;
- Response response = RequestCycle.get().getResponse();
- encodingBodyResponse = new AjaxResponse(response);
- encodingHeaderResponse = new AjaxResponse(response);
- }
/**
- * @see org.apache.wicket.request.handler.IPageRequestHandler#getPage()
+ * Adds a component to the list of components to be rendered
+ *
+ * @param markupId
+ * id of client-side dom element that will be updated
+ * @param component
+ * component to be rendered
+ * @throws IllegalArgumentException
+ * if the component is a {@link org.apache.wicket.Page} or an {@link org.apache.wicket.markup.repeater.AbstractRepeater}
+ * @throws IllegalStateException
+ * if the components are currently being rendered, or have already been rendered
*/
- @Override
- public Page getPage()
- {
- return page;
- }
-
- private void assertNotFrozen(boolean frozen, Class<?> clazz)
- {
- if (frozen)
- {
- throw new IllegalStateException(clazz.getSimpleName() + "s can no " +
- " longer be added");
- }
- }
-
- private void assertListenersNotFrozen()
- {
- assertNotFrozen(listenersFrozen, IListener.class);
- }
-
- private void assertComponentsNotFrozen()
- {
- assertNotFrozen(componentsFrozen, Component.class);
- }
-
- private void assertRespondersNotFrozen()
- {
- assertNotFrozen(respondersFrozen, ITargetRespondListener.class);
- }
+ void add(final Component component, final String markupId);
/**
- * Adds a listener to this target
- *
- * @param listener
- * @throws IllegalStateException
- * if {@link IListener}'s events are currently being fired or have both been fired
- * already
+ * Adds components to the list of components to be rendered.
+ *
+ * @param components
+ * components to be rendered
*/
- public void addListener(IListener listener) throws IllegalStateException
- {
- Args.notNull(listener, "listener");
- assertListenersNotFrozen();
-
- if (listeners == null)
- {
- listeners = new LinkedList<IListener>();
- }
+ void add(Component... components);
- if (!listeners.contains(listener))
- {
- listeners.add(listener);
- }
- }
/**
* Visits all children of the specified parent container and adds them to the target if they are
* of same type as <code>childCriteria</code>
- *
+ *
* @param parent
* Must not be null.
* @param childCriteria
* Must not be null. If you want to traverse all components use ` Component.class as
* the value for this argument.
*/
- public final void addChildren(MarkupContainer parent, Class<?> childCriteria)
- {
- Args.notNull(parent, "parent");
- Args.notNull(childCriteria, "childCriteria");
+ void addChildren(MarkupContainer parent, Class<?> childCriteria);
- parent.visitChildren(childCriteria, new IVisitor<Component, Void>()
- {
- @Override
- public void component(final Component component, final IVisit<Void> visit)
- {
- add(component);
- visit.dontGoDeeper();
- }
- });
- }
/**
- * Adds components to the list of components to be rendered
- *
- * @param components
- * components to be rendered
- * @deprecated use {@link #add(Component...)} instead
- */
- // should stay deprecated in 1.5
- @Deprecated
- public void addComponent(Component... components)
- {
- add(components);
- }
-
- /**
- * Adds components to the list of components to be rendered.
- *
- * @param components
- * components to be rendered
- */
- public void add(Component... components)
- {
- for (final Component component : components)
- {
- Args.notNull(component, "component");
-
- if (component.getOutputMarkupId() == false)
- {
- throw new IllegalArgumentException(
- "cannot update component that does not have setOutputMarkupId property set to true. Component: " +
- component.toString());
- }
- add(component, component.getMarkupId());
- }
- }
-
- /**
- * Adds a component to the list of components to be rendered
- *
- * @param markupId
- * id of client-side dom element that will be updated
- *
- * @param component
- * component to be rendered
- * @deprecated use {@link #add(Component...)} instead
- */
- // should stay deprecated in 1.5
- @Deprecated
- public final void addComponent(Component component, String markupId)
- {
- add(component, markupId);
- }
-
- /**
- * Adds a component to the list of components to be rendered
- *
- * @param markupId
- * id of client-side dom element that will be updated
- * @param component
- * component to be rendered
- * @throws IllegalArgumentException
- * if the component is a {@link Page} or an {@link AbstractRepeater}
+ * Adds a listener to this target
+ *
+ * @param listener
* @throws IllegalStateException
- * if the components are currently being rendered, or have already been rendered
- */
- public final void add(final Component component, final String markupId)
- throws IllegalArgumentException, IllegalStateException
- {
- Args.notEmpty(markupId, "markupId");
- Args.notNull(component, "component");
-
- if (component instanceof Page)
- {
- if (component != page)
- {
- throw new IllegalArgumentException("component cannot be a page");
- }
- }
- else if (component instanceof AbstractRepeater)
- {
- throw new IllegalArgumentException(
- "Component " +
- component.getClass().getName() +
- " has been added to the target. This component is a repeater and cannot be repainted via ajax directly. " +
- "Instead add its parent or another markup container higher in the hierarchy.");
- }
-
- assertComponentsNotFrozen();
-
- component.setMarkupId(markupId);
- markupIdToComponent.put(markupId, component);
- }
-
- /**
- * Returns an unmodifiable collection of all components added to this target
- *
- * @return unmodifiable collection of all components added to this target
- */
- public final Collection<? extends Component> getComponents()
- {
- return Collections.unmodifiableCollection(markupIdToComponent.values());
- }
-
- /**
- * Sets the focus in the browser to the given component. The markup id must be set. If the
- * component is null the focus will not be set to any component.
- *
- * @param component
- * The component to get the focus or null.
+ * if {@link AjaxRequestTarget.IListener}'s events are currently being fired or have both been fired
+ * already
*/
- public final void focusComponent(Component component)
- {
- if (component != null && component.getOutputMarkupId() == false)
- {
- throw new IllegalArgumentException(
- "cannot update component that does not have setOutputMarkupId property set to true. Component: " +
- component.toString());
- }
- final String id = component != null ? ("'" + component.getMarkupId() + "'") : "null";
- appendJavaScript("Wicket.Focus.setFocusOnId(" + id + ");");
- }
+ void addListener(AjaxRequestTarget.IListener listener);
/**
* Adds javascript that will be evaluated on the client side after components are replaced
- *
+ *
* @param javascript
*/
- public final void appendJavaScript(CharSequence javascript)
- {
- Args.notNull(javascript, "javascript");
-
- appendJavaScripts.add(javascript);
- }
-
- /**
- * @see org.apache.wicket.request.handler.IPageRequestHandler#detach(org.apache.wicket.request.IRequestCycle)
- */
- @Override
- public void detach(final IRequestCycle requestCycle)
- {
- if (logData == null)
- logData = new PageLogData(page);
-
- // detach the page if it was updated
- if (markupIdToComponent.size() > 0)
- {
- final Component component = markupIdToComponent.values().iterator().next();
- final Page page = component.findParent(Page.class);
- if (page != null)
- {
- page.detach();
- }
- }
- }
-
- /**
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(final Object obj)
- {
- if (obj instanceof AjaxRequestTarget)
- {
- AjaxRequestTarget that = (AjaxRequestTarget)obj;
- return markupIdToComponent.equals(that.markupIdToComponent) &&
- prependJavaScripts.equals(that.prependJavaScripts) &&
- appendJavaScripts.equals(that.appendJavaScripts);
- }
- return false;
- }
-
- /**
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode()
- {
- int result = "AjaxRequestTarget".hashCode();
- result += markupIdToComponent.hashCode() * 17;
- result += prependJavaScripts.hashCode() * 17;
- result += appendJavaScripts.hashCode() * 17;
- return result;
- }
+ void appendJavaScript(CharSequence javascript);
/**
* Adds javascript that will be evaluated on the client side before components are replaced
- *
+ *
* @param javascript
*/
- public final void prependJavaScript(CharSequence javascript)
- {
- Args.notNull(javascript, "javascript");
-
- prependJavaScripts.add(javascript);
- }
-
- /**
- * Components can implement this interface to get a notification when AjaxRequestTarget begins
- * to respond. This can be used to postpone adding components to AjaxRequestTarget until the
- * response begins.
- *
- * @author Matej Knopp
- */
- public static interface ITargetRespondListener
- {
- /**
- * Invoked when AjaxRequestTarget is about the respond.
- *
- * @param target
- */
- public void onTargetRespond(AjaxRequestTarget target);
- }
+ void prependJavaScript(CharSequence javascript);
/**
* Register the given respond listener. The listener's
- * {@link ITargetRespondListener#onTargetRespond(AjaxRequestTarget)} method will be invoked when
+ * {@link org.apache.wicket.ajax.AjaxRequestTarget.ITargetRespondListener#onTargetRespond} method will be invoked when
* the {@link AjaxRequestTarget} starts to respond.
- *
+ *
* @param listener
*/
- public void registerRespondListener(ITargetRespondListener listener)
- {
- assertRespondersNotFrozen();
- respondListeners.add(listener);
- }
-
- /**
- * @see org.apache.wicket.request.handler.IPageRequestHandler#respond(org.apache.wicket.request.IRequestCycle)
- */
- @Override
- public final void respond(final IRequestCycle requestCycle)
- {
- final RequestCycle rc = (RequestCycle)requestCycle;
- final WebResponse response = (WebResponse)requestCycle.getResponse();
-
- if (markupIdToComponent.values().contains(page))
- {
- // the page itself has been added to the request target, we simply issue a redirect
- // back to the page
- IRequestHandler handler = new RenderPageRequestHandler(new PageProvider(page));
- final String url = rc.urlFor(handler).toString();
- response.sendRedirect(url);
- return;
- }
-
- respondersFrozen = true;
-
- for (ITargetRespondListener listener : respondListeners)
- {
- listener.onTargetRespond(this);
- }
-
- final Application app = Application.get();
-
- page.send(app, Broadcast.BREADTH, this);
-
- // Determine encoding
- final String encoding = app.getRequestCycleSettings().getResponseRequestEncoding();
-
- // Set content type based on markup type for page
- response.setContentType("text/xml; charset=" + encoding);
-
- // Make sure it is not cached by a client
- response.disableCaching();
-
- try
- {
- final StringResponse bodyResponse = new StringResponse();
- constructResponseBody(bodyResponse, encoding);
- CharSequence filteredResponse = invokeResponseFilters(bodyResponse);
- response.write(filteredResponse);
- }
- finally
- {
- // restore the original response
- RequestCycle.get().setResponse(response);
- }
- }
-
- /**
- * Collects the response body (without the headers) so that it can be pre-processed before
- * written down to the original response.
- *
- * @param bodyResponse
- * the buffering response
- * @param encoding
- * the encoding that should be used to encode the body
- */
- private void constructResponseBody(final Response bodyResponse, final String encoding)
- {
- bodyResponse.write("<?xml version=\"1.0\" encoding=\"");
- bodyResponse.write(encoding);
- bodyResponse.write("\"?>");
- bodyResponse.write("<ajax-response>");
-
- // invoke onbeforerespond event on listeners
- fireOnBeforeRespondListeners();
-
- // process added components
- respondComponents(bodyResponse);
-
- fireOnAfterRespondListeners(bodyResponse);
-
- // queue up prepend javascripts. unlike other steps these are executed out of order so that
- // components can contribute them from inside their onbeforerender methods.
- Iterator<CharSequence> it = prependJavaScripts.iterator();
- while (it.hasNext())
- {
- CharSequence js = it.next();
- respondPriorityInvocation(bodyResponse, js);
- }
-
-
- // execute the dom ready javascripts as first javascripts
- // after component replacement
- it = domReadyJavaScripts.iterator();
- while (it.hasNext())
- {
- CharSequence js = it.next();
- respondInvocation(bodyResponse, js);
- }
- it = appendJavaScripts.iterator();
- while (it.hasNext())
- {
- CharSequence js = it.next();
- respondInvocation(bodyResponse, js);
- }
-
- bodyResponse.write("</ajax-response>");
- }
-
- /**
- * Runs the configured {@link IResponseFilter}s over the constructed Ajax response
- *
- * @param contentResponse
- * the Ajax {@link Response} body
- * @return filtered response
- */
- private AppendingStringBuffer invokeResponseFilters(final StringResponse contentResponse)
- {
- AppendingStringBuffer responseBuffer = new AppendingStringBuffer(
- contentResponse.getBuffer());
-
- List<IResponseFilter> responseFilters = Application.get()
- .getRequestCycleSettings()
- .getResponseFilters();
-
- if (responseFilters != null)
- {
- for (IResponseFilter filter : responseFilters)
- {
- responseBuffer = filter.filter(responseBuffer);
- }
- }
- return responseBuffer;
- }
-
- /**
- * Freezes the {@link #listeners} before firing the event and un-freezes them afterwards to
- * allow components to add more {@link IListener}s for the second event.
- */
- private void fireOnBeforeRespondListeners()
- {
- listenersFrozen = true;
-
- if (listeners != null)
- {
- final Map<String, Component> components = Collections.unmodifiableMap(markupIdToComponent);
-
- for (IListener listener : listeners)
- {
- listener.onBeforeRespond(components, this);
- }
- }
-
- listenersFrozen = false;
- }
-
- /**
- * Freezes the {@link #listeners}, and does not un-freeze them as the events will have been
- * fired by now.
- *
- * @param response
- */
- private void fireOnAfterRespondListeners(final Response response)
- {
- listenersFrozen = true;
-
- // invoke onafterresponse event on listeners
- if (listeners != null)
- {
- final Map<String, Component> components = Collections.unmodifiableMap(markupIdToComponent);
-
- // create response that will be used by listeners to append
- // javascript
- final IJavaScriptResponse jsresponse = new IJavaScriptResponse()
- {
- @Override
- public void addJavaScript(String script)
- {
- respondInvocation(response, script);
- }
- };
-
- for (IListener listener : listeners)
- {
- listener.onAfterRespond(components, jsresponse);
- }
- }
- }
-
- /**
- * Processes components added to the target. This involves attaching components, rendering
- * markup into a client side xml envelope, and detaching them
- *
- * @param response
- */
- private void respondComponents(Response response)
- {
- componentsFrozen = true;
- // TODO: We might need to call prepareRender on all components upfront
-
- // process component markup
- for (Map.Entry<String, Component> stringComponentEntry : markupIdToComponent.entrySet())
- {
- final Component component = stringComponentEntry.getValue();
- // final String markupId = stringComponentEntry.getKey();
-
- if (!containsAncestorFor(component))
- {
- respondComponent(response, component.getAjaxRegionMarkupId(), component);
- }
- }
-
- if (header != null)
- {
- // some header responses buffer all calls to render*** until close is called.
- // when they are closed, they do something (i.e. aggregate all JS resource urls to a
- // single url), and then "flush" (by writing to the real response) before closing.
- // to support this, we need to allow header contributions to be written in the close
- // tag, which we do here:
- headerRendering = true;
- // save old response, set new
- Response oldResponse = RequestCycle.get().setResponse(encodingHeaderResponse);
- encodingHeaderResponse.reset();
-
- // now, close the response (which may render things)
- header.getHeaderResponse().close();
-
- // revert to old response
- RequestCycle.get().setResponse(oldResponse);
-
- // write the XML tags and we're done
- writeHeaderContribution(response);
- headerRendering = false;
- }
- }
-
- private void writeHeaderContribution(Response response)
- {
- if (encodingHeaderResponse.getContents().length() != 0)
- {
- response.write("<header-contribution");
-
- if (encodingHeaderResponse.isContentsEncoded())
- {
- response.write(" encoding=\"");
- response.write(getEncodingName());
- response.write("\" ");
- }
-
- // we need to write response as CDATA and parse it on client,
- // because konqueror crashes when there is a <script> element
- response.write("><![CDATA[<head xmlns:wicket=\"http://wicket.apache.org\">");
- response.write(encodingHeaderResponse.getContents());
- response.write("</head>]]>");
- response.write("</header-contribution>");
- }
- }
-
- /**
- * Checks if the target contains an ancestor for the given component
- *
- * @param component
- * @return <code>true</code> if target contains an ancestor for the given component
- */
- private boolean containsAncestorFor(Component component)
- {
- Component cursor = component.getParent();
- while (cursor != null)
- {
- if (markupIdToComponent.containsValue(cursor))
- {
- return true;
- }
- cursor = cursor.getParent();
- }
- return false;
- }
-
- /**
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString()
- {
- return "[AjaxRequestTarget@" + hashCode() + " markupIdToComponent [" + markupIdToComponent +
- "], prependJavaScript [" + prependJavaScripts + "], appendJavaScript [" +
- appendJavaScripts + "]";
- }
-
- /**
- * Encodes a string so it is safe to use inside CDATA blocks
- *
- * @param str
- * @return encoded string
- */
- protected String encode(CharSequence str)
- {
- if (str == null)
- {
- return null;
- }
-
- return Strings.replaceAll(str, "]", "]^").toString();
- }
+ void registerRespondListener(ITargetRespondListener listener);
/**
- * @return name of encoding used to possibly encode the contents of the CDATA blocks
- */
- protected String getEncodingName()
- {
- return "wicket1";
- }
-
- /**
- *
- * @param str
- * @return true if string needs to be encoded, false otherwise
+ * Returns an unmodifiable collection of all components added to this target
+ *
+ * @return unmodifiable collection of all components added to this target
*/
- protected boolean needsEncoding(CharSequence str)
- {
- /*
- * TODO Post 1.2: Ajax: we can improve this by keeping a buffer of at least 3 characters and
- * checking that buffer so that we can narrow down escaping occurring only for ']]>'
- * sequence, or at least for ]] if ] is the last char in this buffer.
- *
- * but this improvement will only work if we write first and encode later instead of working
- * on fragments sent to write
- */
- return Strings.indexOf(str, ']') >= 0;
- }
+ Collection<? extends Component> getComponents();
/**
- *
- * @param response
- * @param markupId
- * id of client-side dom element
+ * Sets the focus in the browser to the given component. The markup id must be set. If the
+ * component is null the focus will not be set to any component.
+ *
* @param component
- * component to render
- */
- private void respondComponent(final Response response, final String markupId,
- final Component component)
- {
- if (component.getRenderBodyOnly() == true)
- {
- throw new IllegalStateException(
- "Ajax render cannot be called on component that has setRenderBodyOnly enabled. Component: " +
- component.toString());
- }
-
- component.setOutputMarkupId(true);
-
- // substitute our encoding response for the real one so we can capture
- // component's markup in a manner safe for transport inside CDATA block
- encodingBodyResponse.reset();
- RequestCycle.get().setResponse(encodingBodyResponse);
-
- // Initialize temporary variables
- final Page page = component.findParent(Page.class);
- if (page == null)
- {
- // dont throw an exception but just ignore this component, somehow
- // it got removed from the page.
- log.debug("component: " + component + " with markupid: " + markupId +
- " not rendered because it was already removed from page");
- return;
- }
-
- page.startComponentRender(component);
-
- try
- {
- component.prepareForRender();
-
- // render any associated headers of the component
- respondHeaderContribution(response, component);
- }
- catch (RuntimeException e)
- {
- try
- {
- component.afterRender();
- }
- catch (RuntimeException e2)
- {
- // ignore this one could be a result off.
- }
- // Restore original response
- RequestCycle.get().setResponse(response);
- encodingBodyResponse.reset();
- throw e;
- }
-
- try
- {
- component.render();
- }
- catch (RuntimeException e)
- {
- RequestCycle.get().setResponse(response);
- encodingBodyResponse.reset();
- throw e;
- }
-
- page.endComponentRender(component);
-
- // Restore original response
- RequestCycle.get().setResponse(response);
-
- response.write("<component id=\"");
- response.write(markupId);
- response.write("\" ");
- if (encodingBodyResponse.isContentsEncoded())
- {
- response.write(" encoding=\"");
- response.write(getEncodingName());
- response.write("\" ");
- }
- response.write("><![CDATA[");
- response.write(encodingBodyResponse.getContents());
- response.write("]]></component>");
-
- encodingBodyResponse.reset();
- }
-
- /**
- * Header response for an ajax request.
- *
- * @author Matej Knopp
+ * The component to get the focus or null.
*/
- private class AjaxHeaderResponse extends HeaderResponse
- {
- @Override
- public void render(HeaderItem item)
- {
- if (item instanceof OnLoadHeaderItem)
- {
- if (!wasItemRendered(item))
- {
- appendJavaScripts.add(((OnLoadHeaderItem)item).getJavaScript());
- markItemRendered(item);
- }
- }
- else if (item instanceof OnDomReadyHeaderItem)
- {
- if (!wasItemRendered(item))
- {
- domReadyJavaScripts.add(((OnDomReadyHeaderItem)item).getJavaScript());
- markItemRendered(item);
- }
- }
- else if (headerRendering)
- super.render(item);
- else
- log.debug("Only methods that can be called on IHeaderResponse outside renderHead() are renderOnLoadJavaScript and renderOnDomReadyJavaScript");
- }
-
- /**
- * Construct.
- */
- public AjaxHeaderResponse()
- {
- }
-
- /**
- *
- * @see org.apache.wicket.markup.head.internal.HeaderResponse#getRealResponse()
- */
- @Override
- protected Response getRealResponse()
- {
- return RequestCycle.get().getResponse();
- }
- }
-
- // whether a header contribution is being rendered
- private boolean headerRendering = false;
- private HtmlHeaderContainer header = null;
-
- private IHeaderResponse headerResponse;
+ void focusComponent(Component component);
/**
* Returns the header response associated with current AjaxRequestTarget.
- *
+ *
* Beware that only renderOnDomReadyJavaScript and renderOnLoadJavaScript can be called outside
* the renderHeader(IHeaderResponse response) method. Calls to other render** methods will
* result in the call failing with a debug-level log statement to help you see why it failed.
- *
+ *
* @return header response
*/
- public IHeaderResponse getHeaderResponse()
- {
- if (headerResponse == null)
- {
- // we don't need to decorate the header response here because this is called from
- // within AjaxHtmlHeaderContainer, which decorates the response
- headerResponse = new AjaxHeaderResponse();
- }
- return headerResponse;
- }
-
- /**
- * Header container component for ajax header contributions
- *
- * @author Matej Knopp
- */
- private static class AjaxHtmlHeaderContainer extends HtmlHeaderContainer
- {
- private static final long serialVersionUID = 1L;
-
- /**
- * Construct.
- *
- * @param id
- * @param target
- */
- public AjaxHtmlHeaderContainer(String id, AjaxRequestTarget target)
- {
- super(id);
- this.target = target;
- }
-
- /**
- *
- * @see org.apache.wicket.markup.html.internal.HtmlHeaderContainer#newHeaderResponse()
- */
- @Override
- protected IHeaderResponse newHeaderResponse()
- {
- return target.getHeaderResponse();
- }
-
- private final transient AjaxRequestTarget target;
- }
-
- /**
- *
- * @param response
- * @param component
- */
- private void respondHeaderContribution(final Response response, final Component component)
- {
- headerRendering = true;
-
- // create the htmlheadercontainer if needed
- if (header == null)
- {
- header = new AjaxHtmlHeaderContainer(HtmlHeaderSectionHandler.HEADER_ID, this);
- final Page page = component.getPage();
- page.addOrReplace(header);
- }
-
- // save old response, set new
- Response oldResponse = RequestCycle.get().setResponse(encodingHeaderResponse);
-
- encodingHeaderResponse.reset();
-
- // render the head of component and all it's children
-
- component.renderHead(header);
-
- if (component instanceof MarkupContainer)
- {
- ((MarkupContainer)component).visitChildren(new IVisitor<Component, Void>()
- {
- @Override
- public void component(final Component component, final IVisit<Void> visit)
- {
- if (component.isVisibleInHierarchy())
- {
- component.renderHead(header);
- }
- else
- {
- visit.dontGoDeeper();
- }
- }
- });
- }
-
- // revert to old response
- RequestCycle.get().setResponse(oldResponse);
-
- writeHeaderContribution(response);
-
- headerRendering = false;
- }
-
- private void respondInvocation(final Response response, final CharSequence js)
- {
- respondJavascriptInvocation("evaluate", response, js);
- }
-
- private void respondPriorityInvocation(final Response response, final CharSequence js)
- {
- respondJavascriptInvocation("priority-evaluate", response, js);
- }
-
-
- /**
- * @param invocation
- * type of invocation tag, usually {@literal evaluate} or
- * {@literal priority-evaluate}
- * @param response
- * @param js
- */
- private void respondJavascriptInvocation(final String invocation, final Response response,
- final CharSequence js)
- {
- boolean encoded = false;
- CharSequence javascript = js;
-
- // encode the response if needed
- if (needsEncoding(js))
- {
- encoded = true;
- javascript = encode(js);
- }
-
- response.write("<");
- response.write(invocation);
- if (encoded)
- {
- response.write(" encoding=\"");
- response.write(getEncodingName());
- response.write("\"");
- }
- response.write(">");
-
- response.write("<![CDATA[");
- response.write(javascript);
- response.write("]]>");
-
- response.write("</");
- response.write(invocation);
- response.write(">");
-
- encodingBodyResponse.reset();
- }
-
- /**
- * Static method that returns current {@link AjaxRequestTarget} or <code>null</code> of no
- * {@link AjaxRequestTarget} is available.
- *
- * @return {@link AjaxRequestTarget} instance if current request is an Ajax request,
- * <code>null</code> otherwise.
- */
- public static AjaxRequestTarget get()
- {
- final RequestCycle requestCycle = RequestCycle.get();
- if (requestCycle != null)
- {
- if (requestCycle.getActiveRequestHandler() instanceof AjaxRequestTarget)
- {
- return (AjaxRequestTarget)requestCycle.getActiveRequestHandler();
- }
- else if (requestCycle.getRequestHandlerScheduledAfterCurrent() instanceof AjaxRequestTarget)
- {
- return (AjaxRequestTarget)requestCycle.getRequestHandlerScheduledAfterCurrent();
- }
- }
- return null;
- }
+ IHeaderResponse getHeaderResponse();
/**
* Returns the HTML id of the last focused element.
- *
+ *
* @return markup id of last focused element, <code>null</code> if none
*/
- public String getLastFocusedElementId()
- {
- WebRequest request = (WebRequest)RequestCycle.get().getRequest();
- String id = request.getHeader("Wicket-FocusedElementId");
- return Strings.isEmpty(id) ? null : id;
- }
-
- /**
- * @see org.apache.wicket.request.handler.IPageRequestHandler#getPageClass()
- */
- @Override
- public Class<? extends IRequestablePage> getPageClass()
- {
- return page.getPageClass();
- }
+ String getLastFocusedElementId();
- /**
- * @see org.apache.wicket.request.handler.IPageRequestHandler#getPageId()
- */
- @Override
- public Integer getPageId()
- {
- return page.getPageId();
- }
/**
- * @see org.apache.wicket.request.handler.IPageRequestHandler#getPageParameters()
+ * Returns the page. Be aware that the page can be instantiated if this wasn't the case already.
+ *
+ * @return page instance
*/
- @Override
- public PageParameters getPageParameters()
- {
- return page.getPageParameters();
- }
-
- @Override
- public final boolean isPageInstanceCreated()
- {
- return true;
- }
-
- @Override
- public final Integer getRenderCount()
- {
- return page.getRenderCount();
- }
-
- /** {@inheritDoc} */
- @Override
- public PageLogData getLogData()
- {
- return logData;
- }
+ Page getPage();
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTargetListenerCollection.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTargetListenerCollection.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTargetListenerCollection.java
index c7f1cc5..a3153b8 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTargetListenerCollection.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestTargetListenerCollection.java
@@ -20,7 +20,7 @@ import org.apache.wicket.util.listener.ListenerCollection;
/**
* A collection of {@link AjaxRequestTarget.IListener}s
- *
+ *
* @since 1.5
*/
public class AjaxRequestTargetListenerCollection extends
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxSelfUpdatingTimerBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxSelfUpdatingTimerBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxSelfUpdatingTimerBehavior.java
index 9d00331..0a7552e 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxSelfUpdatingTimerBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxSelfUpdatingTimerBehavior.java
@@ -42,7 +42,7 @@ public class AjaxSelfUpdatingTimerBehavior extends AbstractAjaxTimerBehavior
}
/**
- * @see org.apache.wicket.ajax.AbstractAjaxTimerBehavior#onTimer(org.apache.wicket.ajax.AjaxRequestTarget)
+ * @see org.apache.wicket.ajax.AbstractAjaxTimerBehavior#onTimer(AjaxRequestTarget)
*/
@Override
protected final void onTimer(final AjaxRequestTarget target)
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormChoiceComponentUpdatingBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormChoiceComponentUpdatingBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormChoiceComponentUpdatingBehavior.java
index f6e4070..1cb9d2a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormChoiceComponentUpdatingBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormChoiceComponentUpdatingBehavior.java
@@ -21,13 +21,13 @@ import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
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.markup.html.form.CheckBoxMultipleChoice;
import org.apache.wicket.markup.html.form.CheckGroup;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.RadioChoice;
import org.apache.wicket.markup.html.form.RadioGroup;
-import org.apache.wicket.markup.head.JavaScriptHeaderItem;
-import org.apache.wicket.markup.head.OnLoadHeaderItem;
import org.apache.wicket.util.string.AppendingStringBuffer;
/**
@@ -88,7 +88,7 @@ public abstract class AjaxFormChoiceComponentUpdatingBehavior extends AbstractDe
/**
* Called to handle any error resulting from updating form component. Errors thrown from
- * {@link #onUpdate(AjaxRequestTarget)} will not be caught here.
+ * {@link #onUpdate(org.apache.wicket.ajax.AjaxRequestTarget)} will not be caught here.
*
* The RuntimeException will be null if it was just a validation or conversion error of the
* FormComponent
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
index 1c91e10..93795a0 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
@@ -19,12 +19,11 @@ package org.apache.wicket.ajax.form;
import org.apache.wicket.Application;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes.Method;
-import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.validation.IFormValidator;
-import org.apache.wicket.util.string.AppendingStringBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -191,7 +190,7 @@ public abstract class AjaxFormComponentUpdatingBehavior extends AjaxEventBehavio
/**
* Called to handle any error resulting from updating form component. Errors thrown from
- * {@link #onUpdate(AjaxRequestTarget)} will not be caught here.
+ * {@link #onUpdate(org.apache.wicket.ajax.AjaxRequestTarget)} will not be caught here.
*
* The RuntimeException will be null if it was just a validation or conversion error of the
* FormComponent
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java
index 8057c24..fe78ecb 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java
@@ -80,10 +80,6 @@ public abstract class AjaxFallbackLink<T> extends Link<T> implements IAjaxLink
{
private static final long serialVersionUID = 1L;
- /**
- *
- * @see org.apache.wicket.ajax.AjaxEventBehavior#onEvent(org.apache.wicket.ajax.AjaxRequestTarget)
- */
@Override
protected void onEvent(AjaxRequestTarget target)
{
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java
index 0ade076..3df547d 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java
@@ -91,20 +91,12 @@ public abstract class AjaxButton extends Button
{
private static final long serialVersionUID = 1L;
- /**
- *
- * @see org.apache.wicket.ajax.form.AjaxFormSubmitBehavior#onSubmit(org.apache.wicket.ajax.AjaxRequestTarget)
- */
@Override
protected void onSubmit(AjaxRequestTarget target)
{
AjaxButton.this.onSubmit(target, AjaxButton.this.getForm());
}
- /**
- *
- * @see org.apache.wicket.ajax.form.AjaxFormSubmitBehavior#onError(org.apache.wicket.ajax.AjaxRequestTarget)
- */
@Override
protected void onError(AjaxRequestTarget target)
{
http://git-wip-us.apache.org/repos/asf/wicket/blob/c2b44cca/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxCheckBox.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxCheckBox.java b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxCheckBox.java
index f621347..bf9a6ca 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxCheckBox.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxCheckBox.java
@@ -16,8 +16,8 @@
*/
package org.apache.wicket.ajax.markup.html.form;
-import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.model.IModel;