You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wicket.apache.org by dashorst <gi...@git.apache.org> on 2015/12/23 21:17:57 UTC
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
GitHub user dashorst opened a pull request:
https://github.com/apache/wicket/pull/151
WICKET-6055 Made AjaxLazyLoadPanel non-blocking
When having multiple AjaxLazyLoadPanels on your page, they all block
their Wicket request thread until the content is ready to load. This
can be problematic when you try to wait for some background job to
finish and want to poll for that job to be ready, and only then update
the contents.
The improvement would be to add a method that gives the developer the
option to not update just yet (isReadyForReplacement) and when it
returns true, start the replacement. By default this would return true,
implementing the current behavior of the AjaxLazyLoadPanel.
Furthermore to improve the responsiveness of the ALLP it should add a
single timer to the page that can be used by multiple ALLPs to update
themselves. The timer would poll each second and the ALLPs would use
Wicket's event bus to update themselves. With some reference counting,
the timer can remove itself from the page when all ALLPs have updated
themselves.
This enables refreshing the page as well when outside an AJAX context,
or having a user be impatient and pressing F5.
Fixes WICKET-6055
You can merge this pull request into a Git repository by running:
$ git pull https://github.com/dashorst/wicket WICKET-6055
Alternatively you can review and apply these changes as the patch at:
https://github.com/apache/wicket/pull/151.patch
To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:
This closes #151
----
commit 73ed63dac6e4426c843b4826406fab1984264d9d
Author: Martijn Dashorst <ma...@gmail.com>
Date: 2015-12-23T20:16:43Z
WICKET-6055 Made AjaxLazyLoadPanel non-blocking
When having multiple AjaxLazyLoadPanels on your page, they all block
their Wicket request thread until the content is ready to load. This
can be problematic when you try to wait for some background job to
finish and want to poll for that job to be ready, and only then update
the contents.
The improvement would be to add a method that gives the developer the
option to not update just yet (isReadyForReplacement) and when it
returns true, start the replacement. By default this would return true,
implementing the current behavior of the AjaxLazyLoadPanel.
Furthermore to improve the responsiveness of the ALLP it should add a
single timer to the page that can be used by multiple ALLPs to update
themselves. The timer would poll each second and the ALLPs would use
Wicket's event bus to update themselves. With some reference counting,
the timer can remove itself from the page when all ALLPs have updated
themselves.
This enables refreshing the page as well when outside an AJAX context,
or having a user be impatient and pressing F5.
Fixes WICKET-6055
----
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48417106
--- Diff: wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java ---
@@ -16,38 +16,100 @@
*/
package org.apache.wicket.examples.ajax.builtin;
+import java.util.Random;
+
import org.apache.wicket.Component;
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.EmptyPanel;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.util.time.Duration;
-/**
- * @author jcompagner
- */
+@SuppressWarnings({ "javadoc", "serial" })
public class LazyLoadingPage extends BasePage
{
- /**
- * Construct.
- */
+ private Random r = new Random();
+
public LazyLoadingPage()
{
- add(new AjaxLazyLoadPanel("lazy")
+ add(new Link<Void>("startNonblocking")
+ {
+ @Override
+ public void onClick()
+ {
+ addNonBlockingPanels();
+ }
+ });
+ add(new Link<Void>("startBlocking")
{
-
@Override
- public Component getLazyLoadComponent(String id)
+ public void onClick()
{
- // sleep for 5 seconds to show the behavior
- try
+ addBlockingPanels();
+ }
+ });
+
+ add(new EmptyPanel("lazy"));
+ add(new EmptyPanel("lazy2"));
+ }
+
+ private void addNonBlockingPanels()
+ {
+ RepeatingView rv;
+ addOrReplace(rv = new RepeatingView("lazy"));
+
+ for (int i = 0; i < 10; i++)
+ rv.add(new AjaxLazyLoadPanel(rv.newChildId())
+ {
+ private static final long serialVersionUID = 1L;
+
+ private long startTime = System.currentTimeMillis();
+
+ private int seconds = r.nextInt(10);
+
+ @Override
+ protected boolean isReadyForReplacement()
{
- Thread.sleep(5000);
+ return Duration.milliseconds(System.currentTimeMillis() - startTime)
+ .seconds() > seconds;
}
- catch (InterruptedException e)
+
+ @Override
+ public Component getLazyLoadComponent(String id)
{
- throw new RuntimeException(e);
+ return new Label(id, "Lazy Loaded after " + seconds + " seconds");
}
- return new Label(id, "Lazy Loaded after 5 seconds");
- }
+ });
+ }
- });
+ private void addBlockingPanels()
+ {
+ RepeatingView rv;
+ addOrReplace(rv = new RepeatingView("lazy2"));
+
+ for (int i = 0; i < 5; i++)
+ rv.add(new AjaxLazyLoadPanel(rv.newChildId())
+ {
+ private static final long serialVersionUID = 1L;
+
+ private int seconds = r.nextInt(5);
+
+ @Override
+ public Component getLazyLoadComponent(String markupId)
+ {
+ try
+ {
+ System.out.println("Starting sleep");
--- End diff --
oopsie, this one should've been removed.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r52115636
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
--- End diff --
No, as `isReadyForReplacement()` is actually there for preventing replacement prematurely. Why would you wait until some time in the future to do the replacement when you can replace now and the component is ready for replacement?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48414165
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -187,8 +237,56 @@ public Component getLoadingComponent(final String markupId)
{
IRequestHandler handler = new ResourceReferenceRequestHandler(
AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
+ return new Label(markupId,
+ "<img alt=\"Loading...\" src=\"" + RequestCycle.get().urlFor(handler) + "\"/>")
+ .setEscapeModelStrings(false);
}
+ /**
+ * Factory method for creating the lazily loaded component that replaces the spinner after
+ * {@link #isReadyForReplacement()} returns {@code true}. You may call setRenderBodyOnly(true)
+ * on this component if you need the body only.
+ *
+ * @param markupId
+ * The components markupid.
+ * @return The component that must be lazy created.
+ */
+ public abstract Component getLazyLoadComponent(String markupId);
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private int lazyLoadPanels = 0;
--- End diff --
Fixed it by tracking the panels directly.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r52115621
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
+ {
+ if (isReadyForReplacement())
+ {
+ // create the lazy load component
+ Component component = getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
+
+ // replace the spinner with the new component
+ AjaxLazyLoadPanel.this.replace(component);
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ getLazyLoadTimer().removeLazyLoadPanel(this);
+
+ AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
+
+ // notify our subclasses of the updated component
+ onComponentLoaded(component, target);
+
+ // repaint our selves if there's an AJAX request in play, otherwise let the page
+ // redraw itself
+ if (target != null)
+ {
+ target.add(AjaxLazyLoadPanel.this);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ AjaxLazyLoadTimer timer = getLazyLoadTimer();
+ if (timer != null)
+ {
+ timer.removeLazyLoadPanel(this);
+ }
+ }
+
/**
+ * Sets the new LoadingState for this panel.
*
- * @param state
+ * @param newState
*/
- private void setState(final byte state)
+ private void setState(final LoadingState newState)
{
- this.state = state;
+ this.state = newState;
getPage().dirty();
}
/**
+ * Gets the central lazy load timer from the page if one is registered
*
- * @param markupId
- * The components markupid.
- * @return The component that must be lazy created. You may call setRenderBodyOnly(true) on this
- * component if you need the body only.
+ * @return the central lazy load timer or {@code null}
*/
- public abstract Component getLazyLoadComponent(String markupId);
+ private AjaxLazyLoadTimer getLazyLoadTimer()
+ {
+ return getPage().getMetaData(AJAX_LAZY_LOAD_TIMER);
+ }
/**
- * Called when the placeholder component is replaced with the lazy loaded one.
- *
- * @param component
- * The lazy loaded component
- * @param target
- * The Ajax request handler
+ * Sets the central lazy load timer on the page
+ *
+ * @param timer
+ * the timer to set
*/
- protected void onComponentLoaded(Component component, AjaxRequestTarget target)
+ private void setLazyLoadTimer(AjaxLazyLoadTimer timer)
{
+ getPage().setMetaData(AJAX_LAZY_LOAD_TIMER, timer);
}
/**
- * @param markupId
- * The components markupid.
- * @return The component to show while the real component is being created.
+ * @deprecated No longer called as the AjaxLazyLoadPanel uses a central AJAX timer, and it
+ * doesn't make sense to modify the single timer from multiple panels
*/
- public Component getLoadingComponent(final String markupId)
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
- IRequestHandler handler = new ResourceReferenceRequestHandler(
- AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
}
+ /**
+ * Allows subclasses to change the callback script if needed.
+ *
+ * @param response
+ * the current response that writes to the header
+ * @param callbackScript
+ * the JavaScript to write in the header
+ * @param component
+ * the component which produced the callback script
+ */
+ protected void handleCallbackScript(final IHeaderResponse response,
+ final CharSequence callbackScript, final Component component)
+ {
+ response.render(OnDomReadyHeaderItem.forScript(callbackScript));
+ }
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final List<AjaxLazyLoadPanel> lazyLoadPanels = new ArrayList<>();
+
+ public AjaxLazyLoadTimer()
+ {
+ super(Duration.ONE_SECOND);
--- End diff --
The `ALLT` is per-page. Perhaps we can check if the Page implements a special settings interface e.g. `IAjaxLazyLoadTimerSettings` and retrieve the duration from that?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket issue #151: WICKET-6055 Made AjaxLazyLoadPanel non-blocking
Posted by martin-g <gi...@git.apache.org>.
Github user martin-g commented on the issue:
https://github.com/apache/wicket/pull/151
@dashorst Ping!
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by martin-g <gi...@git.apache.org>.
Github user martin-g commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48414764
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -74,63 +106,74 @@ public AjaxLazyLoadPanel(final String id, final IModel<?> model)
super(id, model);
setOutputMarkupId(true);
+ }
- add(new AbstractDefaultAjaxBehavior()
- {
- private static final long serialVersionUID = 1L;
-
- @Override
- protected void respond(final AjaxRequestTarget target)
- {
- if (state < 2)
- {
- Component component = getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
- AjaxLazyLoadPanel.this.replace(component);
- setState((byte) 2);
- AjaxLazyLoadPanel.this.onComponentLoaded(component, target);
- }
- target.add(AjaxLazyLoadPanel.this);
-
- }
-
- @Override
- protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
- {
- super.updateAjaxAttributes(attributes);
- AjaxLazyLoadPanel.this.updateAjaxAttributes(attributes);
- }
-
- @Override
- public void renderHead(final Component component, final IHeaderResponse response)
- {
- super.renderHead(component, response);
- if (state < 2)
- {
- CharSequence js = getCallbackScript(component);
- handleCallbackScript(response, js, component);
- }
- }
- });
+ /**
+ * Determines that the component we're waiting for is ready for replacement, typically used in
+ * polling background threads for their result. Override this to implement your own check.
+ *
+ * @return true when the LazyLoadPanel should replace its contents with the actual component
+ */
+ protected boolean isReadyForReplacement()
+ {
+ return true;
}
- protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
+ /**
+ * Gets the spinner component shown when the lazy component is not ready yet.
+ *
+ * @param markupId
+ * The components markupid.
+ * @return The component to show while the real component is being created.
+ */
+ public Component getLoadingComponent(final String markupId)
{
+ IRequestHandler handler = new ResourceReferenceRequestHandler(
+ AbstractDefaultAjaxBehavior.INDICATOR);
+ return new Label(markupId,
+ "<img alt=\"Loading...\" src=\"" + RequestCycle.get().urlFor(handler) + "\"/>")
+ .setEscapeModelStrings(false);
}
/**
- * Allows subclasses to change the callback script if needed.
+ * Factory method for creating the lazily loaded component that replaces the spinner after
+ * {@link #isReadyForReplacement()} returns {@code true}. You may call setRenderBodyOnly(true)
+ * on this component if you need the body only.
*
- * @param response
- * the current response that writes to the header
- * @param callbackScript
- * the JavaScript to write in the header
+ * @param markupId
+ * The components markupid.
+ * @return The component that must be lazy created.
+ */
+ public abstract Component getLazyLoadComponent(String markupId);
+
+ /**
+ * Called when the placeholder component is replaced with the lazy loaded one.
+ *
* @param component
- * the component which produced the callback script
+ * The lazy loaded component
+ * @param target
+ * The Ajax request handler, can be null
*/
- protected void handleCallbackScript(final IHeaderResponse response,
- final CharSequence callbackScript, final Component component)
+ protected void onComponentLoaded(Component component, AjaxRequestTarget target)
{
- response.render(OnDomReadyHeaderItem.forScript(callbackScript));
+ }
+
+ @Override
+ protected void onInitialize()
+ {
+ super.onInitialize();
+
+ // when the timer is not yet installed add it
+ AjaxLazyLoadTimer timer = getLazyLoadTimer();
+ if (timer == null)
+ {
+ timer = new AjaxLazyLoadTimer();
+ setLazyLoadTimer(timer);
+ getPage().add(timer);
--- End diff --
I think there is no need to keep two references to the timer in the page.
You can use `page.getBehaviors(AjaxLazyLoadTimer.class).get(0)` to get the reference. No need of meta data.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request #151: WICKET-6055 Made AjaxLazyLoadPanel non-blocking
Posted by Jezza <gi...@git.apache.org>.
Github user Jezza commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r89122777
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
+ {
+ if (isReadyForReplacement())
+ {
+ // create the lazy load component
+ Component component = getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
+
+ // replace the spinner with the new component
+ AjaxLazyLoadPanel.this.replace(component);
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ getLazyLoadTimer().removeLazyLoadPanel(this);
+
+ AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
+
+ // notify our subclasses of the updated component
+ onComponentLoaded(component, target);
+
+ // repaint our selves if there's an AJAX request in play, otherwise let the page
+ // redraw itself
+ if (target != null)
+ {
+ target.add(AjaxLazyLoadPanel.this);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ AjaxLazyLoadTimer timer = getLazyLoadTimer();
+ if (timer != null)
+ {
+ timer.removeLazyLoadPanel(this);
+ }
+ }
+
/**
+ * Sets the new LoadingState for this panel.
*
- * @param state
+ * @param newState
*/
- private void setState(final byte state)
+ private void setState(final LoadingState newState)
{
- this.state = state;
+ this.state = newState;
getPage().dirty();
}
/**
+ * Gets the central lazy load timer from the page if one is registered
*
- * @param markupId
- * The components markupid.
- * @return The component that must be lazy created. You may call setRenderBodyOnly(true) on this
- * component if you need the body only.
+ * @return the central lazy load timer or {@code null}
*/
- public abstract Component getLazyLoadComponent(String markupId);
+ private AjaxLazyLoadTimer getLazyLoadTimer()
+ {
+ return getPage().getMetaData(AJAX_LAZY_LOAD_TIMER);
+ }
/**
- * Called when the placeholder component is replaced with the lazy loaded one.
- *
- * @param component
- * The lazy loaded component
- * @param target
- * The Ajax request handler
+ * Sets the central lazy load timer on the page
+ *
+ * @param timer
+ * the timer to set
*/
- protected void onComponentLoaded(Component component, AjaxRequestTarget target)
+ private void setLazyLoadTimer(AjaxLazyLoadTimer timer)
{
+ getPage().setMetaData(AJAX_LAZY_LOAD_TIMER, timer);
}
/**
- * @param markupId
- * The components markupid.
- * @return The component to show while the real component is being created.
+ * @deprecated No longer called as the AjaxLazyLoadPanel uses a central AJAX timer, and it
+ * doesn't make sense to modify the single timer from multiple panels
*/
- public Component getLoadingComponent(final String markupId)
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
- IRequestHandler handler = new ResourceReferenceRequestHandler(
- AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
}
+ /**
+ * Allows subclasses to change the callback script if needed.
+ *
+ * @param response
+ * the current response that writes to the header
+ * @param callbackScript
+ * the JavaScript to write in the header
+ * @param component
+ * the component which produced the callback script
+ */
+ protected void handleCallbackScript(final IHeaderResponse response,
+ final CharSequence callbackScript, final Component component)
+ {
+ response.render(OnDomReadyHeaderItem.forScript(callbackScript));
+ }
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final List<AjaxLazyLoadPanel> lazyLoadPanels = new ArrayList<>();
+
+ public AjaxLazyLoadTimer()
+ {
+ super(Duration.ONE_SECOND);
--- End diff --
Yeah, I was just about to say, why not delegate it to the page.
That seems like a nice compromise between making sure we don't flood the server, and we can control the polling time.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request #151: WICKET-6055 Made AjaxLazyLoadPanel non-blocking
Posted by Jezza <gi...@git.apache.org>.
Github user Jezza commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r89123046
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
+ {
+ if (isReadyForReplacement())
+ {
+ // create the lazy load component
+ Component component = getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
+
+ // replace the spinner with the new component
+ AjaxLazyLoadPanel.this.replace(component);
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ getLazyLoadTimer().removeLazyLoadPanel(this);
+
+ AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
+
+ // notify our subclasses of the updated component
+ onComponentLoaded(component, target);
+
+ // repaint our selves if there's an AJAX request in play, otherwise let the page
+ // redraw itself
+ if (target != null)
+ {
+ target.add(AjaxLazyLoadPanel.this);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ AjaxLazyLoadTimer timer = getLazyLoadTimer();
+ if (timer != null)
+ {
+ timer.removeLazyLoadPanel(this);
+ }
+ }
+
/**
+ * Sets the new LoadingState for this panel.
*
- * @param state
+ * @param newState
*/
- private void setState(final byte state)
+ private void setState(final LoadingState newState)
{
- this.state = state;
+ this.state = newState;
getPage().dirty();
}
/**
+ * Gets the central lazy load timer from the page if one is registered
*
- * @param markupId
- * The components markupid.
- * @return The component that must be lazy created. You may call setRenderBodyOnly(true) on this
- * component if you need the body only.
+ * @return the central lazy load timer or {@code null}
*/
- public abstract Component getLazyLoadComponent(String markupId);
+ private AjaxLazyLoadTimer getLazyLoadTimer()
+ {
+ return getPage().getMetaData(AJAX_LAZY_LOAD_TIMER);
+ }
/**
- * Called when the placeholder component is replaced with the lazy loaded one.
- *
- * @param component
- * The lazy loaded component
- * @param target
- * The Ajax request handler
+ * Sets the central lazy load timer on the page
+ *
+ * @param timer
+ * the timer to set
*/
- protected void onComponentLoaded(Component component, AjaxRequestTarget target)
+ private void setLazyLoadTimer(AjaxLazyLoadTimer timer)
{
+ getPage().setMetaData(AJAX_LAZY_LOAD_TIMER, timer);
}
/**
- * @param markupId
- * The components markupid.
- * @return The component to show while the real component is being created.
+ * @deprecated No longer called as the AjaxLazyLoadPanel uses a central AJAX timer, and it
+ * doesn't make sense to modify the single timer from multiple panels
*/
- public Component getLoadingComponent(final String markupId)
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
- IRequestHandler handler = new ResourceReferenceRequestHandler(
- AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
}
+ /**
+ * Allows subclasses to change the callback script if needed.
+ *
+ * @param response
+ * the current response that writes to the header
+ * @param callbackScript
+ * the JavaScript to write in the header
+ * @param component
+ * the component which produced the callback script
+ */
+ protected void handleCallbackScript(final IHeaderResponse response,
+ final CharSequence callbackScript, final Component component)
+ {
+ response.render(OnDomReadyHeaderItem.forScript(callbackScript));
+ }
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final List<AjaxLazyLoadPanel> lazyLoadPanels = new ArrayList<>();
+
+ public AjaxLazyLoadTimer()
+ {
+ super(Duration.ONE_SECOND);
--- End diff --
Or go one step futher, and make it a parent interface.
So, you just call findParent(IAjaxLazyLoadTimerSettings.class), and that way we have even more control over it, and it will still work when attached only to a page.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by martin-g <gi...@git.apache.org>.
Github user martin-g commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48414551
--- Diff: wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java ---
@@ -16,38 +16,100 @@
*/
package org.apache.wicket.examples.ajax.builtin;
+import java.util.Random;
+
import org.apache.wicket.Component;
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.EmptyPanel;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.util.time.Duration;
-/**
- * @author jcompagner
- */
+@SuppressWarnings({ "javadoc", "serial" })
public class LazyLoadingPage extends BasePage
{
- /**
- * Construct.
- */
+ private Random r = new Random();
+
public LazyLoadingPage()
{
- add(new AjaxLazyLoadPanel("lazy")
+ add(new Link<Void>("startNonblocking")
+ {
+ @Override
+ public void onClick()
+ {
+ addNonBlockingPanels();
+ }
+ });
+ add(new Link<Void>("startBlocking")
{
-
@Override
- public Component getLazyLoadComponent(String id)
+ public void onClick()
{
- // sleep for 5 seconds to show the behavior
- try
+ addBlockingPanels();
+ }
+ });
+
+ add(new EmptyPanel("lazy"));
+ add(new EmptyPanel("lazy2"));
+ }
+
+ private void addNonBlockingPanels()
+ {
+ RepeatingView rv;
+ addOrReplace(rv = new RepeatingView("lazy"));
+
+ for (int i = 0; i < 10; i++)
+ rv.add(new AjaxLazyLoadPanel(rv.newChildId())
+ {
+ private static final long serialVersionUID = 1L;
+
+ private long startTime = System.currentTimeMillis();
+
+ private int seconds = r.nextInt(10);
+
+ @Override
+ protected boolean isReadyForReplacement()
{
- Thread.sleep(5000);
+ return Duration.milliseconds(System.currentTimeMillis() - startTime)
+ .seconds() > seconds;
}
- catch (InterruptedException e)
+
+ @Override
+ public Component getLazyLoadComponent(String id)
{
- throw new RuntimeException(e);
+ return new Label(id, "Lazy Loaded after " + seconds + " seconds");
}
- return new Label(id, "Lazy Loaded after 5 seconds");
- }
+ });
+ }
- });
+ private void addBlockingPanels()
+ {
+ RepeatingView rv;
+ addOrReplace(rv = new RepeatingView("lazy2"));
+
+ for (int i = 0; i < 5; i++)
+ rv.add(new AjaxLazyLoadPanel(rv.newChildId())
+ {
+ private static final long serialVersionUID = 1L;
+
+ private int seconds = r.nextInt(5);
+
+ @Override
+ public Component getLazyLoadComponent(String markupId)
+ {
+ try
+ {
+ System.out.println("Starting sleep");
--- End diff --
Use Logger instead.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by svenmeier <gi...@git.apache.org>.
Github user svenmeier commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48427293
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
--- End diff --
Shouldn't #onEvent() check for a specific event? If other events are sent through the component hierarchy (e.g. when any other Ajax request is processed), the lazy component might be replaced prematurely.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by martin-g <gi...@git.apache.org>.
Github user martin-g commented on the pull request:
https://github.com/apache/wicket/pull/151#issuecomment-180774664
@dashorst What is the status here? Can I help somehow ?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by svenmeier <gi...@git.apache.org>.
Github user svenmeier commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48385474
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -187,8 +237,56 @@ public Component getLoadingComponent(final String markupId)
{
IRequestHandler handler = new ResourceReferenceRequestHandler(
AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
+ return new Label(markupId,
+ "<img alt=\"Loading...\" src=\"" + RequestCycle.get().urlFor(handler) + "\"/>")
+ .setEscapeModelStrings(false);
}
+ /**
+ * Factory method for creating the lazily loaded component that replaces the spinner after
+ * {@link #isReadyForReplacement()} returns {@code true}. You may call setRenderBodyOnly(true)
+ * on this component if you need the body only.
+ *
+ * @param markupId
+ * The components markupid.
+ * @return The component that must be lazy created.
+ */
+ public abstract Component getLazyLoadComponent(String markupId);
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private int lazyLoadPanels = 0;
--- End diff --
Counting all loading panels might be problematic: What if one (or one of its parents) is removed from the component hierarchy? The timer will keep requesting until forever.
How about broadcasting the AjaxLazyLoadTimer to all components, giving them the opportunity to keep the timer running?
((AjaxLazyLoadTimer)event.getPayload()).notReadyForReplacement();
If any of the panels is not ready yet, the timer has to keep running.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request #151: WICKET-6055 Made AjaxLazyLoadPanel non-blocking
Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:
https://github.com/apache/wicket/pull/151
---
[GitHub] wicket issue #151: WICKET-6055 Made AjaxLazyLoadPanel non-blocking
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on the issue:
https://github.com/apache/wicket/pull/151
Any comments about configuring the duration of the polling timer? I'm inclined to just defer that to a specific user request rather than implement it directly. Perhaps someone comes up with a better solution to configure the duration than what we have now. I'd rather wait for the need and a good solution than implement a solution that paints us in the corner.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48414009
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -187,8 +237,56 @@ public Component getLoadingComponent(final String markupId)
{
IRequestHandler handler = new ResourceReferenceRequestHandler(
AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
+ return new Label(markupId,
+ "<img alt=\"Loading...\" src=\"" + RequestCycle.get().urlFor(handler) + "\"/>")
+ .setEscapeModelStrings(false);
}
+ /**
+ * Factory method for creating the lazily loaded component that replaces the spinner after
+ * {@link #isReadyForReplacement()} returns {@code true}. You may call setRenderBodyOnly(true)
+ * on this component if you need the body only.
+ *
+ * @param markupId
+ * The components markupid.
+ * @return The component that must be lazy created.
+ */
+ public abstract Component getLazyLoadComponent(String markupId);
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
--- End diff --
It would not pose a problem and make the code simpler. With static I have to get the component's page and ran into a order problem of removing the behavior from the page and trying to change the page's meta data. The dangling reference is only a problem when you have memory constraints, but then the lazyloadpanel's reference would not be your biggest problem. Regardless I've changed it to be static.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by svenmeier <gi...@git.apache.org>.
Github user svenmeier commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48385193
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -187,8 +237,56 @@ public Component getLoadingComponent(final String markupId)
{
IRequestHandler handler = new ResourceReferenceRequestHandler(
AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
+ return new Label(markupId,
+ "<img alt=\"Loading...\" src=\"" + RequestCycle.get().urlFor(handler) + "\"/>")
+ .setEscapeModelStrings(false);
}
+ /**
+ * Factory method for creating the lazily loaded component that replaces the spinner after
+ * {@link #isReadyForReplacement()} returns {@code true}. You may call setRenderBodyOnly(true)
+ * on this component if you need the body only.
+ *
+ * @param markupId
+ * The components markupid.
+ * @return The component that must be lazy created.
+ */
+ public abstract Component getLazyLoadComponent(String markupId);
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
--- End diff --
This should probably be static to prevent a dangling reference to the surrounding component.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by dashorst <gi...@git.apache.org>.
Github user dashorst commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48417286
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
+ {
+ if (isReadyForReplacement())
+ {
+ // create the lazy load component
+ Component component = getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
+
+ // replace the spinner with the new component
+ AjaxLazyLoadPanel.this.replace(component);
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ getLazyLoadTimer().removeLazyLoadPanel(this);
+
+ AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
+
+ // notify our subclasses of the updated component
+ onComponentLoaded(component, target);
+
+ // repaint our selves if there's an AJAX request in play, otherwise let the page
+ // redraw itself
+ if (target != null)
+ {
+ target.add(AjaxLazyLoadPanel.this);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ AjaxLazyLoadTimer timer = getLazyLoadTimer();
+ if (timer != null)
+ {
+ timer.removeLazyLoadPanel(this);
+ }
+ }
+
/**
+ * Sets the new LoadingState for this panel.
*
- * @param state
+ * @param newState
*/
- private void setState(final byte state)
+ private void setState(final LoadingState newState)
{
- this.state = state;
+ this.state = newState;
getPage().dirty();
}
/**
+ * Gets the central lazy load timer from the page if one is registered
*
- * @param markupId
- * The components markupid.
- * @return The component that must be lazy created. You may call setRenderBodyOnly(true) on this
- * component if you need the body only.
+ * @return the central lazy load timer or {@code null}
*/
- public abstract Component getLazyLoadComponent(String markupId);
+ private AjaxLazyLoadTimer getLazyLoadTimer()
+ {
+ return getPage().getMetaData(AJAX_LAZY_LOAD_TIMER);
+ }
/**
- * Called when the placeholder component is replaced with the lazy loaded one.
- *
- * @param component
- * The lazy loaded component
- * @param target
- * The Ajax request handler
+ * Sets the central lazy load timer on the page
+ *
+ * @param timer
+ * the timer to set
*/
- protected void onComponentLoaded(Component component, AjaxRequestTarget target)
+ private void setLazyLoadTimer(AjaxLazyLoadTimer timer)
{
+ getPage().setMetaData(AJAX_LAZY_LOAD_TIMER, timer);
}
/**
- * @param markupId
- * The components markupid.
- * @return The component to show while the real component is being created.
+ * @deprecated No longer called as the AjaxLazyLoadPanel uses a central AJAX timer, and it
+ * doesn't make sense to modify the single timer from multiple panels
*/
- public Component getLoadingComponent(final String markupId)
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
- IRequestHandler handler = new ResourceReferenceRequestHandler(
- AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
}
+ /**
+ * Allows subclasses to change the callback script if needed.
+ *
+ * @param response
+ * the current response that writes to the header
+ * @param callbackScript
+ * the JavaScript to write in the header
+ * @param component
+ * the component which produced the callback script
+ */
+ protected void handleCallbackScript(final IHeaderResponse response,
+ final CharSequence callbackScript, final Component component)
+ {
+ response.render(OnDomReadyHeaderItem.forScript(callbackScript));
+ }
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final List<AjaxLazyLoadPanel> lazyLoadPanels = new ArrayList<>();
+
+ public AjaxLazyLoadTimer()
+ {
+ super(Duration.ONE_SECOND);
--- End diff --
Can't. The timer is a single instance for all ALLP's on a page. The reason for using just one timer is that when you have more, you get a barrage of events fired at your server and you don't want that (I've seen the horror). A single timer is the best compromise for this. I've thought about increasing the timer the longer the wait takes, but decided against it because as a user you want direct feedback. A timer of a second is a rather nice compromise between request pressure on the server and wait time for the user.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket pull request: WICKET-6055 Made AjaxLazyLoadPanel non-blocki...
Posted by martin-g <gi...@git.apache.org>.
Github user martin-g commented on a diff in the pull request:
https://github.com/apache/wicket/pull/151#discussion_r48414689
--- Diff: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java ---
@@ -139,56 +182,176 @@ protected void handleCallbackScript(final IHeaderResponse response,
@Override
protected void onBeforeRender()
{
- if (state == 0)
+ if (state == LoadingState.WAITING_FOR_LAZY_COMPONENT)
{
add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
+ setState(LoadingState.REPLACING_LAZY_COMPONENT);
}
super.onBeforeRender();
}
+ @Override
+ public void onEvent(IEvent<?> event)
+ {
+ super.onEvent(event);
+
+ if (state == LoadingState.REPLACING_LAZY_COMPONENT)
+ {
+ if (isReadyForReplacement())
+ {
+ // create the lazy load component
+ Component component = getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
+
+ // replace the spinner with the new component
+ AjaxLazyLoadPanel.this.replace(component);
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ getLazyLoadTimer().removeLazyLoadPanel(this);
+
+ AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
+
+ // notify our subclasses of the updated component
+ onComponentLoaded(component, target);
+
+ // repaint our selves if there's an AJAX request in play, otherwise let the page
+ // redraw itself
+ if (target != null)
+ {
+ target.add(AjaxLazyLoadPanel.this);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+
+ // mark replacement as done
+ setState(LoadingState.REPLACEMENT_COMPLETED);
+
+ // remove ourselves from the timer
+ AjaxLazyLoadTimer timer = getLazyLoadTimer();
+ if (timer != null)
+ {
+ timer.removeLazyLoadPanel(this);
+ }
+ }
+
/**
+ * Sets the new LoadingState for this panel.
*
- * @param state
+ * @param newState
*/
- private void setState(final byte state)
+ private void setState(final LoadingState newState)
{
- this.state = state;
+ this.state = newState;
getPage().dirty();
}
/**
+ * Gets the central lazy load timer from the page if one is registered
*
- * @param markupId
- * The components markupid.
- * @return The component that must be lazy created. You may call setRenderBodyOnly(true) on this
- * component if you need the body only.
+ * @return the central lazy load timer or {@code null}
*/
- public abstract Component getLazyLoadComponent(String markupId);
+ private AjaxLazyLoadTimer getLazyLoadTimer()
+ {
+ return getPage().getMetaData(AJAX_LAZY_LOAD_TIMER);
+ }
/**
- * Called when the placeholder component is replaced with the lazy loaded one.
- *
- * @param component
- * The lazy loaded component
- * @param target
- * The Ajax request handler
+ * Sets the central lazy load timer on the page
+ *
+ * @param timer
+ * the timer to set
*/
- protected void onComponentLoaded(Component component, AjaxRequestTarget target)
+ private void setLazyLoadTimer(AjaxLazyLoadTimer timer)
{
+ getPage().setMetaData(AJAX_LAZY_LOAD_TIMER, timer);
}
/**
- * @param markupId
- * The components markupid.
- * @return The component to show while the real component is being created.
+ * @deprecated No longer called as the AjaxLazyLoadPanel uses a central AJAX timer, and it
+ * doesn't make sense to modify the single timer from multiple panels
*/
- public Component getLoadingComponent(final String markupId)
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
- IRequestHandler handler = new ResourceReferenceRequestHandler(
- AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
}
+ /**
+ * Allows subclasses to change the callback script if needed.
+ *
+ * @param response
+ * the current response that writes to the header
+ * @param callbackScript
+ * the JavaScript to write in the header
+ * @param component
+ * the component which produced the callback script
+ */
+ protected void handleCallbackScript(final IHeaderResponse response,
+ final CharSequence callbackScript, final Component component)
+ {
+ response.render(OnDomReadyHeaderItem.forScript(callbackScript));
+ }
+
+ /**
+ * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be a page-local singleton
+ * keeping track of multiple LazyLoadPanels using reference counting.
+ */
+ private static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final List<AjaxLazyLoadPanel> lazyLoadPanels = new ArrayList<>();
+
+ public AjaxLazyLoadTimer()
+ {
+ super(Duration.ONE_SECOND);
--- End diff --
+1 to make the duration configurable, e.g. overridable method in AjaxLazyLoadPanel.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] wicket issue #151: WICKET-6055 Made AjaxLazyLoadPanel non-blocking
Posted by svenmeier <gi...@git.apache.org>.
Github user svenmeier commented on the issue:
https://github.com/apache/wicket/pull/151
I've wrapped my ideas about this topic in #240
---