You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2021/04/15 12:05:26 UTC

[myfaces-tobago] branch master updated: fix: tc:reload

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

lofwyr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git


The following commit(s) were added to refs/heads/master by this push:
     new 5773a87  fix: tc:reload
5773a87 is described below

commit 5773a87222ac51c5cd576d938f16bcdf089cdb0b
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Thu Apr 15 12:44:05 2021 +0200

    fix: tc:reload
    
    * implement as custom element
    * Use TypeScript instead of JavaScript
    
    issue: TOBAGO-1633
---
 .../myfaces/tobago/component/ClientBehaviors.java  |   4 +-
 .../myfaces/tobago/component/RendererTypes.java    |   2 +
 .../tobago/internal/component/AbstractUIPanel.java |  30 ----
 .../tobago/internal/component/AbstractUISheet.java |  17 +--
 .../internal/renderkit/renderer/PanelRenderer.java |   9 +-
 .../renderkit/renderer/ReloadRenderer.java         |  78 ++++++++++
 .../internal/renderkit/renderer/SheetRenderer.java |   7 +-
 .../taglib/component/ReloadTagDeclaration.java     |   2 +
 .../tobago/renderkit/html/HtmlAttributes.java      |   1 +
 .../tobago/renderkit/html/HtmlElements.java        |   1 +
 .../050-container/20-panel/Panel.xhtml             |  22 ++-
 tobago-theme/src/main/scss/_tobago.scss            |   4 +
 .../src/main/css/tobago.css                        |   1 +
 .../src/main/css/tobago.css.map                    |   2 +-
 .../src/main/css/tobago.min.css.map                |   2 +-
 .../src/main/css/tobago.css                        |   1 +
 .../src/main/css/tobago.css.map                    |   2 +-
 .../src/main/css/tobago.min.css.map                |   2 +-
 .../src/main/css/tobago.css                        |   1 +
 .../src/main/css/tobago.css.map                    |   2 +-
 .../src/main/css/tobago.min.css.map                |   2 +-
 .../tobago-theme-speyside/src/main/css/tobago.css  |   1 +
 .../src/main/css/tobago.css.map                    |   2 +-
 .../src/main/css/tobago.min.css.map                |   2 +-
 .../tobago-theme-standard/src/main/css/tobago.css  |   1 +
 .../src/main/css/tobago.css.map                    |   2 +-
 .../src/main/css/tobago.min.css.map                |   2 +-
 .../tobago-theme-standard/src/main/js/tobago.js    | 164 +++++++++++----------
 .../src/main/js/tobago.js.map                      |   2 +-
 .../src/main/js/tobago.min.js                      |   4 +-
 .../src/main/js/tobago.min.js.map                  |   2 +-
 .../src/main/ts/tobago-page.ts                     |  42 +++---
 .../src/main/ts/tobago-reload.ts                   |  62 ++++----
 33 files changed, 272 insertions(+), 206 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
