You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/02/22 14:20:35 UTC

[isis] branch master updated: ISIS-2538: remove AjaxDeferredBehaviour

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

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 96d94cd  ISIS-2538: remove AjaxDeferredBehaviour
96d94cd is described below

commit 96d94cdd920fe2d5f78a272a1093bb6ea57305a8
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Feb 22 15:20:19 2021 +0100

    ISIS-2538: remove AjaxDeferredBehaviour
    
    instead dealing with LocalResourcePath action results more generally
---
 .../ui/actionresponse/ActionResultResponse.java    |  40 ++++--
 .../ActionResultResponseHandlingStrategy.java      |  76 +++++++----
 .../actionresponse/ActionResultResponseType.java   |  34 ++++-
 .../widgets/linkandlabel/ActionLink.java           |  43 +-----
 .../linkandlabel/AjaxDeferredBehaviour.java        | 147 ---------------------
 5 files changed, 118 insertions(+), 222 deletions(-)

diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java
index bc70be7..e3c44b1 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java
@@ -18,16 +18,18 @@
  */
 package org.apache.isis.viewer.wicket.ui.actionresponse;
 
-import java.net.URL;
-
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.request.IRequestHandler;
 
+import org.apache.isis.applib.value.OpenUrlStrategy;
 import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 
+import lombok.NonNull;
+
 /**
  * The response to provide as a result of interpreting the response;
- * either to show a {@link #toPage(PageAbstract) page}, or to {@link #withHandler(IRequestHandler) redirect} to a
+ * either to show a {@link #toPage(PageAbstract) page}, or to 
+ * {@link #withHandler(IRequestHandler) redirect} to a
  * handler (eg a download).
  */
 public class ActionResultResponse {
@@ -36,27 +38,36 @@ public class ActionResultResponse {
     private final IRequestHandler handler;
     private final PageAbstract page;
     private final AjaxRequestTarget target;
-    private final URL url;
+    private final String url;
 
     public static ActionResultResponse withHandler(IRequestHandler handler) {
         return new ActionResultResponse(
                 ActionResultResponseHandlingStrategy.SCHEDULE_HANDLER, handler, null, null, null);
     }
+    
     public static ActionResultResponse toPage(PageAbstract page) {
         return new ActionResultResponse(
                 ActionResultResponseHandlingStrategy.REDIRECT_TO_PAGE, null, page, null, null);
     }
-    public static ActionResultResponse openUrlInBrowser(final AjaxRequestTarget target, final URL url) {
+    
+    public static ActionResultResponse openUrlInBrowser(
+            final AjaxRequestTarget target, 
+            final String url, 
+            final @NonNull OpenUrlStrategy openUrlStrategy) {
         return new ActionResultResponse(
-                ActionResultResponseHandlingStrategy.OPEN_URL_IN_BROWSER, null, null, target, url);
+                openUrlStrategy.isNewWindow()
+                    ? ActionResultResponseHandlingStrategy.OPEN_URL_IN_NEW_BROWSER_WINDOW 
+                    : ActionResultResponseHandlingStrategy.OPEN_URL_IN_SAME_BROWSER_WINDOW,
+                null, null, target, url);
     }
+    
     private ActionResultResponse(
             final ActionResultResponseHandlingStrategy strategy,
             final IRequestHandler handler,
             final PageAbstract page,
             final AjaxRequestTarget target,
-            final URL url) {
-        handlingStrategy = strategy;
+            final String url) {
+        this.handlingStrategy = strategy;
         this.handler = handler;
         this.page = page;
         this.target = target;
@@ -73,22 +84,29 @@ public class ActionResultResponse {
     public IRequestHandler getHandler() {
         return handler;
     }
+    
     /**
      * Populated only if {@link #getHandlingStrategy() handling strategy} is {@link ActionResultResponseHandlingStrategy#REDIRECT_TO_PAGE}
      */
     public PageAbstract getToPage() {
         return page;
     }
+    
     /**
-     * Populated only if {@link #getHandlingStrategy() handling strategy} is {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_BROWSER}
+     * Populated only if {@link #getHandlingStrategy() handling strategy} is 
+     * either {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_NEW_BROWSER_WINDOW}
+     * or {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_SAME_BROWSER_WINDOW}
      */
     public AjaxRequestTarget getTarget() {
         return target;
     }
+    
     /**
-     * Populated only if {@link #getHandlingStrategy() handling strategy} is {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_BROWSER}
+     * Populated only if {@link #getHandlingStrategy() handling strategy} is 
+     * either {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_NEW_BROWSER_WINDOW}
+     * or {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_SAME_BROWSER_WINDOW}
      */
-    public URL getUrl() {
+    public String getUrl() {
         return url;
     }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
index b60d137..5df4e5f 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
@@ -18,19 +18,20 @@
  */
 package org.apache.isis.viewer.wicket.ui.actionresponse;
 
-import java.net.URL;
-
 import org.apache.wicket.Component;
 import org.apache.wicket.Page;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.behavior.AbstractAjaxBehavior;
+import org.apache.wicket.request.IRequestHandler;
 import org.apache.wicket.request.Url;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
+import org.apache.wicket.request.http.handler.RedirectRequestHandler;
 import org.apache.wicket.request.resource.ContentDisposition;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.time.Duration;
 
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
 import org.apache.isis.viewer.wicket.model.models.VoidModel;
 import org.apache.isis.viewer.wicket.ui.pages.voidreturn.VoidReturnPage;
@@ -79,31 +80,53 @@ public enum ActionResultResponseHandlingStrategy {
             } else {
                 // otherwise,
                 // Ajax request => respond with a redirect to be able to stream the Lob to the client
-                ResourceStreamRequestHandler scheduledHandler = (ResourceStreamRequestHandler) resultResponse.getHandler();
-                StreamAfterAjaxResponseBehavior streamingBehavior = new StreamAfterAjaxResponseBehavior(scheduledHandler);
-                final Page page = target.getPage();
-                page.add(streamingBehavior);
-                CharSequence callbackUrl = streamingBehavior.getCallbackUrl();
-                target.appendJavaScript("setTimeout(\"window.location.href='" + callbackUrl + "'\", 10);");
+                final IRequestHandler requestHandler = resultResponse.getHandler();
+                if(requestHandler instanceof ResourceStreamRequestHandler) {
+                    ResourceStreamRequestHandler scheduledHandler = (ResourceStreamRequestHandler) requestHandler;
+                    StreamAfterAjaxResponseBehavior streamingBehavior = new StreamAfterAjaxResponseBehavior(scheduledHandler);
+                    final Page page = target.getPage();
+                    page.add(streamingBehavior);
+                    CharSequence callbackUrl = streamingBehavior.getCallbackUrl();
+                    scheduleJs(target, javascriptFor_sameWindow(callbackUrl), 10);    
+                } else if(requestHandler instanceof RedirectRequestHandler) {
+                    RedirectRequestHandler redirectHandler = (RedirectRequestHandler) requestHandler;
+                    requestCycle.scheduleRequestHandlerAfterCurrent(redirectHandler);
+                } else {
+                    throw _Exceptions.unrecoverableFormatted(
+                            "no logic implemented to handle IRequestHandler of type %s",
+                            requestHandler.getClass().getName());
+                }
+                
             }
-
         }
     },
-    OPEN_URL_IN_BROWSER {
+    OPEN_URL_IN_NEW_BROWSER_WINDOW {
         @Override
         public void handleResults(
                 IsisAppCommonContext commonContext,
                 ActionResultResponse resultResponse) {
             
             final AjaxRequestTarget target = resultResponse.getTarget();
-            final URL url = resultResponse.getUrl();
-
+            final String url = resultResponse.getUrl();
             final RequestCycle requestCycle = RequestCycle.get();
-
             final String fullUrl = expanded(requestCycle, url);
-            target.appendJavaScript("setTimeout(function(){Wicket.Event.publish(Isis.Topic.OPEN_IN_NEW_TAB, '" + fullUrl + "');}, 100);");
+            
+            scheduleJs(target, javascriptFor_newWindow(fullUrl), 100);
+        }
+    },
+    OPEN_URL_IN_SAME_BROWSER_WINDOW {
+        @Override
+        public void handleResults(
+                IsisAppCommonContext commonContext,
+                ActionResultResponse resultResponse) {
+            
+            final AjaxRequestTarget target = resultResponse.getTarget();
+            final String url = resultResponse.getUrl();
+            final RequestCycle requestCycle = RequestCycle.get();
+            final String fullUrl = expanded(requestCycle, url);
+            
+            scheduleJs(target, javascriptFor_sameWindow(fullUrl), 100);
         }
-
     };
 
     public abstract void handleResults(
@@ -113,19 +136,12 @@ public enum ActionResultResponseHandlingStrategy {
     /**
      * @see #expanded(String)
      */
-    public static String expanded(RequestCycle requestCycle, final URL url) {
+    public static String expanded(RequestCycle requestCycle, final String url) {
         String urlStr = expanded(url);
         return requestCycle.getUrlRenderer().renderFullUrl(Url.parse(urlStr));
     }
 
     /**
-     * @see #expanded(String)
-     */
-    public static String expanded(final URL url) {
-        return expanded(url.toString());
-    }
-
-    /**
      * very simple templating support, the idea being that "antiCache=${currentTimeMillis}"
      * will be replaced automatically.
      */
@@ -136,6 +152,20 @@ public enum ActionResultResponseHandlingStrategy {
         return urlStr;
     }
 
+    private static String javascriptFor_newWindow(CharSequence url) {
+        return "function(){Wicket.Event.publish(Isis.Topic.OPEN_IN_NEW_TAB, '" + url + "');}";
+    }
+    
+    private static String javascriptFor_sameWindow(CharSequence url) {
+        return "\"window.location.href='" + url + "'\"";
+    }
+    
+    private static void scheduleJs(AjaxRequestTarget target, String js, int millis) {
+        // the timeout is needed to let Wicket release the channel
+        target.appendJavaScript(String.format("setTimeout(%s, %d);", js, millis));        
+    }
+    
+    
     /**
      * A special Ajax behavior that is used to stream the contents of a Lob after
      * an Ajax request.
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
index 66f11a4..16439da 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
@@ -27,6 +27,8 @@ import org.apache.wicket.request.IRequestHandler;
 
 import org.apache.isis.applib.value.Blob;
 import org.apache.isis.applib.value.Clob;
+import org.apache.isis.applib.value.LocalResourcePath;
+import org.apache.isis.applib.value.OpenUrlStrategy;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -41,6 +43,7 @@ import org.apache.isis.viewer.wicket.ui.pages.standalonecollection.StandaloneCol
 import org.apache.isis.viewer.wicket.ui.pages.value.ValuePage;
 import org.apache.isis.viewer.wicket.ui.pages.voidreturn.VoidReturnPage;
 
+import lombok.SneakyThrows;
 import lombok.val;
 
 public enum ActionResultResponseType {
@@ -94,13 +97,30 @@ public enum ActionResultResponseType {
             return ActionResultResponse.withHandler(handler);
         }
     },
+    VALUE_LOCALRESPATH_AJAX {
+        @Override @SneakyThrows
+        public ActionResultResponse interpretResult(ActionModel model, AjaxRequestTarget target, ManagedObject resultAdapter) {
+            final LocalResourcePath localResPath = (LocalResourcePath)resultAdapter.getPojo();
+            return ActionResultResponse
+                    .openUrlInBrowser(target, localResPath.getPath(), localResPath.getOpenUrlStrategy());
+        }
+    },
+    VALUE_LOCALRESPATH_NOAJAX {
+        @Override
+        public ActionResultResponse interpretResult(ActionModel model, AjaxRequestTarget target, ManagedObject resultAdapter) {
+            // open URL server-side redirect
+            final Object value = resultAdapter.getPojo();
+            IRequestHandler handler = ActionModel.redirectHandler(value);
+            return ActionResultResponse.withHandler(handler);
+        }
+    },
     VALUE_URL_AJAX {
         @Override
         public ActionResultResponse interpretResult(ActionModel model, AjaxRequestTarget target, ManagedObject resultAdapter) {
             final URL url = (URL)resultAdapter.getPojo();
-            return ActionResultResponse.openUrlInBrowser(target, url);
+            return ActionResultResponse
+                    .openUrlInBrowser(target, url.toString(), OpenUrlStrategy.NEW_WINDOW); // default behavior
         }
-
     },
     VALUE_URL_NOAJAX {
         @Override
@@ -110,7 +130,6 @@ public enum ActionResultResponseType {
             IRequestHandler handler = ActionModel.redirectHandler(value);
             return ActionResultResponse.withHandler(handler);
         }
-
     },
     VOID {
         @Override
@@ -190,8 +209,15 @@ public enum ActionResultResponseType {
                 if(value instanceof Blob) {
                     return ActionResultResponseType.VALUE_BLOB;
                 }
+                if(value instanceof LocalResourcePath) {
+                    return targetIfAny != null
+                            ? ActionResultResponseType.VALUE_LOCALRESPATH_AJAX
+                            : ActionResultResponseType.VALUE_LOCALRESPATH_NOAJAX;
+                }
                 if(value instanceof java.net.URL) {
-                    return targetIfAny != null? ActionResultResponseType.VALUE_URL_AJAX: ActionResultResponseType.VALUE_URL_NOAJAX;
+                    return targetIfAny != null
+                            ? ActionResultResponseType.VALUE_URL_AJAX
+                            : ActionResultResponseType.VALUE_URL_NOAJAX;
                 }
                 // else
                 return ActionResultResponseType.VALUE;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java
index 89ca475..84e12c2 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java
@@ -28,7 +28,6 @@ import org.apache.wicket.extensions.ajax.markup.html.AjaxIndicatorAppender;
 import org.apache.wicket.markup.ComponentTag;
 
 import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.value.LocalResourcePath;
 import org.apache.isis.commons.internal.debug._Probe;
 import org.apache.isis.commons.internal.debug._Probe.EntryPoint;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -50,8 +49,6 @@ public abstract class ActionLink extends AjaxLink<ManagedObject> implements IAja
 
     private final AjaxIndicatorAppender indicatorAppenderIfAny;
 
-    final AjaxDeferredBehaviour ajaxDeferredBehaviourIfAny;
-
     protected transient IsisAppCommonContext commonContext;
 
     ActionLink(IsisAppCommonContext commonContext, String id, ActionModel model) {
@@ -63,21 +60,15 @@ public abstract class ActionLink extends AjaxLink<ManagedObject> implements IAja
         this.indicatorAppenderIfAny =
                 useIndicatorForNoArgAction
                 ? new AjaxIndicatorAppender()
-                        : null;
+                : null;
 
-                if(this.indicatorAppenderIfAny != null) {
-                    this.add(this.indicatorAppenderIfAny);
-                }
+        if(this.indicatorAppenderIfAny != null) {
+            this.add(this.indicatorAppenderIfAny);
+        }
 
-                // trivial optimization; also store the objectAction if it is available (saves looking it up)
-                objectAction = model.getMetaModel();
+        // trivial optimization; also store the objectAction if it is available (saves looking it up)
+        objectAction = model.getMetaModel();
 
-                // this returns non-null if the action is no-arg and returns a LocalResourcePath or URL.
-                // Otherwise can use default handling
-                ajaxDeferredBehaviourIfAny = determineDeferredBehaviour();
-                if(ajaxDeferredBehaviourIfAny != null) {
-                    this.add(ajaxDeferredBehaviourIfAny);
-                }
     }
     
     public IsisAppCommonContext getCommonContext() {
@@ -90,12 +81,6 @@ public abstract class ActionLink extends AjaxLink<ManagedObject> implements IAja
         _Probe.entryPoint(EntryPoint.USER_INTERACTION, "Wicket Ajax Request, "
                 + "originating from User clicking an Action Link.");
 
-        if(ajaxDeferredBehaviourIfAny!=null
-                && ajaxDeferredBehaviourIfAny.needsDeferring()) {
-            ajaxDeferredBehaviourIfAny.initiate(target);
-            return;
-        }
-
         doOnClick(target);
     }
 
@@ -181,20 +166,4 @@ public abstract class ActionLink extends AjaxLink<ManagedObject> implements IAja
         return ((WicketViewerSettingsAccessor) Application.get()).getSettings();
     }
 
-    // TODO: should unify with ActionResultResponseType (as used in ActionParametersPanel)
-    AjaxDeferredBehaviour determineDeferredBehaviour() {
-
-        val action = getObjectAction();
-        val actionReturnTypeSpec = action.getReturnType();
-        
-        if(action.getParameterCount() > 0 
-                || actionReturnTypeSpec == null) {
-            return null; // default behavior, don't defer
-        }
-
-        // use redirect handler, which only executes if needed 
-        return AjaxDeferredBehaviour.redirecting(this.getActionModel());
-    }
-
-
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/AjaxDeferredBehaviour.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/AjaxDeferredBehaviour.java
deleted file mode 100644
index 4b68007..0000000
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/AjaxDeferredBehaviour.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- *  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.isis.viewer.wicket.ui.components.widgets.linkandlabel;
-
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.behavior.AbstractAjaxBehavior;
-import org.apache.wicket.request.IRequestHandler;
-import org.apache.wicket.request.Url;
-
-import org.apache.isis.applib.value.LocalResourcePath;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.viewer.wicket.model.models.ActionModel;
-import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseHandlingStrategy;
-
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-
-@RequiredArgsConstructor
-public abstract class AjaxDeferredBehaviour extends AbstractAjaxBehavior {
-    private static final long serialVersionUID = 1L;
-    
-    private final @NonNull ActionModel actionModel;
-    
-    // -- FACTORIES
-
-    public static AjaxDeferredBehaviour redirecting(final @NonNull ActionModel actionModel){
-        
-        /**
-         * adapted from:
-         *
-         * @see https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
-         */
-        return new AjaxDeferredBehaviour(actionModel) {
-
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public boolean needsDeferring() {
-                // introspect the action result, to decide whether needs deferring
-                val value = getResultValue();
-                if(value==null) {
-                    return false;
-                }
-                return value instanceof LocalResourcePath
-                        || value instanceof java.net.URL;
-            }
-            
-            
-            @Override
-            protected String javascriptFor(String url) {
-                // introspect the action result, to decide which JS to use
-                val value = getResultValue();
-                if(value instanceof LocalResourcePath) {
-                    if(((LocalResourcePath)value).getOpenUrlStrategy().isSameWindow()) {
-                        return javascriptFor_sameWindow(this, url);
-                    }
-                }
-                return javascriptFor_newWindow(this, url);
-            }
-            
-            @Override
-            protected IRequestHandler getRequestHandler() {
-                val value = getResultValue();
-                freeResultValue();
-                return ActionModel.redirectHandler(value);
-            }
-            
-        };
-    }
-    
-    // -- IMPL
-
-    /**
-     * Call this method to initiate the download or redirect.
-     */
-    public void initiate(
-            final @NonNull AjaxRequestTarget target) {
-        
-        val url = ActionResultResponseHandlingStrategy.expanded(getCallbackUrl().toString());
-        val js = javascriptFor(url);
-
-        // the timeout is needed to let Wicket release the channel
-        target.appendJavaScript(String.format("setTimeout(%s, 100);", js));
-    }
-
-    @Override
-    public void onRequest() {
-        IRequestHandler handler = getRequestHandler();
-        if(handler != null) {
-            getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
-        }
-    }
-    
-    public abstract boolean needsDeferring();
-    protected abstract IRequestHandler getRequestHandler();
-    protected abstract String javascriptFor(String url);
-    
-    // -- RESULT MEMOIZATION
-    
-    private transient ManagedObject resultAdapter = null;
-    
-    protected Object getResultValue() {
-        if(resultAdapter==null) {
-            resultAdapter = actionModel.execute();
-        }
-        return ManagedObjects.UnwrapUtil.single(resultAdapter);
-    }
-    
-    protected void freeResultValue() {
-        resultAdapter = null;
-    }
-    
-    // -- HELPER
-    
-    private static String javascriptFor_newWindow(AjaxDeferredBehaviour deferredBehaviour, String url) {
-        val parsedUrl = Url.parse(url);
-        val requestCycle = deferredBehaviour.getComponent().getRequestCycle();
-        val urlRenderer = requestCycle.getUrlRenderer();
-        val fullUrl = urlRenderer.renderFullUrl(parsedUrl);
-        return "function(){Wicket.Event.publish(Isis.Topic.OPEN_IN_NEW_TAB, '" + fullUrl + "');}";
-    }
-    
-    private static String javascriptFor_sameWindow(AjaxDeferredBehaviour deferredBehaviour, String url) {
-        return "\"window.location.href='" + url + "'\"";
-    }
-
-    
-}