refactor popup: remove jQuery, use Custom Elements

issue: TOBAGO-1633: TS refactoring
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/HackResourceExtentionFilter.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/HackResourceExtentionFilter.java
index 6656751..c6f4799 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/HackResourceExtentionFilter.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/HackResourceExtentionFilter.java
@@ -51,7 +51,7 @@
     }
     final String version = Package.getPackage("org.apache.myfaces.tobago.component").getImplementationVersion();
     final String contextPath = filterConfig.getServletContext().getContextPath();
-    prefix = contextPath + "/tobago/standard/tobago-bootstrap/" + version + "/js/tobago-";
+    prefix = contextPath + "/tobago/standard/tobago-bootstrap/" + version + "/js/";
   }
 
   @Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java
index d1736a7..4072d86 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java
@@ -24,7 +24,6 @@
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.model.CollapseMode;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
-import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlRoleValues;
@@ -49,11 +48,9 @@
     // this makes the popup NOT closable with a click to the background
     ComponentUtils.putDataAttribute(popup, "backdrop", "static");
 
-    writer.startElement(HtmlElements.DIV);
+    writer.startElement(HtmlElements.TOBAGO_POPUP);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
-        TobagoClass.POPUP,
-        TobagoClass.POPUP.createMarkup(markup),
         BootstrapClass.MODAL,
         BootstrapClass.FADE,
         popup.getCustomClass());
@@ -81,7 +78,7 @@
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
     writer.endElement(HtmlElements.DIV);
-    writer.endElement(HtmlElements.DIV);
+    writer.endElement(HtmlElements.TOBAGO_POPUP);
 
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
index f07f3e6..324cdbd 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
@@ -153,7 +153,6 @@
   PAGE__MENU_STORE("tobago-page-menuStore"),
   PAGE__NOSCRIPT("tobago-page-noscript"),
   PANEL("tobago-panel"),
-  POPUP("tobago-popup"),
   PROGRESS("tobago-progress"),
   SECTION("tobago-section"),
   SECTION__HEADER("tobago-section-header"),
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 7c05b17..8766a3d 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
@@ -135,6 +135,7 @@
 
   TOBAGO_IN("tobago-in"),
   TOBAGO_PANEL("tobago-panel"),
+  TOBAGO_POPUP("tobago-popup"),
   TOBAGO_SPLIT_LAYOUT("tobago-split-layout"),
   TOBAGO_STARS("tobago-stars"),
   TOBAGO_SUGGEST("tobago-suggest");
diff --git a/tobago-core/src/main/resources/scss/_tobago.scss b/tobago-core/src/main/resources/scss/_tobago.scss
index d517229..e4c2b75 100644
--- a/tobago-core/src/main/resources/scss/_tobago.scss
+++ b/tobago-core/src/main/resources/scss/_tobago.scss
@@ -743,9 +743,6 @@
 
 /* popup ------------------------------------------------------------- */
 
-.tobago-popup {
-}
-
 .modal-content > .card {
   margin-bottom: 0;
 }
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/script/demo.js b/tobago-example/tobago-example-demo/src/main/webapp/script/demo.js
index 6345e55..319cb48 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/script/demo.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/script/demo.js
@@ -15,9 +15,9 @@
  * limitations under the License.
  */
 
-import {Tobago} from "../tobago/standard/tobago-bootstrap/5.0.0-SNAPSHOT/js/tobago-core";
-import {Listener, Phase} from "../tobago/standard/tobago-bootstrap/5.0.0-SNAPSHOT/js/tobago-listener";
-import {Tobago4Utils} from "../tobago/standard/tobago-bootstrap/5.0.0-SNAPSHOT/js/tobago-utils";
+import {Tobago} from "../tobago/standard/tobago-bootstrap/5.0.0-SNAPSHOT/js/tobago-core";
+import {Listener, Phase} from "../tobago/standard/tobago-bootstrap/5.0.0-SNAPSHOT/js/tobago-listener";
+import {Tobago4Utils} from "../tobago/standard/tobago-bootstrap/5.0.0-SNAPSHOT/js/tobago-utils";
 
 const Demo = {};
 
diff --git a/tobago-theme/pom.xml b/tobago-theme/pom.xml
index c449698..8ee4aab 100644
--- a/tobago-theme/pom.xml
+++ b/tobago-theme/pom.xml
@@ -145,10 +145,13 @@
                     <include>css/tobago.min.css.map</include>
                     <include>js/test.js</include>
                     <include>js/test.js.map</include>