index f47ec3a..36363a5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
@@ -31,7 +31,7 @@ public enum ClientBehaviors {
   load,
   mouseover,
   mouseout,
-  reload, // tbd
+  reload, // tbd - may be called timeout?
   resize,
   suggest; // tbd
 
@@ -45,7 +45,7 @@ public enum ClientBehaviors {
   public static final String LOAD = "load";
   public static final String MOUSEOVER = "mouseover";
   public static final String MOUSEOUT = "mouseout";
-  public static final String RELOAD = "reload"; // tbd
+  public static final String RELOAD = "reload"; // tbd - may be called timeout?
   public static final String RESIZE = "resize";
   public static final String SUGGEST = "suggest"; // tbd
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
index 97a4a2a..0b9f91e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
@@ -59,6 +59,7 @@ public enum RendererTypes {
   Popup,
   Progress,
   Range,
+  Reload,
   Row,
   Script,
   Section,
@@ -129,6 +130,7 @@ public enum RendererTypes {
   public static final String PANEL = "Panel";
   public static final String POPUP = "Popup";
   public static final String PROGRESS = "Progress";
+  public static final String RELOAD = "Reload";
   public static final String RANGE = "Range";
   public static final String ROW = "Row";
   public static final String SCRIPT = "Script";
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java
index 277de4e..0d5c1f7 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java
@@ -19,40 +19,10 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
-import org.apache.myfaces.tobago.renderkit.RendererBase;
-import org.apache.myfaces.tobago.util.AjaxUtils;
-import org.apache.myfaces.tobago.util.ComponentUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import javax.faces.component.behavior.ClientBehaviorHolder;
-import javax.faces.context.FacesContext;
-import javax.faces.render.Renderer;
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
 
 /**
  * {@link org.apache.myfaces.tobago.internal.taglib.component.PanelTagDeclaration}
  */
 public abstract class AbstractUIPanel extends AbstractUICollapsiblePanel implements ClientBehaviorHolder {
-
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  @Override
-  public void encodeAll(FacesContext facesContext) throws IOException {
-
-    final AbstractUIReload reload = ComponentUtils.getReloadFacet(this);
-
-    if (reload != null && AjaxUtils.isAjaxRequest(facesContext) && reload.isRendered() && !reload.isUpdate()) {
-      // do not render content
-      final Renderer renderer = getRenderer(facesContext);
-      if (renderer instanceof RendererBase) {
-        ((RendererBase) renderer).encodeReload(facesContext, reload);
-      } else {
-        LOG.warn("Found reload facet but no renderer support for it id='{}'!", getClientId(facesContext));
-      }
-    } else {
-      super.encodeAll(facesContext);
-    }
-  }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
index c2e9720..537e704 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
@@ -37,8 +37,6 @@ import org.apache.myfaces.tobago.model.ExpandedState;
 import org.apache.myfaces.tobago.model.ScrollPosition;
 import org.apache.myfaces.tobago.model.SelectedState;
 import org.apache.myfaces.tobago.model.SheetState;
-import org.apache.myfaces.tobago.renderkit.RendererBase;
-import org.apache.myfaces.tobago.util.AjaxUtils;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -58,7 +56,6 @@ import javax.faces.event.FacesEvent;
 import javax.faces.event.ListenerFor;
 import javax.faces.event.PhaseId;
 import javax.faces.event.PreRenderComponentEvent;
-import javax.faces.render.Renderer;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
@@ -109,19 +106,7 @@ public abstract class AbstractUISheet extends AbstractUIData
       }
     }
 
-    final AbstractUIReload reload = ComponentUtils.getReloadFacet(this);
-
-    if (reload != null && AjaxUtils.isAjaxRequest(facesContext) && reload.isRendered() && !reload.isUpdate()) {
-      // do not render content
-      final Renderer renderer = getRenderer(facesContext);
-      if (renderer instanceof RendererBase) {
-        ((RendererBase) renderer).encodeReload(facesContext, reload);
-      } else {
-        LOG.warn("Found reload facet but no renderer support for it id='{}'!", getClientId(facesContext));
-      }
-    } else {
-      super.encodeAll(facesContext);
-    }
+    super.encodeAll(facesContext);
   }
 
   @Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java
index 646c4da..14fb911 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java
@@ -25,7 +25,6 @@ import org.apache.myfaces.tobago.internal.component.AbstractUIReload;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.model.CollapseMode;
 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
-import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
@@ -60,15 +59,15 @@ public class PanelRenderer<T extends AbstractUIPanel> extends CollapsiblePanelRe
       writer.writeAttribute(HtmlAttributes.TITLE, tip, true);
     }
 
-    if (reload != null && reload.isRendered()) {
-      writer.writeAttribute(DataAttributes.RELOAD, reload.getFrequency());
-    }
-
     if (component.getCollapsedMode() != CollapseMode.none) {
       encodeHidden(writer, clientId, collapsed);
     }
 
     encodeBehavior(writer, facesContext, component);
+
+    if (reload != null) {
+      reload.encodeAll(facesContext);
+    }
   }
 
   @Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ReloadRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ReloadRenderer.java
