myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lof...@apache.org
Subject [myfaces-tobago] branch master updated: new custom element <tobago-date>
Date Wed, 02 Oct 2019 10:30:00 GMT
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 ae31318  new custom element <tobago-date>
ae31318 is described below

commit ae31318be104a54eb4b668824e5999fcae0bff08
Author: Udo Schnurpfeil <udo.schnurpfeil@irian.eu>
AuthorDate: Wed Oct 2 12:29:29 2019 +0200

    new custom element <tobago-date>
    
    issue: TOBAGO-1633: TS refactoring
---
 .../internal/renderkit/renderer/DateRenderer.java  |   6 +-
 .../internal/renderkit/renderer/InRenderer.java    |   5 +-
 .../tobago/renderkit/html/HtmlElements.java        |   1 +
 tobago-core/src/main/resources/scss/_tobago.scss   |   7 +
 .../src/main/npm/package.json                      |   2 +-
 .../src/main/npm/ts/tobago-all.ts                  |   2 +-
 .../src/main/npm/ts/tobago-calendar.ts             | 376 ---------------------
 .../src/main/npm/ts/tobago-date.ts                 | 372 ++++++++++++++++++++
 .../src/main/resources/META-INF/tobago-config.xml  |   2 +-
 9 files changed, 391 insertions(+), 382 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
