Project import generated by Copybara.
GitOrigin-RevId: 63746295f1a5ab5a619056791995793d65529e62
diff --git a/src/js/common.js b/src/js/common.js
new file mode 100644
index 0000000..445016e
--- /dev/null
+++ b/src/js/common.js
@@ -0,0 +1,242 @@
+/**
+ * Functions hasClass(), addClass() and removeClass() developed by Jake Trent (http://jaketrent.com/post/addremove-classes-raw-javascript/)
+ */
+function hasClass(el, className) {
+ if (el.classList)
+ return el.classList.contains(className)
+ else
+ return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'))
+}
+
+function addClass(el, className) {
+ if (el.classList)
+ el.classList.add(className)
+ else if (!hasClass(el, className)) el.className += " " + className
+}
+
+function removeClass(el, className) {
+ if (el.classList)
+ el.classList.remove(className)
+ else if (hasClass(el, className)) {
+ var reg = new RegExp('(\\s|^)' + className + '(\\s|$)')
+ el.className=el.className.replace(reg, ' ')
+ }
+}
+
+// MultiSelect implementation:
+var MultiSelect = function MultiSelect(element) {
+ this.element_ = element;
+ this.selected_ = [];
+
+ var forElId = this.element_.getAttribute("for") || this.element_.getAttribute("data-for");
+ if (forElId) {
+ this.forEl_ = (forElId ? document.getElementById(this.element_.getAttribute("for")) : null);
+ }
+
+ this.init();
+};
+
+MultiSelect.prototype.renderSummary = function() {
+ if (this.forEl_) {
+ this.forEl_.innerText = this.selected_.join(", ") || "-";
+ }
+};
+
+MultiSelect.prototype.init = function() {
+ if (this.element_) {
+ this.element_.addEventListener("click", e => {
+ e.stopImmediatePropagation();
+ }, true);
+
+ this.element_.querySelectorAll(".mdl-custom-multiselect__item").forEach(item => {
+ var checkbox = item.querySelector("input[type=\"checkbox\"]");
+ var label = item.querySelector(".mdl-checkbox__label").innerText;
+ checkbox.addEventListener("change", e => {
+ if(checkbox.checked) {
+ this.selected_.push(label);
+ } else {
+ this.selected_ = this.selected_.filter(item => item !== label);
+ }
+ this.renderSummary();
+
+ var customEvent = new Event('custom-multiselect-change');
+ this.element_.dispatchEvent(customEvent);
+ });
+ });
+ }
+};
+
+var dynDialog = {
+ didItInit: false,
+ dialog: null,
+ url: null,
+ load: function(url, reload) {
+ if (this.didItInit === false) {
+ this.init();
+ }
+
+ if (this.url == url && reload !== true) {
+ this.show();
+ return;
+ }
+
+ this.url = url;
+
+ fetch(url).then(response => response.text()).then(response => {
+ if (this.dialog.open) {
+ this.close();
+ }
+
+ this.dialog.innerHTML = response;
+ componentHandler.upgradeElements(this.dialog);
+
+ this.dialog.querySelectorAll("[data-required]").forEach(input => {
+ input.setAttribute("required", "true");
+ });
+
+ var script = this.dialog.querySelectorAll("dynscript");
+ if (script.length > 0) {
+ for (var i = 0; i < script.length; i++) {
+ eval(script[i].innerText);
+ }
+ }
+ this.dialog.querySelectorAll("[data-dyndialog-close]").forEach(btn => {
+ btn.addEventListener("click", e => {
+ e.preventDefault();
+ this.close();
+ });
+ });
+
+ this.dialog.showModal();
+ });
+ },
+ reload: function() {
+ this.load(this.url, true);
+ },
+ show: function() {
+ this.dialog.showModal();
+ },
+ close: function() {
+ this.dialog.close();
+ },
+ init: function() {
+ this.dialog = document.createElement("dialog");
+ this.dialog.setAttribute("id", "dynDialog");
+ this.dialog.setAttribute("class", "mdl-dialog");
+ dialogPolyfill.registerDialog(this.dialog);
+ document.body.appendChild(this.dialog);
+
+ this.didItInit = true;
+ }
+};
+
+// From nodep-date-input-polyfill
+function isDateInputSupported() {
+ const input = document.createElement("input");
+ input.setAttribute("type", "date");
+
+ const notADateValue = "not-a-date";
+ input.setAttribute("value", notADateValue);
+
+ return (input.value !== notADateValue);
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+ var dialogs = document.querySelectorAll("dialog");
+ for (var i = 0; i < dialogs.length; i++) {
+ dialogPolyfill.registerDialog(dialogs[i]);
+ }
+
+ document.querySelectorAll("[data-dyndialog-href]").forEach(link => {
+ link.addEventListener("click", e => {
+ e.preventDefault();
+ dynDialog.load(link.getAttribute("data-dyndialog-href"));
+ });
+ });
+
+ document.querySelectorAll(".mdl-custom-multiselect-js").forEach(menu => {
+ new MultiSelect(menu);
+ });
+});
+
+function importCSS(url) {
+ var link = document.createElement("link");
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("href", url);
+ document.head.appendChild(link);
+}
+
+var loadScriptAsync = function(uri) {
+ return new Promise((resolve, reject) => {
+ var script = document.createElement('script');
+ script.src = uri;
+ script.async = true;
+ script.onload = () => {
+ resolve();
+ };
+ document.head.appendChild(script);
+ });
+}
+
+function hasParentDialog(el) {
+ while (el != document.documentElement) {
+ if (el.tagName == "DIALOG") {
+ return el;
+ }
+
+ el = el.parentNode;
+ }
+
+ return undefined;
+}
+
+function polyfillDateSupport(container) {
+ container.querySelectorAll("input[type=\"date\"]").forEach(el => {
+ el.setAttribute("type", "text");
+
+ dialogParent = hasParentDialog(el);
+
+ var options = {
+ format: "yyyy-mm-dd",
+ todayHighlight: true,
+ weekStart: 1,
+ zIndexOffset: 100,
+ container: dialogParent || container
+ };
+
+ if (el.hasAttribute("max")) {
+ options.endDate = el.getAttribute("max");
+ }
+
+ $(el).datepicker(options);
+ });
+
+ container.querySelectorAll("input[type=\"time\"]").forEach(el => {
+ el.setAttribute("placeholder", "hh:mm");
+ });
+}
+
+function initPolyfillDateSupport() {
+ console.info("Polyfilling date support");
+
+ importCSS("https://unpkg.com/bootstrap-datepicker@1.9.0/dist/css/bootstrap-datepicker3.standalone.min.css", "css");
+
+ loadScriptAsync("https://unpkg.com/jquery@3.4.1/dist/jquery.min.js", "js").then(_ => {
+ return loadScriptAsync("https://unpkg.com/bootstrap-datepicker@1.9.0/dist/js/bootstrap-datepicker.min.js");
+ }).then(_ => {
+ return loadScriptAsync("https://unpkg.com/bootstrap-datepicker@1.9.0/dist/locales/bootstrap-datepicker.es.min.js");
+ }).then(_ => {
+ console.log("[Date polyfill] Scripts loaded.");
+ polyfillDateSupport(document.documentElement);
+ });
+}
+
+window.addEventListener("load", function() {
+ document.querySelectorAll("[data-required]").forEach(input => {
+ input.setAttribute("required", "true");
+ });
+
+ if (!isDateInputSupported()) {
+ initPolyfillDateSupport();
+ }
+});