new file mode 100644
index 0000000..9678f3a
--- /dev/null
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ReloadRenderer.java
@@ -0,0 +1,78 @@
+/*
+ * 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.myfaces.tobago.internal.renderkit.renderer;
+
+import org.apache.myfaces.tobago.internal.component.AbstractUIReload;
+import org.apache.myfaces.tobago.renderkit.RendererBase;
+import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
+import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
+import org.apache.myfaces.tobago.util.AjaxUtils;
+import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.PartialViewContext;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+
+public class ReloadRenderer<T extends AbstractUIReload> extends RendererBase<T> {
+
+  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  @Override
+  public void decodeInternal(final FacesContext facesContext, final T component) {
+
+    final String sourceId = facesContext.getExternalContext().getRequestParameterMap().get("javax.faces.source");
+    final String clientId = component.getClientId(facesContext);
+    if (clientId.equals(sourceId)) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("matching = '{}'", clientId);
+      }
+      if (AjaxUtils.isAjaxRequest(facesContext) && component.isRendered() && !component.isUpdate()) {
+        // do not render content, only render the reload tag for the next request
+        final PartialViewContext partialViewContext = facesContext.getPartialViewContext();
+        final String parentId = component.getParent().getClientId(facesContext);
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("removing '{}' from lists renderIds and executeIds", clientId);
+        }
+        partialViewContext.getRenderIds().remove(parentId);
+        partialViewContext.getExecuteIds().remove(parentId);
+      }
+    }
+  }
+
+  @Override
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
+
+    final TobagoResponseWriter writer = getResponseWriter(facesContext);
+
+    writer.startElement(HtmlElements.TOBAGO_RELOAD);
+    writer.writeIdAttribute(component.getClientId(facesContext));
+    writer.writeAttribute(HtmlAttributes.FREQUENCY, component.getFrequency());
+  }
+
+  @Override
+  public void encodeEndInternal(FacesContext facesContext, T component) throws IOException {
+    final TobagoResponseWriter writer = getResponseWriter(facesContext);
+    writer.endElement(HtmlElements.TOBAGO_RELOAD);
+  }
+
+}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
index a86a023..30d9c62 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
@@ -272,9 +272,6 @@ public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
         component.getCustomClass(),
         TobagoClass.SHEET.createMarkup(markup),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
-    if (reload != null && reload.isRendered()) {
-      writer.writeAttribute(DataAttributes.RELOAD, reload.getFrequency());
-    }
     writer.writeAttribute(DataAttributes.SELECTION_MODE, component.getSelectable().name(), false);
     writer.writeAttribute(DataAttributes.FIRST, Integer.toString(component.getFirst()), false);
     writer.writeAttribute(CustomAttributes.ROWS, component.getRows());
@@ -288,6 +285,10 @@ public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
     }
 
     encodeBehavior(writer, facesContext, component);
+
+    if (reload != null) {
+      reload.encodeAll(facesContext);
+    }
   }
 
   @Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ReloadTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ReloadTagDeclaration.java
index 7d4ef85..0e3230a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ReloadTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ReloadTagDeclaration.java
@@ -24,6 +24,7 @@ import org.apache.myfaces.tobago.apt.annotation.Tag;
 import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
 import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
 import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
+import org.apache.myfaces.tobago.component.RendererTypes;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasIdBindingAndRendered;
 
 /**
@@ -39,6 +40,7 @@ import org.apache.myfaces.tobago.internal.taglib.declaration.HasIdBindingAndRend
 @UIComponentTag(
     uiComponent = "org.apache.myfaces.tobago.component.UIReload",
     componentFamily = "org.apache.myfaces.tobago.Reload",
+    rendererType = RendererTypes.RELOAD,
     allowedChildComponenents = "NONE")
 public interface ReloadTagDeclaration extends HasIdBindingAndRendered {
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java
index 2391397..cce9276 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java
@@ -45,6 +45,7 @@ public enum HtmlAttributes implements MarkupLanguageAttributes {
   ENCTYPE("enctype"),
   FOR("for"),
   FRAMEBORDER("frameborder"),
+  FREQUENCY("frequency"),
   HEIGHT("height"),
   HREF("href"),
   HREFLANG("hreflang"),
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java
index 7e516b1..b5b9ecc 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java
@@ -161,6 +161,7 @@ public enum HtmlElements {
   TOBAGO_POPUP("tobago-popup"),
   TOBAGO_PROGRESS("tobago-progress"),
   TOBAGO_RANGE("tobago-range"),
+  TOBAGO_RELOAD("tobago-reload"),
   TOBAGO_SECTION("tobago-section"),
   TOBAGO_SEGMENT_LAYOUT("tobago-segment-layout"),
   TOBAGO_SELECT_BOOLEAN_CHECKBOX("tobago-select-boolean-checkbox"),
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/050-container/20-panel/Panel.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/050-container/20-panel/Panel.xhtml
index 33f9ece..8efa150 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/050-container/20-panel/Panel.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/050-container/20-panel/Panel.xhtml
@@ -42,12 +42,14 @@
   </tc:section>
 
   <tc:section label="Reload">
+    <tc:link label="Tag Library Documentation" image="#{request.contextPath}/image/feather-leaf.png"
+             link="#{apiController.tldBase}/#{apiController.currentRelease}/tld/tc/reload.html"/>
     <p>To reload the panel in a dedicated frequency, you can use the
       <code class="language-markup">&lt;f:facet name="reload"></code> tag.
       The content of the panel is an output text, which display the current time.</p>
     <demo-highlight language="markup">&lt;tc:panel>
   &lt;f:facet name="reload">
-    &lt;tc:reload frequency="1000" update="true"/>
+    &lt;tc:reload frequency="1000"/>
       ...</demo-highlight>
     <tc:panel>
       <f:facet name="reload">
@@ -60,21 +62,29 @@
   </tc:section>
 
   <tc:section label="Reload with update control">
-    <p>To reload the panel in a dedicated frequency, you can use the
-      <code class="language-markup">&lt;f:facet name="reload"></code> tag.
-      The content of the panel is an output text, which display the current time.</p>
+    <p>With the <code class="language-markup">update</code> attribute
+      the rendering of the panel can be dropped, if there is no need to
+      update the content.
+      In this example, we only display the current time, if the seconds
+      are between 10 - 19, 30 - 39 or 50 - 59.</p>
     <demo-highlight language="markup">&lt;tc:panel>
   &lt;f:facet name="reload">
     &lt;tc:reload frequency="1000" update="\#{panelController.oddDecaSecond}"/>
       ...</demo-highlight>
-    <tc:panel>
+    <tc:panel id="panel-reload-update">
       <f:facet name="reload">
-        <tc:reload frequency="1000" update="#{panelController.oddDecaSecond}"/>
+        <tc:reload id="reload-update" frequency="1000" update="#{panelController.oddDecaSecond}"/>
       </f:facet>
       <tc:out id="r" label="Current Date" value="#{panelController.currentDate}">
         <f:convertDateTime pattern="HH:mm:ss"/>
       </tc:out>
     </tc:panel>
+
+    This
+    <tc:link label="explicit reload link">
+      <f:ajax execute="panel-reload-update" render="panel-reload-update"/>
+    </tc:link>
+    reloads the panel directly (only for testing purpuse here).
   </tc:section>
 
   <tc:section label="Ajax">
diff --git a/tobago-theme/src/main/scss/_tobago.scss b/tobago-theme/src/main/scss/_tobago.scss
index 343a677..28f62cc 100644
--- a/tobago-theme/src/main/scss/_tobago.scss
+++ b/tobago-theme/src/main/scss/_tobago.scss
@@ -883,6 +883,10 @@ label.tobago-required:after {
   color: $danger;
 }
 
+/* reload ---------------------------------------------------------- */
+tobago-reload {
+}
+
 /* section ----------------------------------------------------------- */
 tobago-section {
   display: block;
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css
index 3f007dc..a6a756b 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css
@@ -11679,6 +11679,7 @@ label.tobago-required:after {
   color: #ff00be;
 }
 
+/* reload ---------------------------------------------------------- */
 /* section ----------------------------------------------------------- */
 tobago-section {
   display: block;
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map
index bd0d0f2..0b84cc1 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map
index 2171898..23beab1 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-charlotteville/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,QACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,SAAS,CAAE,aAAa,CAAE,UAAU,CAAE,MAAM,CAAE,gBAAgB,CAAE,KAAK,CAAE,WAAW,CAAE,iBAAiB,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBACnM,oBAAqB,cAAc,CAAE,KAA [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-charlotteville/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,QACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,SAAS,CAAE,aAAa,CAAE,UAAU,CAAE,MAAM,CAAE,gBAAgB,CAAE,KAAK,CAAE,WAAW,CAAE,iBAAiB,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBACnM,oBAAqB,cAAc,CAAE,KAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css
index 0fd4f77..a3f2a70 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css
@@ -11702,6 +11702,7 @@ label.tobago-required:after {
   color: #ffb243;
 }
 
+/* reload ---------------------------------------------------------- */
 /* section ----------------------------------------------------------- */
 tobago-section {
   display: block;
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map
index 0b62ba0..a290d07 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map
index 2eec3f3..24f42ae 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-roxborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAiCA,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,qCAAqC,mBAE5C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,kCAAkC,mBAEzC,WACE,YAAa,SACb,WAAY,OACZ,IAAK,oCAAoC,mBAE3C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,wCAAwC,mBAEvB,mBAAxB,uBACE,YAAa,QAAQ,CAAE,KAAK,CAAE,MAShC,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB, [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-roxborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAiCA,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,qCAAqC,mBAE5C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,kCAAkC,mBAEzC,WACE,YAAa,SACb,WAAY,OACZ,IAAK,oCAAoC,mBAE3C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,wCAAwC,mBAEvB,mBAAxB,uBACE,YAAa,QAAQ,CAAE,KAAK,CAAE,MAShC,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css
index a4f17c6..135127e 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css
@@ -11689,6 +11689,7 @@ label.tobago-required:after {
   color: #dc3545;
 }
 
+/* reload ---------------------------------------------------------- */
 /* section ----------------------------------------------------------- */
 tobago-section {
   display: block;
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map
index 5362131..dd906f7 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map
index dfc7390..8c9bd48 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-scarborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,SAAS,CAAE,aAAa,CAAE,UAAU,CAAE,MAAM,CAAE,gBAAgB,CAAE,KAAK,CAAE,WAAW,CAAE,iBAAiB,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBACnM,oBAAqB,cAAc,CAAE,KAAK,C [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-scarborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,SAAS,CAAE,aAAa,CAAE,UAAU,CAAE,MAAM,CAAE,gBAAgB,CAAE,KAAK,CAAE,WAAW,CAAE,iBAAiB,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBACnM,oBAAqB,cAAc,CAAE,KAAK,C [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css
index 76816e4..74909a7 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css
@@ -11391,6 +11391,7 @@ label.tobago-required:after {
   color: #d30040;
 }
 
+/* reload ---------------------------------------------------------- */
 /* section ----------------------------------------------------------- */
 tobago-section {
   display: block;
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map
index f707cca..374293a 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_modules/bootstrap/scss/mixins/_lists.scss","../. [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_modules/bootstrap/scss/mixins/_lists.scss","../. [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map
index 4080e24..4baf454 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-speyside/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,KACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,OAAO,CAAE,WAC/B,oBAAqB,cAAc,CAAE,KAAK,CAAE,MAAM,CAAE,QAAQ,CAAE,iBAAiB,CAAE,aAAa,CAAE,UAChG,cAAe,2EAGjB,EAEA,QADA,SAEE,WAAY,WAGd,MACE,UAAW,KAEb,8CACE,MACE,gBAAiB,QA [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-speyside/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,KACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,OAAO,CAAE,WAC/B,oBAAqB,cAAc,CAAE,KAAK,CAAE,MAAM,CAAE,QAAQ,CAAE,iBAAiB,CAAE,aAAa,CAAE,UAChG,cAAe,2EAGjB,EAEA,QADA,SAEE,WAAY,WAGd,MACE,UAAW,KAEb,8CACE,MACE,gBAAiB,QA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css
index f3c6c68..41c727c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css
@@ -11659,6 +11659,7 @@ label.tobago-required:after {
   color: #dc3545;
 }
 
+/* reload ---------------------------------------------------------- */
 /* section ----------------------------------------------------------- */
 tobago-section {
   display: block;
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map
index ad12093..e31b409 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map
index 37ae43f..5a6101b 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-standard/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,SAAS,CAAE,aAAa,CAAE,UAAU,CAAE,MAAM,CAAE,gBAAgB,CAAE,KAAK,CAAE,WAAW,CAAE,iBAAiB,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBACnM,oBAAqB,cAAc,CAAE,KAAK,CAAE [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-standard/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,qBAAsB,SAAS,CAAE,aAAa,CAAE,UAAU,CAAE,MAAM,CAAE,gBAAgB,CAAE,KAAK,CAAE,WAAW,CAAE,iBAAiB,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBACnM,oBAAqB,cAAc,CAAE,KAAK,CAAE [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
index a425f74..082edd7 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
@@ -10104,59 +10104,6 @@
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
-  // TODO: might be implemented with a web component
-  class ReloadManager {
-      constructor() {
-          this.timeouts = new Map();
-      }
-      schedule(id, reloadMillis) {
-          if (reloadMillis > 0) {
-              // may remove old schedule
-              const oldTimeout = this.timeouts.get(id);
-              if (oldTimeout) {
-                  console.debug("clear reload timeout '" + oldTimeout + "' for #'" + id + "'");
-                  window.clearTimeout(oldTimeout);
-                  this.timeouts.delete(id);
-              }
-              // add new schedule
-              const timeout = window.setTimeout(function () {
-                  console.debug("reloading #'" + id + "'");
-                  jsf.ajax.request(id, null, {
-                      "javax.faces.behavior.event": "reload",
-                      execute: id,
-                      render: id
-                  });
-              }, reloadMillis);
-              console.debug("adding reload timeout '" + timeout + "' for #'" + id + "'");
-              this.timeouts.set(id, timeout);
-          }
-      }
-  }
-  ReloadManager.instance = new ReloadManager();
-  ReloadManager.init = function (element) {
-      for (const reload of DomUtils.selfOrQuerySelectorAll(element, "[data-tobago-reload]")) {
-          ReloadManager.instance.schedule(reload.id, Number(reload.dataset.tobagoReload));
-      }
-  };
-  Listener.register(ReloadManager.init, Phase.DOCUMENT_READY);
-  Listener.register(ReloadManager.init, Phase.AFTER_UPDATE);
-
-  /*
-   * 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.
-   */
   class Page extends HTMLElement {
       constructor() {
           super();
@@ -10277,36 +10224,28 @@
           }
       }
       jsfResponseSuccess(update) {
-          const result = /<!\[CDATA\[(.*)]]>/gm.exec(update.innerHTML);
           const id = update.id;
-          if (result !== null && result.length === 2 && result[1].startsWith("{\"reload\"")) {
-              // not modified on server, needs be reloaded after some time
-              console.debug("[tobago-jsf] Found reload-JSON in response!");
-              ReloadManager.instance.schedule(id, JSON.parse(result[1]).reload.frequency);
+          let rootNode = this.getRootNode();
+          // XXX in case of "this" is tobago-page (e.g. ajax exception handling) rootNode is not set correctly???
+          if (!rootNode.getElementById) {
+              rootNode = document;
           }
-          else {
-              let rootNode = this.getRootNode();
-              // XXX in case of "this" is tobago-page (e.g. ajax exception handling) rootNode is not set correctly???
-              if (!rootNode.getElementById) {
-                  rootNode = document;
-              }
-              console.info("[tobago-jsf] Update after jsf.ajax success: %s", id);
-              if (JsfParameter.isJsfId(id)) {
-                  console.debug("[tobago-jsf] updating #%s", id);
-                  const element = rootNode.getElementById(id);
-                  if (element) {
-                      Listener.executeAfterUpdate(element);
-                  }
-                  else {
-                      console.warn("[tobago-jsf] element not found for #%s", id);
-                  }
+          console.info("[tobago-jsf] Update after jsf.ajax success: %s", id);
+          if (JsfParameter.isJsfId(id)) {
+              console.debug("[tobago-jsf] updating #%s", id);
+              const element = rootNode.getElementById(id);
+              if (element) {
+                  Listener.executeAfterUpdate(element);
               }
-              else if (JsfParameter.isJsfBody(id)) {
-                  console.debug("[tobago-jsf] updating body");
-                  // there should be only one element with this tag name
-                  Listener.executeAfterUpdate(rootNode.querySelector("tobago-page"));
+              else {
+                  console.warn("[tobago-jsf] element not found for #%s", id);
               }
           }
+          else if (JsfParameter.isJsfBody(id)) {
+              console.debug("[tobago-jsf] updating body");
+              // there should be only one element with this tag name
+              Listener.executeAfterUpdate(rootNode.querySelector("tobago-page"));
+          }
       }
       jsfResponseComplete(update) {
           const id = update.id;
@@ -11702,6 +11641,75 @@
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
+  class TobagoReload extends HTMLElement {
+      constructor() {
+          super();
+      }
+      connectedCallback() {
+          this.schedule(this.id, this.component.id, this.frequency);
+      }
+      schedule(reloadId, componentId, reloadMillis) {
+          if (reloadMillis > 0) {
+              // may remove old schedule
+              const oldTimeout = TobagoReload.timeoutMap.get(componentId);
+              if (oldTimeout) {
+                  console.debug("clear reload timeout '" + oldTimeout + "' for #'" + componentId + "'");
+                  window.clearTimeout(oldTimeout);
+                  TobagoReload.timeoutMap.delete(componentId);
+              }
+              // add new schedule
+              const timeout = window.setTimeout(function () {
+                  console.debug("reloading #'" + componentId + "'");
+                  jsf.ajax.request(reloadId, null, {
+                      "javax.faces.behavior.event": "reload",
+                      execute: reloadId + " " + componentId,
+                      render: reloadId + " " + componentId
+                  });
+              }, reloadMillis);
+              console.debug("adding reload timeout '" + timeout + "' for #'" + componentId + "'");
+              TobagoReload.timeoutMap.set(componentId, timeout);
+          }
+      }
+      get component() {
+          return this.parentElement;
+      }
+      /** frequency is the number of millis for the timeout */
+      get frequency() {
+          const frequency = this.getAttribute("frequency");
+          if (frequency) {
+              return Number.parseFloat(frequency);
+          }
+          else {
+              return 0;
+          }
+      }
+  }
+  /**
+   * Map to store the scheduled timeouts by id, to prevent duplicate scheduling of the same elements.
+   */
+  TobagoReload.timeoutMap = new Map();
+  document.addEventListener("tobago.init", function (event) {
+      if (window.customElements.get("tobago-reload") == null) {
+          window.customElements.define("tobago-reload", TobagoReload);
+      }
+  });
+
+  /*
+   * 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.
+   */
   class Scroll {
   }
   Scroll.initScrollPosition = function (element) {
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
index 2e6a7d7..f4cbe0c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago.js","sources":["../ts/tobago-listener.ts","../ts/tobago-utils.ts","../ts/tobago-bar.ts","../ts/tobago-dropdown.ts","../../../../node_modules/vanillajs-datepicker/js/lib/utils.js","../../../../node_modules/vanillajs-datepicker/js/lib/date.js","../../../../node_modules/vanillajs-datepicker/js/lib/date-format.js","../../../../node_modules/vanillajs-datepicker/js/lib/event.js","../../../../node_modules/vanillajs-datepicker/js/i18n/base-locales.js","../../../../nod [...]
\ No newline at end of file
+{"version":3,"file":"tobago.js","sources":["../ts/tobago-listener.ts","../ts/tobago-utils.ts","../ts/tobago-bar.ts","../ts/tobago-dropdown.ts","../../../../node_modules/vanillajs-datepicker/js/lib/utils.js","../../../../node_modules/vanillajs-datepicker/js/lib/date.js","../../../../node_modules/vanillajs-datepicker/js/lib/date-format.js","../../../../node_modules/vanillajs-datepicker/js/lib/event.js","../../../../node_modules/vanillajs-datepicker/js/i18n/base-locales.js","../../../../nod [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js
index a788bc1..319fcc5 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js
@@ -1,8 +1,8 @@
-!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e,t;!function(e){e[e.DOCUMENT_READY=0]="DOCUMENT_READY",e[e.WINDOW_LOAD=1]="WINDOW_LOAD",e[e.BEFORE_SUBMIT=2]="BEFORE_SUBMIT",e[e.AFTER_UPDATE=3]="AFTER_UPDATE",e[e.BEFORE_UNLOAD=4]="BEFORE_UNLOAD",e[e.BEFORE_EXIT=5]="BEFORE_EXIT"}(e||(e={})),function(e){e[e.EARLIER=0]="EARLIER",e[e.EARLY=1]="EARLY",e[e.NORMAL=2]="NORMAL",e[e.LATE=3]="LATE",e[e.LATER=4]="LATER"}(t||(t={}));class s{constructor() [...]
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e,t;!function(e){e[e.DOCUMENT_READY=0]="DOCUMENT_READY",e[e.WINDOW_LOAD=1]="WINDOW_LOAD",e[e.BEFORE_SUBMIT=2]="BEFORE_SUBMIT",e[e.AFTER_UPDATE=3]="AFTER_UPDATE",e[e.BEFORE_UNLOAD=4]="BEFORE_UNLOAD",e[e.BEFORE_EXIT=5]="BEFORE_EXIT"}(e||(e={})),function(e){e[e.EARLIER=0]="EARLIER",e[e.EARLY=1]="EARLY",e[e.NORMAL=2]="NORMAL",e[e.LATE=3]="LATE",e[e.LATER=4]="LATER"}(t||(t={}));class s{constructor() [...]
 /*!
     * Bootstrap v5.0.0-beta3 (https://getbootstrap.com/)
     * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
     */
-const Es="transitionend",Ls=e=>{do{e+=Math.floor(1e6*Math.random())}while(document.getElementById(e));return e},Ss=e=>{let t=e.getAttribute("data-bs-target");if(!t||"#"===t){let s=e.getAttribute("href");if(!s||!s.includes("#")&&!s.startsWith("."))return null;s.includes("#")&&!s.startsWith("#")&&(s="#"+s.split("#")[1]),t=s&&"#"!==s?s.trim():null}return t},xs=e=>{const t=Ss(e);return t&&document.querySelector(t)?t:null},ks=e=>{const t=Ss(e);return t?document.querySelector(t):null},As=e=>{i [...]
+const Es="transitionend",Ls=e=>{do{e+=Math.floor(1e6*Math.random())}while(document.getElementById(e));return e},Ss=e=>{let t=e.getAttribute("data-bs-target");if(!t||"#"===t){let s=e.getAttribute("href");if(!s||!s.includes("#")&&!s.startsWith("."))return null;s.includes("#")&&!s.startsWith("#")&&(s="#"+s.split("#")[1]),t=s&&"#"!==s?s.trim():null}return t},xs=e=>{const t=Ss(e);return t&&document.querySelector(t)?t:null},ks=e=>{const t=Ss(e);return t?document.querySelector(t):null},As=e=>{i [...]
 //# sourceMappingURL=tobago.min.js.map
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map
index e387735..badc0aa 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago.min.js","sources":["../ts/tobago-listener.ts","../ts/tobago-utils.ts","../ts/tobago-bar.ts","../ts/tobago-dropdown.ts","../../../../node_modules/vanillajs-datepicker/js/lib/utils.js","../../../../node_modules/vanillajs-datepicker/js/lib/date.js","../../../../node_modules/vanillajs-datepicker/js/lib/date-format.js","../../../../node_modules/vanillajs-datepicker/js/lib/event.js","../../../../node_modules/vanillajs-datepicker/js/i18n/base-locales.js","../../../.. [...]
\ No newline at end of file
+{"version":3,"file":"tobago.min.js","sources":["../ts/tobago-listener.ts","../ts/tobago-utils.ts","../ts/tobago-bar.ts","../ts/tobago-dropdown.ts","../../../../node_modules/vanillajs-datepicker/js/lib/utils.js","../../../../node_modules/vanillajs-datepicker/js/lib/date.js","../../../../node_modules/vanillajs-datepicker/js/lib/date-format.js","../../../../node_modules/vanillajs-datepicker/js/lib/event.js","../../../../node_modules/vanillajs-datepicker/js/i18n/base-locales.js","../../../.. [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-page.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-page.ts
index ad2f41a..91c249a 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-page.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-page.ts
@@ -18,7 +18,6 @@
 import {CommandHelper} from "./tobago-command";
 import {Overlay} from "./tobago-overlay";
 import {Listener} from "./tobago-listener";
-import {ReloadManager} from "./tobago-reload";
 
 export class Page extends HTMLElement {
 
@@ -155,32 +154,25 @@ export class Page extends HTMLElement {
   }
 
   jsfResponseSuccess(update: Element): void {
-    const result = /<!\[CDATA\[(.*)]]>/gm.exec(update.innerHTML);
     const id = update.id;
-    if (result !== null && result.length === 2 && result[1].startsWith("{\"reload\"")) {
-      // not modified on server, needs be reloaded after some time
-      console.debug("[tobago-jsf] Found reload-JSON in response!");
-      ReloadManager.instance.schedule(id, JSON.parse(result[1]).reload.frequency);
-    } else {
-      let rootNode = this.getRootNode() as ShadowRoot | Document;
-      // XXX in case of "this" is tobago-page (e.g. ajax exception handling) rootNode is not set correctly???
-      if (! rootNode.getElementById) {
-        rootNode = document;
-      }
-      console.info("[tobago-jsf] Update after jsf.ajax success: %s", id);
-      if (JsfParameter.isJsfId(id)) {
-        console.debug("[tobago-jsf] updating #%s", id);
-        const element = rootNode.getElementById(id);
-        if (element) {
-          Listener.executeAfterUpdate(element);
-        } else {
-          console.warn("[tobago-jsf] element not found for #%s", id);
-        }
-      } else if (JsfParameter.isJsfBody(id)) {
-        console.debug("[tobago-jsf] updating body");
-        // there should be only one element with this tag name
-        Listener.executeAfterUpdate(rootNode.querySelector("tobago-page") as HTMLElement);
+    let rootNode = this.getRootNode() as ShadowRoot | Document;
+    // XXX in case of "this" is tobago-page (e.g. ajax exception handling) rootNode is not set correctly???
+    if (!rootNode.getElementById) {
+      rootNode = document;
+    }
+    console.info("[tobago-jsf] Update after jsf.ajax success: %s", id);
+    if (JsfParameter.isJsfId(id)) {
+      console.debug("[tobago-jsf] updating #%s", id);
+      const element = rootNode.getElementById(id);
+      if (element) {
+        Listener.executeAfterUpdate(element);
+      } else {
+        console.warn("[tobago-jsf] element not found for #%s", id);
       }
+    } else if (JsfParameter.isJsfBody(id)) {
+      console.debug("[tobago-jsf] updating body");
+      // there should be only one element with this tag name
+      Listener.executeAfterUpdate(rootNode.querySelector("tobago-page") as HTMLElement);
     }
   }
 
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-reload.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-reload.ts
index 9d75766..ba024f4 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-reload.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-reload.ts
@@ -15,58 +15,66 @@
  * limitations under the License.
  */
 
-import {Listener, Phase} from "./tobago-listener";
-import {DomUtils} from "./tobago-utils";
-
-// TODO: might be implemented with a web component
-export class ReloadManager {
-
-  static instance: ReloadManager = new ReloadManager();
+class TobagoReload extends HTMLElement {
 
   /**
    * Map to store the scheduled timeouts by id, to prevent duplicate scheduling of the same elements.
    */
-  private timeouts: Map<string, number>;
+  private static timeoutMap: Map<string, number> = new Map<string, number>();
 
-  static init = function (element: HTMLElement): void {
-    for (const reload of DomUtils.selfOrQuerySelectorAll(element, "[data-tobago-reload]")) {
-      ReloadManager.instance.schedule(reload.id, Number(reload.dataset.tobagoReload));
-    }
-  };
+  constructor() {
+    super();
+  }
 
-  private constructor() {
-    this.timeouts = new Map<string, number>();
+  connectedCallback(): void {
+    this.schedule(this.id, this.component.id, this.frequency);
   }
 
-  public schedule(id: string, reloadMillis: number): void {
+  public schedule(reloadId: string, componentId: string, reloadMillis: number): void {
     if (reloadMillis > 0) {
 
       // may remove old schedule
-      const oldTimeout = this.timeouts.get(id);
+      const oldTimeout = TobagoReload.timeoutMap.get(componentId);
       if (oldTimeout) {
-        console.debug("clear reload timeout '" + oldTimeout + "' for #'" + id + "'");
+        console.debug("clear reload timeout '" + oldTimeout + "' for #'" + componentId + "'");
         window.clearTimeout(oldTimeout);
-        this.timeouts.delete(id);
+        TobagoReload.timeoutMap.delete(componentId);
       }
 
       // add new schedule
       const timeout = window.setTimeout(function (): void {
-        console.debug("reloading #'" + id + "'");
+        console.debug("reloading #'" + componentId + "'");
         jsf.ajax.request(
-            id,
+            reloadId,
             null,
             {
               "javax.faces.behavior.event": "reload",
-              execute: id,
-              render: id
+              execute: reloadId + " " + componentId,
+              render: reloadId + " " + componentId
             });
       }, reloadMillis);
-      console.debug("adding reload timeout '" + timeout + "' for #'" + id + "'");
-      this.timeouts.set(id, timeout);
+      console.debug("adding reload timeout '" + timeout + "' for #'" + componentId + "'");
+      TobagoReload.timeoutMap.set(componentId, timeout);
     }
   }
 
+  get component(): HTMLElement {
+    return this.parentElement;
+  }
+
+  /** frequency is the number of millis for the timeout */
+  get frequency(): number {
+    const frequency = this.getAttribute("frequency");
+    if (frequency) {
+      return Number.parseFloat(frequency);
+    } else {
+      return 0;
+    }
+  }
 }
 
-Listener.register(ReloadManager.init, Phase.DOCUMENT_READY);
-Listener.register(ReloadManager.init, Phase.AFTER_UPDATE);
+document.addEventListener("tobago.init", function (event: Event): void {
+  if (window.customElements.get("tobago-reload") == null) {
+    window.customElements.define("tobago-reload", TobagoReload);
+  }
+});