+                    <include>js/ext*.js</include>
+                    <include>js/ext*.js.map</include>
+                    <include>ts/ext*.ts</include>
                     <include>js/tobago*.js</include>
                     <include>js/tobago*.js.map</include>
-                    <include>ts/test.ts</include>
                     <include>ts/tobago*.ts</include>
+                    <include>ts/test.ts</include>
                     <!-- todo: check a better way for polyfill -->
                     <include>node_modules/@babel/polyfill/dist/polyfill.js</include>
                   </includes>
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/package.json b/tobago-theme/tobago-theme-standard/src/main/npm/package.json
index 4077fcf..39892f9 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/package.json
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/package.json
@@ -24,7 +24,7 @@
     "css-prefix": "postcss --config postcss.config.js --replace \"css/*.css\" \"!css/*.min.css\"",
     "css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output css/tobago.min.css css/tobago.css",
     "ts-compile": "tsc",
-    "js-minify": "uglifyjs --compress typeofs=false,drop_console=true --mangle --source-map includeSources --output js/tobago.min.js js/tobago-myfaces.js js/tobago-deltaspike.js js/tobago-polyfill.js js/tobago-listener.js js/tobago-core.js js/tobago-dropdown.js js/tobago-calendar.js js/tobago-command.js js/tobago-file.js js/tobago-focus.js js/tobago-header-footer.js js/tobago-in.js js/tobago-jsf.js js/tobago-overlay.js js/tobago-panel.js js/tobago-popover.js js/tobago-popup.js js/tobago-reload.js js/tobago-scroll.js js/tobago-select-boolean-checkbox.js js/tobago-select-boolean-toggle.js js/tobago-select-many-checkbox.js js/tobago-select-many-shuttle.js js/tobago-select-one-listbox.js js/tobago-select-one-radio.js js/tobago-sheet.js js/tobago-split-layout.js js/tobago-stars.js js/tobago-suggest.js js/tobago-tab.js js/tobago-tree.js js/tobago-tree-listbox.js js/tobago-utils.js",
+    "js-minify": "uglifyjs --compress typeofs=false,drop_console=true --mangle --source-map includeSources --output js/tobago.min.js js/tobago-myfaces.js js/tobago-deltaspike.js js/tobago-polyfill.js js/ext-bootstrap.js js/tobago-listener.js js/tobago-core.js js/tobago-dropdown.js js/tobago-calendar.js js/tobago-command.js js/tobago-file.js js/tobago-focus.js js/tobago-header-footer.js js/tobago-in.js js/tobago-jsf.js js/tobago-overlay.js js/tobago-panel.js js/tobago-popover.js js/tobago-popup.js js/tobago-reload.js js/tobago-scroll.js js/tobago-select-boolean-checkbox.js js/tobago-select-boolean-toggle.js js/tobago-select-many-checkbox.js js/tobago-select-many-shuttle.js js/tobago-select-one-listbox.js js/tobago-select-one-radio.js js/tobago-sheet.js js/tobago-split-layout.js js/tobago-stars.js js/tobago-suggest.js js/tobago-tab.js js/tobago-tree.js js/tobago-tree-listbox.js js/tobago-utils.js",
     "test": "jest"
   },
   "devDependencies": {
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/ext-bootstrap.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/ext-bootstrap.ts
new file mode 100644
index 0000000..ecd323c
--- /dev/null
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/ext-bootstrap.ts
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+// Utility to "not" use jQuery and Bootstrap directly in the Tobago code.
+
+export class BootstrapUtils {
+
+  static modal(element: Element, data?: any, options?: any) {
+    jQuery(element).modal(data, options);
+  }
+
+}
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts
index 6d7a304..15bbffa 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+import "./ext-bootstrap";
 import "./tobago-listener";
 import "./tobago-core";
 import "./tobago-dropdown";
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts
index 6c2381c..be593f4 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts
@@ -15,53 +15,50 @@
  * limitations under the License.
  */
 
-import {Listener, Phase} from "./tobago-listener";
-import {DomUtils, Tobago4Utils} from "./tobago-utils";
+import {BootstrapUtils} from "./ext-bootstrap";
 
-export class Popup {
+export class Popup extends HTMLElement {
 
-  /**
-   * Init popup for bootstrap
-   */
-  static init = function (elements) {
-    elements = elements.jQuery ? elements : jQuery(elements); // fixme jQuery -> ES5
-    var popups = Tobago4Utils.selectWithJQuery(elements, ".modal");
-    popups.each(function () {
-      var $popup = jQuery(this);
-      var $hidden = Collapse.findHidden($popup);
-      if ($hidden.val() == "false") {
-        // XXX hack: this is needed for popups open by AJAX.
-        // XXX currently the DOM replacement done by Tobago doesn't remove the modal-backdrop
-        jQuery(".modal-backdrop").remove();
+  static close(button: HTMLElement) {
+    BootstrapUtils.modal(button.closest(".modal"), "hide");
+  }
 
-        jQuery(this).modal("show"); // inits and opens the popup
-      } else {
-        jQuery(this).modal("hide"); // inits and hides the popup
+  constructor() {
+    super();
+  }
+
+  connectedCallback() {
+    const hidden = Collapse.findHidden(this);
+    if (hidden.value === "false") {
+      // XXX hack: this is needed for popups open by AJAX.
+      // XXX currently the DOM replacement done by Tobago doesn't remove the modal-backdrop
+      for (const backdrop of document.querySelectorAll(".modal-backdrop")) {
+        backdrop.parentNode.removeChild(backdrop);
       }
-    });
-  };
 
-  static close = function (button) {
-    jQuery(button).parents('.modal:first').modal("hide");
-
-  };
+      BootstrapUtils.modal(this, "show"); // inits and opens the popup
+    } else {
+      BootstrapUtils.modal(this, "hide"); // inits and hides the popup
+    }
+  }
 }
 
-Listener.register(Popup.init, Phase.DOCUMENT_READY);
-Listener.register(Popup.init, Phase.AFTER_UPDATE);
+document.addEventListener("DOMContentLoaded", function (event: Event) {
+  window.customElements.define("tobago-popup", Popup);
+});
 
 export class Collapse {
 
-  static findHidden = function ($element) {
-    return jQuery(DomUtils.escapeClientId($element.attr("id") + "::collapse"));
-  };
+  static findHidden(element: HTMLElement): HTMLInputElement {
+    return document.getElementById(element.id + "::collapse") as HTMLInputElement;
+  }
 
   static execute = function (collapse) {
-    var transition = collapse.transition;
-    var $for = jQuery(DomUtils.escapeClientId(collapse.forId));
-    var $hidden = Collapse.findHidden($for);
-    var isPopup = $for.hasClass("tobago-popup");
-    var newCollapsed;
+    const transition = collapse.transition;
+    const forElement = document.getElementById(collapse.forId);
+    const hidden = Collapse.findHidden(forElement);
+    const isPopup = forElement.tagName === "TOBAGO-POPUP";
+    let newCollapsed;
     switch (transition) {
       case "hide":
         newCollapsed = true;
@@ -74,17 +71,17 @@
     }
     if (newCollapsed) {
       if (isPopup) {
-        $for.modal("hide");
+        BootstrapUtils.modal(forElement, "hide");
       } else {
-        $for.addClass("tobago-collapsed");
+        forElement.classList.add("tobago-collapsed");
       }
     } else {
       if (isPopup) {
-        $for.modal("show");
+        BootstrapUtils.modal(forElement, "show");
       } else {
-        $for.removeClass("tobago-collapsed");
+        forElement.classList.remove("tobago-collapsed");
       }
     }
-    $hidden.val(newCollapsed);
+    hidden.value = newCollapsed;
   };
 }
diff --git a/tobago-theme/tobago-theme-standard/src/main/resources/META-INF/tobago-config.xml b/tobago-theme/tobago-theme-standard/src/main/resources/META-INF/tobago-config.xml
index d72a3b9..5921e4d 100644
--- a/tobago-theme/tobago-theme-standard/src/main/resources/META-INF/tobago-config.xml
+++ b/tobago-theme/tobago-theme-standard/src/main/resources/META-INF/tobago-config.xml
@@ -70,6 +70,7 @@
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-polyfill.js"/>
           <script type="module" name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-all.js"/>
 <!--
+          <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/ext-bootstrap.js"/>
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-listener.js"/>
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-core.js"/>
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-dropdown.js"/>