index 8df1ca2..11c0c3a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
@@ -47,6 +47,10 @@ public class DateRenderer extends InRenderer {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+  public HtmlElements getComponentTag() {
+    return HtmlElements.TOBAGO_DATE;
+  }
+
   @Override
   protected void writeAdditionalAttributes(
       final FacesContext facesContext, final TobagoResponseWriter writer, final AbstractUIInput
input)
@@ -128,6 +132,6 @@ public class DateRenderer extends InRenderer {
 
   @Override
   protected TobagoClass getRendererCssClass() {
-    return TobagoClass.DATE;
+    return null;
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
index ab26bbc..2b626fe 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
@@ -137,9 +137,10 @@ public class InRenderer extends MessageLayoutRendererBase {
       writer.writeAttribute(HtmlAttributes.PLACEHOLDER, input.getPlaceholder(), true);
     }
 
+    final TobagoClass rendererCssClass = getRendererCssClass();
     writer.writeClassAttribute(
-        getRendererCssClass(),
-        getRendererCssClass().createMarkup(markup),
+        rendererCssClass,
+        rendererCssClass != null ? rendererCssClass.createMarkup(markup) : null,
         BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(input)),
         BootstrapClass.FORM_CONTROL,
         input.getCustomClass());
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 f12e99f..b5fd301 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
@@ -134,6 +134,7 @@ public enum HtmlElements {
   WBR("wbr", Qualifier.VOID),
 
   TOBAGO_BEHAVIOR("tobago-behavior"),
+  TOBAGO_DATE("tobago-date"),
   TOBAGO_FILE("tobago-file"),
   TOBAGO_LABEL("tobago-label"),
   TOBAGO_IN("tobago-in"),
diff --git a/tobago-core/src/main/resources/scss/_tobago.scss b/tobago-core/src/main/resources/scss/_tobago.scss
index 5d1934f..77ff64f 100644
--- a/tobago-core/src/main/resources/scss/_tobago.scss
+++ b/tobago-core/src/main/resources/scss/_tobago.scss
@@ -210,7 +210,11 @@ tobago-panel.tobago-collapsed {
 
 /* date -------------------------------------------------------------- */
 
+// XXX remove me
 .tobago-date {
+}
+
+tobago-date input {
   min-width: 7em;
 
   &::-ms-clear {
@@ -1580,6 +1584,9 @@ tobago-tree {
 }
 
 /* facesMessages messageLayout focus shadows ------------------------ */
+
+// todo: check class vs. custom element
+
 .tobago-date,
 .tobago-in,
 .tobago-selectManyListbox,
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 756a9e8..418dc33 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/package.json
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/package.json
@@ -26,7 +26,7 @@
     "ts": "npm-run-all --parallel ts-lint ts-compile",
     "ts-lint": "tslint --project tsconfig.json --config tslint.json",
     "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/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 [...]
+    "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-date.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-pop
[...]
     "test": "jest"
   },
   "devDependencies": {
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 d62c216..01a7569 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
@@ -19,7 +19,7 @@ import "./ext-bootstrap";
 import "./tobago-listener";
 import "./tobago-core";
 import "./tobago-dropdown";
-import "./tobago-calendar";
+import "./tobago-date";
 import "./tobago-command";
 import "./tobago-file";
 import "./tobago-focus";
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-calendar.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-calendar.ts
deleted file mode 100644
index e072628..0000000
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-calendar.ts
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {Listener, Phase} from "./tobago-listener";
-import {DomUtils} from "./tobago-utils";
-import {CommandHelper} from "./tobago-command";
-
-class DateTime {
-
-  static init(element: HTMLElement): void {
-    for (const e of DomUtils.selfOrQuerySelectorAll(element, ".tobago-date:not([readonly]):not([disabled])"))
{
-      const date: HTMLInputElement = e as HTMLInputElement;
-
-      const analyzed = DateTime.analyzePattern(date.dataset.tobagoPattern);
-      const options = {
-        format: analyzed,
-        showTodayButton: date.dataset.tobagoTodayButton === "data-tobago-today-button",
-        icons: {
-          time: "fa fa-clock-o",
-          date: "fa fa-calendar",
-          up: "fa fa-chevron-up",
-          down: "fa fa-chevron-down",
-          previous: "fa fa-chevron-left",
-          next: "fa fa-chevron-right",
-          today: "fa fa-calendar-check-o",
-          clear: "fa fa-trash",
-          close: "fa fa-times"
-        },
-        keyBinds: {
-          left: function ($widget): void {
-            const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
-            if (widget === undefined) {
-              if (date.selectionStart === date.selectionEnd) {
-                if (date.selectionStart > 0 || date.selectionStart > 0) {
-                  date.selectionStart--;
-                  date.selectionEnd--;
-                }
-              } else {
-                date.selectionEnd = date.selectionStart;
-              }
-            } else if (DomUtils.isVisible(widget.querySelector(".datepicker"))) {
-              this.date(this.date().clone().subtract(1, "d"));
-            }
-          },
-          right: function ($widget): void {
-            const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
-            if (widget === undefined) {
-              if (date.selectionStart === date.selectionEnd) {
-                if (date.selectionStart > 0 || date.selectionStart < date.value.length)
{
-                  date.selectionEnd++;
-                  date.selectionStart++;
-                }
-              } else {
-                date.selectionStart = date.selectionEnd;
-              }
-            } else if (DomUtils.isVisible(widget.querySelector(".datepicker"))) {
-              this.date(this.date().clone().add(1, "d"));
-            }
-          },
-          enter: function ($widget): void {
-            const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
-            if (widget !== undefined && DomUtils.isVisible(widget.querySelector(".datepicker")))
{
-              this.hide();
-              fixKey(13);
-            } else {
-              //jQuery because used by datetimepicker
-              jQuery(date).trigger(jQuery.Event("keypress", {
-                which: 13,
-                target: date
-              }));
-            }
-          },
-          escape: function ($widget): void {
-            const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
-            if (widget !== undefined && DomUtils.isVisible(widget.querySelector(".datepicker")))
{
-              this.hide();
-              fixKey(27);
-            }
-          },
-          "delete": function (): void {
-            if (date.selectionStart < date.value.length) {
-              const selectionStart = date.selectionStart;
-              let selectionEnd = date.selectionEnd;
-
-              if (selectionStart === selectionEnd && selectionStart < date.value.length)
{
-                selectionEnd++;
-              }
-              date.value = date.value.substr(0, selectionStart)
-                  + date.value.substr(selectionEnd, date.value.length);
-
-              date.selectionEnd = selectionStart;
-              date.selectionStart = selectionStart;
-            }
-          }
-        },
-        widgetParent: ".tobago-page-menuStore"
-      };
-
-      /**
-       * After ESC or ENTER is pressed we need to fire the keyup event manually.
-       * see: https://github.com/tempusdominus/bootstrap-4/issues/159
-       */
-      function fixKey(keyCode): void {
-        let keyupEvent = jQuery.Event("keyup");
-        keyupEvent.which = keyCode;
-        jQuery(date).trigger(keyupEvent);
-      }
-
-      const i18n = date.dataset.tobagoDateTimeI18n ? JSON.parse(date.dataset.tobagoDateTimeI18n)
: undefined;
-      if (i18n) {
-        const monthNames = i18n.monthNames;
-        if (monthNames) {
-          moment.localeData()._months = monthNames;
-        }
-        const monthNamesShort = i18n.monthNamesShort;
-        if (monthNamesShort) {
-          moment.localeData()._monthsShort = monthNamesShort;
-        }
-        const dayNames = i18n.dayNames;
-        if (dayNames) {
-          moment.localeData()._weekdays = dayNames;
-        }
-        const dayNamesShort = i18n.dayNamesShort;
-        if (dayNamesShort) {
-          moment.localeData()._weekdaysShort = dayNamesShort;
-        }
-        const dayNamesMin = i18n.dayNamesMin;
-        if (dayNamesMin) {
-          moment.localeData()._weekdaysMin = dayNamesMin;
-        }
-        const firstDay = i18n.firstDay;
-        if (firstDay) {
-          moment.localeData()._week.dow = firstDay;
-        }
-      }
-
-      let $dateParent = jQuery(date).parent(); //use jQuery because required for datetimepicker
-      $dateParent.datetimepicker(options);
-
-      // we need to add the change listener here, because
-      // in line 1307 of bootstrap-datetimepicker.js
-      // the 'stopImmediatePropagation()' stops the change-event
-      // execution of line 686 in tobago.js
-      $dateParent.on("dp.change", function (event: Event): void {
-        let input: HTMLInputElement = this.querySelector("input");
-        let commands = input.dataset.tobagoCommands ? JSON.parse(input.dataset.tobagoCommands)
: undefined;
-        if (commands && commands.change) {
-          if (commands.change.execute || commands.change.render) {
-            jsf.ajax.request(
-                input.getAttribute("name"),
-                event,
-                {
-                  "javax.faces.behavior.event": "change",
-                  execute: commands.change.execute,
-                  render: commands.change.render
-                });
-          } else if (commands.change.action) {
-            CommandHelper.submitAction(
-                this.firstElementChild as HTMLElement,
-                commands.change.action, commands.change.transition, commands.change.target);
-          }
-        }
-      });
-
-      // set position
-      $dateParent.on("dp.show", function (): void {
-        let datepicker: HTMLDivElement = document.querySelector(".bootstrap-datetimepicker-widget");
-        let div: HTMLDivElement = this;
-        let top, left;
-        if (datepicker.classList.contains("bottom")) {
-          top = DomUtils.offset(div).top + div.offsetHeight;
-          left = DomUtils.offset(div).left;
-          datepicker.style.top = top + "px";
-          datepicker.style.bottom = "auto";
-          datepicker.style.left = left + "px";
-        } else if (datepicker.classList.contains("top")) {
-          top = DomUtils.offset(div).top - datepicker.offsetHeight;
-          left = DomUtils.offset(div).left;
-          datepicker.style.top = top + "px";
-          datepicker.style.bottom = "auto";
-          datepicker.style.left = left + "px";
-        }
-        DateTime.addPastClass(date);
-      });
-
-      // set css class in update - like changing the month
-      $dateParent.on("dp.update", function (): void {
-        DateTime.addPastClass(date);
-      });
-
-      // fix for bootstrap-datetimepicker v4.17.45
-      $dateParent.on("dp.show", function (): void {
-        const collapseIn = document.querySelector(".bootstrap-datetimepicker-widget .collapse.in");
-        const pickerSwitch = document.querySelector(".bootstrap-datetimepicker-widget .picker-switch
a");
-
-        if (collapseIn !== null) {
-          collapseIn.classList.add("show");
-        }
-        if (pickerSwitch !== null) {
-          pickerSwitch.addEventListener(
-              "click", function (): void {
-                // the click is executed before togglePicker() function
-                let datetimepicker: HTMLDivElement = document.querySelector(".bootstrap-datetimepicker-widget");
-                datetimepicker.querySelector(".collapse.in").classList.remove("in");
-                datetimepicker.querySelector(".collapse.show").classList.add("in");
-              });
-        }
-      });
-    }
-  }
-
-  static addPastClass(date: HTMLInputElement): void {
-    let today = date.dataset.tobagoToday;
-    if (today.length === 10) {
-      const todayArray = today.split("-");
-      if (todayArray.length === 3) {
-        const year = todayArray[0];
-        const month = todayArray[1];
-        const day = todayArray[2];
-        const todayTimestamp = new Date(month + "/" + day + "/" + year).getTime();
-
-        const days = document.querySelectorAll(".bootstrap-datetimepicker-widget .datepicker-days
td.day[data-day]");
-        for (const day of days) {
-          const currentTimestamp = new Date(day.getAttribute("data-day")).getTime();
-          if (currentTimestamp < todayTimestamp) {
-            day.classList.add("past");
-          }
-        }
-      }
-    }
-  }
-
-  /*
-   Get the pattern from the "Java world" (http://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html)
-   and convert it to 'moment.js'.
-   Attention: Not every pattern char is supported.
-   */
-  static analyzePattern = function (originalPattern: string): string {
-
-    let pattern;
-    if (!originalPattern || originalPattern.length > 100) {
-      console.warn("Pattern not supported: " + originalPattern);
-      pattern = "";
-    } else {
-      pattern = originalPattern;
-    }
-
-    let analyzedPattern = "";
-    let nextSegment = "";
-    let escMode = false;
-    for (let i = 0; i < pattern.length; i++) {
-      const currentChar = pattern.charAt(i);
-      if (currentChar == "'" && escMode == false) {
-        escMode = true;
-        analyzedPattern += DateTime.analyzePatternPart(nextSegment);
-        nextSegment = "";
-      } else if (currentChar == "'" && pattern.charAt(i + 1) == "'") {
-        if (escMode) {
-          nextSegment += "\\";
-        }
-        nextSegment += "'";
-        i++;
-      } else if (currentChar == "'" && escMode == true) {
-        escMode = false;
-        analyzedPattern += nextSegment;
-        nextSegment = "";
-      } else {
-        if (escMode) {
-          nextSegment += "\\";
-        }
-        nextSegment += currentChar;
-      }
-    }
-    if (nextSegment != "") {
-      if (escMode) {
-        analyzedPattern += nextSegment;
-      } else {
-        analyzedPattern += DateTime.analyzePatternPart(nextSegment);
-      }
-    }
-
-    return analyzedPattern;
-  };
-
-  static analyzePatternPart = function (originalPattern: string): string {
-
-    let pattern = originalPattern;
-
-    if (pattern.search("G") > -1 || pattern.search("W") > -1 || pattern.search("F")
> -1
-        || pattern.search("K") > -1 || pattern.search("z") > -1 || pattern.search("X")
> -1) {
-      console.warn("Pattern chars 'G', 'W', 'F', 'K', 'z' and 'X' are not supported: " +
pattern);
-      pattern = "";
-    }
-
-    if (pattern.search("y") > -1) {
-      pattern = pattern.replace(/y/g, "Y");
-    }
-    if (pattern.search("Y") > -1) {
-      pattern = pattern.replace(/\bY\b/g, "YYYY");
-      pattern = pattern.replace(/\bYYY\b/g, "YY");
-      pattern = pattern.replace(/YYYYYY+/g, "YYYYY");
-    }
-
-    if (pattern.search("MMMMM") > -1) {
-      pattern = pattern.replace(/MMMMM+/g, "MMMM");
-    }
-
-    if (pattern.search("w") > -1) {
-      pattern = pattern.replace(/\bw\b/g, "W");
-      pattern = pattern.replace(/www+/g, "WW");
-    }
-
-    if (pattern.search("D") > -1) {
-      pattern = pattern.replace(/DDD+/g, "DDDD");
-      pattern = pattern.replace(/\bD{1,2}\b/g, "DDD");
-    }
-
-    if (pattern.search("d") > -1) {
-      pattern = pattern.replace(/dd+/g, "DD");
-      pattern = pattern.replace(/\bd\b/g, "D");
-    }
-
-    if (pattern.search("E") > -1) {
-      pattern = pattern.replace(/\bE{1,3}\b/g, "dd");
-      pattern = pattern.replace(/EEEE+/g, "dddd");
-    }
-
-    if (pattern.search("u") > -1) {
-      pattern = pattern.replace(/u+/g, "E");
-    }
-    if (pattern.search("a") > -1) {
-      pattern = pattern.replace(/a+/g, "A");
-    }
-    if (pattern.search("HHH") > -1) {
-      pattern = pattern.replace(/HHH+/g, "HH");
-    }
-    if (pattern.search("kkk") > -1) {
-      pattern = pattern.replace(/kkk+/g, "kk");
-    }
-    if (pattern.search("hhh") > -1) {
-      pattern = pattern.replace(/hhh+/g, "hh");
-    }
-    if (pattern.search("mmm") > -1) {
-      pattern = pattern.replace(/mmm+/g, "mm");
-    }
-    if (pattern.search("sss") > -1) {
-      pattern = pattern.replace(/sss+/g, "ss");
-    }
-    if (pattern.search("SSSS") > -1) {
-      pattern = pattern.replace(/SSSS+/g, "SSS");
-    }
-    if (pattern.search("Z") > -1) {
-      pattern = pattern.replace(/\bZ\b/g, "ZZ");
-      pattern = pattern.replace(/ZZZ+/g, "ZZ");
-    }
-
-    return pattern;
-  };
-}
-
-Listener.register(DateTime.init, Phase.DOCUMENT_READY);
-Listener.register(DateTime.init, Phase.AFTER_UPDATE);
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-date.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-date.ts
new file mode 100644
index 0000000..397c3dd
--- /dev/null
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-date.ts
@@ -0,0 +1,372 @@
+/*
+ * 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.
+ */
+
+import {DomUtils} from "./tobago-utils";
+
+class DateTime extends HTMLElement {
+
+  static addPastClass(date: HTMLInputElement): void {
+    let today = date.dataset.tobagoToday;
+    if (today.length === 10) {
+      const todayArray = today.split("-");
+      if (todayArray.length === 3) {
+        const year = todayArray[0];
+        const month = todayArray[1];
+        const day = todayArray[2];
+        const todayTimestamp = new Date(month + "/" + day + "/" + year).getTime();
+
+        const days = document.querySelectorAll(".bootstrap-datetimepicker-widget .datepicker-days
td.day[data-day]");
+        for (const day of days) {
+          const currentTimestamp = new Date(day.getAttribute("data-day")).getTime();
+          if (currentTimestamp < todayTimestamp) {
+            day.classList.add("past");
+          }
+        }
+      }
+    }
+  }
+
+  constructor() {
+    super();
+  }
+
+  connectedCallback(): void {
+
+    const date = this.inputElement;
+
+    if (date.readOnly || date.disabled) {
+      return;
+    }
+
+    const analyzed = this.analyzePattern();
+    const options = {
+      format: analyzed,
+      showTodayButton: date.dataset.tobagoTodayButton === "data-tobago-today-button",
+      icons: {
+        time: "fa fa-clock-o",
+        date: "fa fa-calendar",
+        up: "fa fa-chevron-up",
+        down: "fa fa-chevron-down",
+        previous: "fa fa-chevron-left",
+        next: "fa fa-chevron-right",
+        today: "fa fa-calendar-check-o",
+        clear: "fa fa-trash",
+        close: "fa fa-times"
+      },
+      keyBinds: {
+        left: function ($widget): void {
+          const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
+          if (widget === undefined) {
+            if (date.selectionStart === date.selectionEnd) {
+              if (date.selectionStart > 0 || date.selectionStart > 0) {
+                date.selectionStart--;
+                date.selectionEnd--;
+              }
+            } else {
+              date.selectionEnd = date.selectionStart;
+            }
+          } else if (DomUtils.isVisible(widget.querySelector(".datepicker"))) {
+            this.date(this.date().clone().subtract(1, "d"));
+          }
+        },
+        right: function ($widget): void {
+          const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
+          if (widget === undefined) {
+            if (date.selectionStart === date.selectionEnd) {
+              if (date.selectionStart > 0 || date.selectionStart < date.value.length)
{
+                date.selectionEnd++;
+                date.selectionStart++;
+              }
+            } else {
+              date.selectionStart = date.selectionEnd;
+            }
+          } else if (DomUtils.isVisible(widget.querySelector(".datepicker"))) {
+            this.date(this.date().clone().add(1, "d"));
+          }
+        },
+        enter: function ($widget): void {
+          const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
+          if (widget !== undefined && DomUtils.isVisible(widget.querySelector(".datepicker")))
{
+            this.hide();
+            fixKey(13);
+          } else {
+            //jQuery because used by datetimepicker
+            jQuery(date).trigger(jQuery.Event("keypress", {
+              which: 13,
+              target: date
+            }));
+          }
+        },
+        escape: function ($widget): void {
+          const widget: HTMLDivElement = $widget[0] as HTMLDivElement;
+          if (widget !== undefined && DomUtils.isVisible(widget.querySelector(".datepicker")))
{
+            this.hide();
+            fixKey(27);
+          }
+        },
+        "delete": function (): void {
+          if (date.selectionStart < date.value.length) {
+            const selectionStart = date.selectionStart;
+            let selectionEnd = date.selectionEnd;
+
+            if (selectionStart === selectionEnd && selectionStart < date.value.length)
{
+              selectionEnd++;
+            }
+            date.value = date.value.substr(0, selectionStart)
+                + date.value.substr(selectionEnd, date.value.length);
+
+            date.selectionEnd = selectionStart;
+            date.selectionStart = selectionStart;
+          }
+        }
+      },
+      widgetParent: ".tobago-page-menuStore"
+    };
+
+    /**
+     * After ESC or ENTER is pressed we need to fire the keyup event manually.
+     * see: https://github.com/tempusdominus/bootstrap-4/issues/159
+     */
+    function fixKey(keyCode): void {
+      let keyupEvent = jQuery.Event("keyup");
+      keyupEvent.which = keyCode;
+      jQuery(date).trigger(keyupEvent);
+    }
+
+    const i18n = date.dataset.tobagoDateTimeI18n ? JSON.parse(date.dataset.tobagoDateTimeI18n)
: undefined;
+    if (i18n) {
+      const monthNames = i18n.monthNames;
+      if (monthNames) {
+        moment.localeData()._months = monthNames;
+      }
+      const monthNamesShort = i18n.monthNamesShort;
+      if (monthNamesShort) {
+        moment.localeData()._monthsShort = monthNamesShort;
+      }
+      const dayNames = i18n.dayNames;
+      if (dayNames) {
+        moment.localeData()._weekdays = dayNames;
+      }
+      const dayNamesShort = i18n.dayNamesShort;
+      if (dayNamesShort) {
+        moment.localeData()._weekdaysShort = dayNamesShort;
+      }
+      const dayNamesMin = i18n.dayNamesMin;
+      if (dayNamesMin) {
+        moment.localeData()._weekdaysMin = dayNamesMin;
+      }
+      const firstDay = i18n.firstDay;
+      if (firstDay) {
+        moment.localeData()._week.dow = firstDay;
+      }
+    }
+
+    let $dateParent = jQuery(date).parent(); //use jQuery because required for datetimepicker
+    $dateParent.datetimepicker(options);
+
+    // we need to add the change listener here, because
+    // in line 1307 of bootstrap-datetimepicker.js
+    // the 'stopImmediatePropagation()' stops the change-event
+    // execution of line 686 in tobago.js
+
+    $dateParent.on("dp.change", function (event: Event): void {
+      event.target.dispatchEvent(new Event("change", {bubbles: true}));
+    });
+
+    // set position
+    $dateParent.on("dp.show", function (): void {
+      let datepicker: HTMLDivElement = document.querySelector(".bootstrap-datetimepicker-widget");
+      let div: HTMLDivElement = this;
+      let top, left;
+      if (datepicker.classList.contains("bottom")) {
+        top = DomUtils.offset(div).top + div.offsetHeight;
+        left = DomUtils.offset(div).left;
+        datepicker.style.top = top + "px";
+        datepicker.style.bottom = "auto";
+        datepicker.style.left = left + "px";
+      } else if (datepicker.classList.contains("top")) {
+        top = DomUtils.offset(div).top - datepicker.offsetHeight;
+        left = DomUtils.offset(div).left;
+        datepicker.style.top = top + "px";
+        datepicker.style.bottom = "auto";
+        datepicker.style.left = left + "px";
+      }
+      DateTime.addPastClass(date);
+    });
+
+    // set css class in update - like changing the month
+    $dateParent.on("dp.update", function (): void {
+      DateTime.addPastClass(date);
+    });
+
+    // fix for bootstrap-datetimepicker v4.17.45
+    $dateParent.on("dp.show", function (): void {
+      const collapseIn = document.querySelector(".bootstrap-datetimepicker-widget .collapse.in");
+      const pickerSwitch = document.querySelector(".bootstrap-datetimepicker-widget .picker-switch
a");
+
+      if (collapseIn !== null) {
+        collapseIn.classList.add("show");
+      }
+      if (pickerSwitch !== null) {
+        pickerSwitch.addEventListener(
+            "click", function (): void {
+              // the click is executed before togglePicker() function
+              let datetimepicker: HTMLDivElement = document.querySelector(".bootstrap-datetimepicker-widget");
+              datetimepicker.querySelector(".collapse.in").classList.remove("in");
+              datetimepicker.querySelector(".collapse.show").classList.add("in");
+            });
+      }
+    });
+  }
+
+  get inputElement(): HTMLInputElement {
+    return this.querySelector("input") as HTMLInputElement;
+  }
+
+  /*
+ Get the pattern from the "Java world" (http://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html)
+ and convert it to 'moment.js'.
+ Attention: Not every pattern char is supported.
+ */
+  analyzePattern(): string {
+    const originalPattern = this.inputElement.dataset.tobagoPattern;
+
+    let pattern;
+    if (!originalPattern || originalPattern.length > 100) {
+      console.warn("Pattern not supported: " + originalPattern);
+      pattern = "";
+    } else {
+      pattern = originalPattern;
+    }
+
+    let analyzedPattern = "";
+    let nextSegment = "";
+    let escMode = false;
+    for (let i = 0; i < pattern.length; i++) {
+      const currentChar = pattern.charAt(i);
+      if (currentChar == "'" && escMode == false) {
+        escMode = true;
+        analyzedPattern += this.analyzePatternPart(nextSegment);
+        nextSegment = "";
+      } else if (currentChar == "'" && pattern.charAt(i + 1) == "'") {
+        if (escMode) {
+          nextSegment += "\\";
+        }
+        nextSegment += "'";
+        i++;
+      } else if (currentChar == "'" && escMode == true) {
+        escMode = false;
+        analyzedPattern += nextSegment;
+        nextSegment = "";
+      } else {
+        if (escMode) {
+          nextSegment += "\\";
+        }
+        nextSegment += currentChar;
+      }
+    }
+    if (nextSegment != "") {
+      if (escMode) {
+        analyzedPattern += nextSegment;
+      } else {
+        analyzedPattern += this.analyzePatternPart(nextSegment);
+      }
+    }
+
+    return analyzedPattern;
+  }
+
+  analyzePatternPart(originalPattern: string): string {
+
+    let pattern = originalPattern;
+
+    if (pattern.search("G") > -1 || pattern.search("W") > -1 || pattern.search("F")
> -1
+        || pattern.search("K") > -1 || pattern.search("z") > -1 || pattern.search("X")
> -1) {
+      console.warn("Pattern chars 'G', 'W', 'F', 'K', 'z' and 'X' are not supported: " +
pattern);
+      pattern = "";
+    }
+
+    if (pattern.search("y") > -1) {
+      pattern = pattern.replace(/y/g, "Y");
+    }
+    if (pattern.search("Y") > -1) {
+      pattern = pattern.replace(/\bY\b/g, "YYYY");
+      pattern = pattern.replace(/\bYYY\b/g, "YY");
+      pattern = pattern.replace(/YYYYYY+/g, "YYYYY");
+    }
+
+    if (pattern.search("MMMMM") > -1) {
+      pattern = pattern.replace(/MMMMM+/g, "MMMM");
+    }
+
+    if (pattern.search("w") > -1) {
+      pattern = pattern.replace(/\bw\b/g, "W");
+      pattern = pattern.replace(/www+/g, "WW");
+    }
+
+    if (pattern.search("D") > -1) {
+      pattern = pattern.replace(/DDD+/g, "DDDD");
+      pattern = pattern.replace(/\bD{1,2}\b/g, "DDD");
+    }
+
+    if (pattern.search("d") > -1) {
+      pattern = pattern.replace(/dd+/g, "DD");
+      pattern = pattern.replace(/\bd\b/g, "D");
+    }
+
+    if (pattern.search("E") > -1) {
+      pattern = pattern.replace(/\bE{1,3}\b/g, "dd");
+      pattern = pattern.replace(/EEEE+/g, "dddd");
+    }
+
+    if (pattern.search("u") > -1) {
+      pattern = pattern.replace(/u+/g, "E");
+    }
+    if (pattern.search("a") > -1) {
+      pattern = pattern.replace(/a+/g, "A");
+    }
+    if (pattern.search("HHH") > -1) {
+      pattern = pattern.replace(/HHH+/g, "HH");
+    }
+    if (pattern.search("kkk") > -1) {
+      pattern = pattern.replace(/kkk+/g, "kk");
+    }
+    if (pattern.search("hhh") > -1) {
+      pattern = pattern.replace(/hhh+/g, "hh");
+    }
+    if (pattern.search("mmm") > -1) {
+      pattern = pattern.replace(/mmm+/g, "mm");
+    }
+    if (pattern.search("sss") > -1) {
+      pattern = pattern.replace(/sss+/g, "ss");
+    }
+    if (pattern.search("SSSS") > -1) {
+      pattern = pattern.replace(/SSSS+/g, "SSS");
+    }
+    if (pattern.search("Z") > -1) {
+      pattern = pattern.replace(/\bZ\b/g, "ZZ");
+      pattern = pattern.replace(/ZZZ+/g, "ZZ");
+    }
+
+    return pattern;
+  }
+
+}
+
+document.addEventListener("DOMContentLoaded", function (event: Event): void {
+  window.customElements.define("tobago-date", DateTime);
+});
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 5921e4d..7c4c862 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
@@ -74,7 +74,7 @@
           <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"/>
-          <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-calendar.js"/>
+          <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-date.js"/>
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-command.js"/>
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-file.js"/>
           <script name="/tobago/standard/tobago-bootstrap/${project.version}/js/tobago-focus.js"/>


Mime
View raw message