CINXE.COM

<!DOCTYPE html><html lang="en"><head> <script defer="" data-domain="app.gbof.ca" src="https://plausible.clickncode.com/js/script.js"></script> <!-- Google Tag Manager --> <script> ;(function (w, d, s, l, i) { w[l] = w[l] || [] w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' }) var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '' j.async = true j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl f.parentNode.insertBefore(j, f) })(window, document, 'script', 'dataLayer', 'GTM-PV695QG') </script> <script> window.dataLayer = window.dataLayer || [] function gtag() { dataLayer.push(arguments) } </script> <!-- End Google Tag Manager --> <title x-t="canadianCommercialCorporation">Canadian Commercial Corporation (CCC)</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../custom.css"> <script src="../main.js"></script> <link rel="icon" href="../images/favicon.ico"> <link href="https://fonts.cdnfonts.com/css/roboto" rel="stylesheet"> <script>(() => { var icons = { success: "app/success", warning: "app/warning", danger: "app/danger", info: "b:info-circle", primary: "b:person-fill" }; var titles = { success: "Success", warning: "Warning", danger: "Failed", info: "Info", primary: "Notification" }; var app_toast_default = { title: "", message: "", kind: "primary", // success , danger , warning , info, delay: 2e3, _notices: [], _visible: [], init() { if (document.querySelectorAll("app-toast").length > 1) console.warn("more than one app-toast rendered in the page"); }, add(notice) { notice.id = Date.now(); notice.icon = icons[notice.kind] || icons.info; notice.title = notice.title || titles[notice.kind] || "Notification"; notice.kind = notice.kind || "primary"; this._notices.push(notice); this._visible.push(notice); const timeShown = this.delay * this._visible.length; notice._timeout = setTimeout(() => this.remove(notice.id), timeShown); }, remove(id) { this._visible = this._visible.filter((notice) => notice.id !== id); setTimeout(() => { this._notices = this._notices.filter((notice) => notice.id !== id); }, 1e3); } }; // <stdin> if (!window.customElements.get("app-toast")) { const factory = WidgetData.buildFactory(typeof app_toast_default === "undefined" ? {} : app_toast_default); Alpine.data("appToast", factory); WidgetElement.widgets.add("app-toast"); class appToastWidget extends WidgetElement { } customElements.define("app-toast", appToastWidget); } })(); (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var require_dataloader = __commonJS({ "../clickncode/node_modules/.pnpm/dataloader@2.2.2/node_modules/dataloader/index.js"(exports, module) { "use strict"; var DataLoader2 = /* @__PURE__ */ function() { function DataLoader3(batchLoadFn, options) { if (typeof batchLoadFn !== "function") { throw new TypeError("DataLoader must be constructed with a function which accepts " + ("Array<key> and returns Promise<Array<value>>, but got: " + batchLoadFn + ".")); } this._batchLoadFn = batchLoadFn; this._maxBatchSize = getValidMaxBatchSize(options); this._batchScheduleFn = getValidBatchScheduleFn(options); this._cacheKeyFn = getValidCacheKeyFn(options); this._cacheMap = getValidCacheMap(options); this._batch = null; this.name = getValidName(options); } var _proto = DataLoader3.prototype; _proto.load = function load(key) { if (key === null || key === void 0) { throw new TypeError("The loader.load() function must be called with a value, " + ("but got: " + String(key) + ".")); } var batch = getCurrentBatch(this); var cacheMap = this._cacheMap; var cacheKey = this._cacheKeyFn(key); if (cacheMap) { var cachedPromise = cacheMap.get(cacheKey); if (cachedPromise) { var cacheHits = batch.cacheHits || (batch.cacheHits = []); return new Promise(function(resolve) { cacheHits.push(function() { resolve(cachedPromise); }); }); } } batch.keys.push(key); var promise = new Promise(function(resolve, reject2) { batch.callbacks.push({ resolve, reject: reject2 }); }); if (cacheMap) { cacheMap.set(cacheKey, promise); } return promise; }; _proto.loadMany = function loadMany(keys) { if (!isArrayLike(keys)) { throw new TypeError("The loader.loadMany() function must be called with Array<key> " + ("but got: " + keys + ".")); } var loadPromises = []; for (var i = 0; i < keys.length; i++) { loadPromises.push(this.load(keys[i])["catch"](function(error) { return error; })); } return Promise.all(loadPromises); }; _proto.clear = function clear(key) { var cacheMap = this._cacheMap; if (cacheMap) { var cacheKey = this._cacheKeyFn(key); cacheMap["delete"](cacheKey); } return this; }; _proto.clearAll = function clearAll() { var cacheMap = this._cacheMap; if (cacheMap) { cacheMap.clear(); } return this; }; _proto.prime = function prime(key, value) { var cacheMap = this._cacheMap; if (cacheMap) { var cacheKey = this._cacheKeyFn(key); if (cacheMap.get(cacheKey) === void 0) { var promise; if (value instanceof Error) { promise = Promise.reject(value); promise["catch"](function() { }); } else { promise = Promise.resolve(value); } cacheMap.set(cacheKey, promise); } } return this; }; return DataLoader3; }(); var enqueuePostPromiseJob = typeof process === "object" && typeof process.nextTick === "function" ? function(fn) { if (!resolvedPromise) { resolvedPromise = Promise.resolve(); } resolvedPromise.then(function() { process.nextTick(fn); }); } : typeof setImmediate === "function" ? function(fn) { setImmediate(fn); } : function(fn) { setTimeout(fn); }; var resolvedPromise; function getCurrentBatch(loader) { var existingBatch = loader._batch; if (existingBatch !== null && !existingBatch.hasDispatched && existingBatch.keys.length < loader._maxBatchSize) { return existingBatch; } var newBatch = { hasDispatched: false, keys: [], callbacks: [] }; loader._batch = newBatch; loader._batchScheduleFn(function() { dispatchBatch(loader, newBatch); }); return newBatch; } function dispatchBatch(loader, batch) { batch.hasDispatched = true; if (batch.keys.length === 0) { resolveCacheHits(batch); return; } var batchPromise; try { batchPromise = loader._batchLoadFn(batch.keys); } catch (e) { return failedDispatch(loader, batch, new TypeError("DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function " + ("errored synchronously: " + String(e) + "."))); } if (!batchPromise || typeof batchPromise.then !== "function") { return failedDispatch(loader, batch, new TypeError("DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did " + ("not return a Promise: " + String(batchPromise) + "."))); } batchPromise.then(function(values) { if (!isArrayLike(values)) { throw new TypeError("DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did " + ("not return a Promise of an Array: " + String(values) + ".")); } if (values.length !== batch.keys.length) { throw new TypeError("DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys." + ("\n\nKeys:\n" + String(batch.keys)) + ("\n\nValues:\n" + String(values))); } resolveCacheHits(batch); for (var i = 0; i < batch.callbacks.length; i++) { var value = values[i]; if (value instanceof Error) { batch.callbacks[i].reject(value); } else { batch.callbacks[i].resolve(value); } } })["catch"](function(error) { failedDispatch(loader, batch, error); }); } function failedDispatch(loader, batch, error) { resolveCacheHits(batch); for (var i = 0; i < batch.keys.length; i++) { loader.clear(batch.keys[i]); batch.callbacks[i].reject(error); } } function resolveCacheHits(batch) { if (batch.cacheHits) { for (var i = 0; i < batch.cacheHits.length; i++) { batch.cacheHits[i](); } } } function getValidMaxBatchSize(options) { var shouldBatch = !options || options.batch !== false; if (!shouldBatch) { return 1; } var maxBatchSize = options && options.maxBatchSize; if (maxBatchSize === void 0) { return Infinity; } if (typeof maxBatchSize !== "number" || maxBatchSize < 1) { throw new TypeError("maxBatchSize must be a positive number: " + maxBatchSize); } return maxBatchSize; } function getValidBatchScheduleFn(options) { var batchScheduleFn = options && options.batchScheduleFn; if (batchScheduleFn === void 0) { return enqueuePostPromiseJob; } if (typeof batchScheduleFn !== "function") { throw new TypeError("batchScheduleFn must be a function: " + batchScheduleFn); } return batchScheduleFn; } function getValidCacheKeyFn(options) { var cacheKeyFn = options && options.cacheKeyFn; if (cacheKeyFn === void 0) { return function(key) { return key; }; } if (typeof cacheKeyFn !== "function") { throw new TypeError("cacheKeyFn must be a function: " + cacheKeyFn); } return cacheKeyFn; } function getValidCacheMap(options) { var shouldCache = !options || options.cache !== false; if (!shouldCache) { return null; } var cacheMap = options && options.cacheMap; if (cacheMap === void 0) { return /* @__PURE__ */ new Map(); } if (cacheMap !== null) { var cacheFunctions = ["get", "set", "delete", "clear"]; var missingFunctions = cacheFunctions.filter(function(fnName) { return cacheMap && typeof cacheMap[fnName] !== "function"; }); if (missingFunctions.length !== 0) { throw new TypeError("Custom cacheMap missing methods: " + missingFunctions.join(", ")); } } return cacheMap; } function getValidName(options) { if (options && options.name) { return options.name; } return null; } function isArrayLike(x) { return typeof x === "object" && x !== null && typeof x.length === "number" && (x.length === 0 || x.length > 0 && Object.prototype.hasOwnProperty.call(x, x.length - 1)); } module.exports = DataLoader2; } }); var import_dataloader = __toESM(require_dataloader(), 1); var iconCache = /* @__PURE__ */ new Map(); var MISSING = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-circle animate-pulse"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>'; var defaultLibraries = { default: "https://icons.clickncode.com/icons/heroicons/{icon}.svg", b: "https://icons.clickncode.com/icons/bootstrap/{icon}.svg", e: "https://icons.clickncode.com/icons/entypo/{icon}.svg", f: "https://icons.clickncode.com/icons/feathers/{icon}.svg", fa: "https://icons.clickncode.com/icons/fontawesome/{icon}.svg", h: "https://icons.clickncode.com/icons/heroicons/{icon}.svg", z: "https://icons.clickncode.com/icons/zondicons/{icon}.svg" }; var iconLoader = new import_dataloader.default( async (iconNames) => { const results = await fetch("/_uplandjs/icons/batch", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(iconNames) }).then((res) => res.json()); const resultMap = new Map(results.map((r) => [r.name, r.svg])); return iconNames.map((iconName) => resultMap.get(iconName) ?? MISSING); }, { batch: true, cache: true } ); function loadIcon(iconName) { try { const expires = parseInt(localStorage.getItem(`icon-${iconName}-expires`) ?? "0"); if (expires > Date.now()) { const localIcon = localStorage.getItem(`icon-${iconName}`) ?? null; const divEl = document.createElement("div"); divEl.innerHTML = localIcon; return Promise.resolve(divEl.firstElementChild); } } catch (err) { console.error(err); } let promisedIcon; if (iconName.match(/^[^:]+:[^:]+$/)) { const parts = iconName.split(":", 2); const libName = parts.length === 1 ? "default" : parts[0]; const name = parts.length === 1 ? parts[0] : parts[1]; const libMap = new Map(Object.entries(defaultLibraries)); const urlTemplate = libMap.get(libName); if (!urlTemplate) return reject(new Error("invalid icon lib: " + libName)); iconUrl = urlTemplate.replace("{icon}", name); promisedIcon = fetch(iconUrl).then((res) => res.status >= 400 ? MISSING : res.text()); } else if (iconName.match(/^[^/]+\/[^/]+$/)) { promisedIcon = iconLoader.load(iconName); } else if (iconName.match(/^[a-z]+$/)) { promisedIcon = fetch(`https://icons.clickncode.com/icons/heroicons/${iconName}.svg`).then( (res) => res.status >= 400 ? MISSING : res.text() ); } else { promisedIcon = Promise.resolve(MISSING); } return promisedIcon.then( (svg) => svg.replace('width="1em"', "").replace('height="1em"', "").replace("<svg ", '<svg width="100%" height="100%" ') ).then((svg) => { try { localStorage.setItem(`icon-${iconName}`, svg); localStorage.setItem(`icon-${iconName}-expires`, Date.now() + 36e5 * 12); } catch (err) { console.error(err); } const divEl = document.createElement("div"); divEl.innerHTML = svg; return divEl.firstElementChild; }); } var cnc_icon_default = { name: "", label: "", size: "md", _svg: "", load(name) { const $img = this.$el.querySelector('[x-ref="img"]'); if (!$img) return; const svgChild = $img.firstElementChild; if (svgChild?.dataset.iconName === name) return; if (!name) { $img.innerHTML = ""; return; } let loadSvg; if (iconCache.has(name)) { loadSvg = iconCache.get(name); } else { loadSvg = loadIcon(name); iconCache.set(name, loadSvg); } loadSvg.then((svgEl) => { $img.innerHTML = ""; $img.append(svgEl.cloneNode(true)); $img.firstElementChild.setAttribute("data-icon-name", name); }); }, init() { if (!this.load) { return; } this.load(this.name); this.$watch("name", (name) => this.load(name)); } }; function parseUrl(url) { const targets = []; let filter = ""; const [rootPath, targetPaths] = url.split("?"); if (targetPaths) { const searchParams = new URLSearchParams(`?${targetPaths}`); for (const [key, value] of searchParams.entries()) { if (key.startsWith("__")) { targets.push({ name: key.slice(2), href: value }); } else if (key === "filter") { filter = value; } } } return { rootPath, targets, filter }; } var cnc_block_default = { name: "", href: "", autosize: false, // used in $call to target server controller _callBaseHref: "", _blockWidth: 400, _blockHeight: 300, _oldOffsetWidth: 0, _initialHref: "", init() { this._initialHref = this.href; this.name ??= "b" + Math.round(Math.random() * Number.MAX_SAFE_INTEGER); const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(`__${this.name}`)) { this.href = urlParams.get(`__${this.name}`); this.$el.setAttribute("href", this.href); } else { const navigationId = urlParams.get(`__nav`); if (navigationId && this.navigationMenu?.children?.length) { const matchedNavigationMenu = findNode(this.navigationMenu, (node) => { if (node.id === navigationId) return node; }); if (matchedNavigationMenu?.href) { const { targets } = parseUrl(matchedNavigationMenu.href); const currentTarget = targets.find((t) => t.name === this.name); currentTarget?.href && this.$el.setAttribute("href", currentTarget.href); } } } this.$watch("href", (...args) => { console.log("href changed", args); this.loadContent(...args); }); if (this.href) this.loadContent(this.href); }, async loadContent(href) { document.body.classList.add("!cursor-progress"); this._callBaseHref = href; const propBindings = [...this.$el.parentElement.attributes].filter((a) => a.name.startsWith("x-prop:")); let language = "en"; if (this.$session?.language) { language = this.$session?.language; const daysToExpire = 365; let expiryDate = new Date(); expiryDate.setTime(expiryDate.getTime() + daysToExpire * 24 * 60 * 60 * 1e3); const expires = "expires=" + expiryDate.toUTCString(); document.cookie = "x-language=" + language + ";" + expires + ";path=/"; } const html = await fetch(href, { headers: { "cnc-block-id": this.name, "x-widgets": Array.from(WidgetElement.widgets)?.join(",") ?? "", "x-language": language } }).then((res) => res.text()).then((html2) => html2.replace(/(\s+)@click=/g, "$1x-on:click=")); const divEl = document.createElement("div"); divEl.innerHTML = html; for (const scriptEl of divEl.querySelectorAll("script")) { await Upland.runScript(scriptEl); } for (const styleEl of divEl.querySelectorAll("style")) { document.body.append(styleEl); } await until(() => this.$refs.content && this.$refs.content.getAttribute("name") === this.name, 5e3); if (!this.$refs.content) { return; } let newPage = document.createElement("div"); for (let child of [...divEl.childNodes]) { newPage.appendChild(child); } newPage.classList.add("blockcontent"); this.$refs.content.textContent = ""; this.$refs.content.appendChild(newPage); const firstElChild = this.$refs.content.firstElementChild; for (const attr of propBindings) { firstElChild.setAttribute(attr.name, attr.value); } document.body.classList.remove("!cursor-progress"); }, // setContainerWidth() { // let blockWidth // if (this.autosize) { // blockWidth = this.$refs.content.offsetWidth || 50 // } else { // blockWidth = this.$refs.content.parentElement.offsetWidth // } // //console.log('---- blockWidth', blockWidth, this.href) // if (this._oldOffsetWidth === blockWidth && blockWidth !== 0) return // this._blockWidth = blockWidth // this.$refs.content.style.setProperty('--block-width', this._blockWidth + 'px') // this._oldOffsetWidth = this.autosize // ? this.$refs.content.offsetWidth || 50 // : this.$refs.content.parentElement.offsetWidth // }, // _handleResize() { // this.setContainerWidth() // }, _handleUrlChange() { const urlParams = new URLSearchParams(window.location.search); const urlParamId = `__${this.name}`; let newHref; if (urlParams.has(urlParamId)) { newHref = urlParams.get(urlParamId); } else if (this._initialHref) { newHref = this._initialHref; } if (newHref !== this.href) { this.href = newHref; this.$el.setAttribute("href", this.href); } } }; function until(predicate, timeout) { let untilId; return new Promise((resolve, reject2) => { if (predicate()) return resolve(); untilId = setInterval(() => predicate() && resolve(), 1); setTimeout(() => reject2(new Error("timeout")), timeout); }).finally(() => { if (untilId) clearInterval(untilId); }); } function findNode(node, predicate) { function _findNode(node2, parent) { let result = null; if (predicate(node2, parent)) return predicate(node2, parent); if (Array.isArray(node2.children) && node2.children.length > 0) { node2.children.some((child) => { result = _findNode(child, node2); return result; }); } return result; } return _findNode(node, null); } var cnc_modal_default = { open: true, label: "", autoClose: "", _autoClose: true, init() { this._autoClose = this.autoClose === "off" ? false : true; } }; var cnc_alert_default = { kind: "primary", title: "", icon: "", accented: false, content: "", closable: false, _closed: false, get _iconName() { switch (this.kind) { case "info": return "fa:info-circle-solid"; case "primary": return "b:person-fill"; case "warning": return "e:warning"; case "danger": return "z:close-solid"; case "success": return "f:check-circle"; default: return "h:information-circle-solid"; } }, close() { this._closed = true; this.$dispatch("closed", {}); } }; var scriptImports = globalThis.scriptImports || (globalThis.scriptImports = /* @__PURE__ */ new Map()); function validate(event) { if (!this.name) return; if (!this.$data.errors) return; delete this.$data.errors[this.name]; for (const validation of this.validations) { if (event && validation.on !== event) continue; if (!validation.validate(this.value)) { this.$data.errors[this.name] = `validation.${validation.name}`; break; } } } var spec = { plain: false, accept: "*", autocapitalize: "", autocomplete: "", autocorrect: "", autofocus: false, clearable: false, disabled: false, inputmode: "", get error() { return this.errors?.[this.name]; }, get hasError() { return this.errors && this.errors[this.name]; }, get _outerPrefix() { return this.$parent?.$slots.outerPrefix; }, get _outerSuffix() { return this.$parent?.$slots.outerSuffix; }, validations: [], invalid: false, isPasswordVisible: false, mask: null, stripMask: "", max: void 0, maxlength: void 0, min: void 0, minlength: 0, name: "", pattern: void 0, pill: false, placeholder: "", prefixIcon: "", suffixIcon: "", readonly: false, spellcheck: false, required: false, skipRequiredValidation: false, step: void 0, type: "text", //'email','number','password','search','tel','text','url' value: "", live: true, options: [], _maskFilled: "", _maskUnfilled: "", _maskedValue: "", _maskedValueHtml: "", _trimmedValue: "", _error: "", // TODO: this should not be handled this way should be in errors from scope _openOptions: false, async init() { if (this.type === "color") { this.type = "text"; } if (this.options.length === 1 && !this.options[0].value) { this.options = []; } if (this.options.length && this.options.every((o) => typeof o === "string" || typeof o === "number")) { this.options = this.options.map((o) => ({ text: o, value: o })); } const inbuiltValidations = []; if (this.required && !this.skipRequiredValidation) { inbuiltValidations.push({ name: "required", on: "blur", validate(value) { return Boolean(value) && value !== ""; } }); } if (!this.$el.closest("cnc-drop") && !this.$el.closest("cnc-signature") && !this.$el.closest("cnc-input-rating") && !this.$el.closest("cnc-select")) { this.plain = !!this.$el.closest("cnc-field") || this.plain; } if (typeof this.mask === "string") { const mask = this.mask; this.mask = buildMask(this.mask); } if (this.mask) { const { mask } = this.mask; if (mask) { inbuiltValidations.push({ name: "invalidmask", on: "blur", validate(value) { const result = mask(value); return Boolean(result) && !result?.unfilled?.includes("_"); } }); } } if (inbuiltValidations.length) { this.validations = [...inbuiltValidations, ...this.validations]; } if (typeof this.value === "undefined") { this.value = ""; } if (this.multiple && this.type === "file") { if (!Array.isArray(this.value)) { this.value = [this.value].filter(Boolean); } } if (this.value) { this._changed(this.value, this.$refs.input); } this.$watch("value", (newValue) => { if (typeof newValue === "undefined") return; this._changed(this.value ?? "", this.$refs.input); }); this.$watch("mask", () => { this._changed(this.value ?? "", this.$refs.input); }); }, validate, handleBlur() { if (typeof this.value === "string") { this.value.trim(); this.validate("blur"); this.$el.parentElement.dispatchEvent(new InputEvent("blur", { bubbles: true })); } else if (this.value === null) { this.validate("blur"); this.$el.parentElement.dispatchEvent(new InputEvent("blur", { bubbles: true })); } }, _clear($event) { $event.preventDefault(); $event.stopPropagation(); if (this.type == "number") { this.value = 0; } else if (this.type == "date") { this.value = null; } else { this.value = ""; this._changed(this.value, this.$refs.input); } this.$refs.input.focus(); this.$dispatch("cleared", {}); }, async _changed(newValue, el) { if (this.mask) { newValue = newValue.toString(); const unmasked = this.mask.unmask.call(this, newValue); this.value = unmasked; const beforeCursor = newValue.substring(0, el.selectionStart); const unmaskedBefore = this.mask.unmask.call(this, beforeCursor); const masking = this.mask.mask.call(this, unmasked); this._maskFilled = masking.filled; this._maskUnfilled = masking.unfilled; if (el.selectionStart !== newValue.length) { const filled = masking.filled; let pos = 0; const beforeLetters = unmaskedBefore.split("").filter((x) => x); for (const letter of beforeLetters) { while (filled[pos] && filled[pos] !== letter) { pos++; } if (filled[pos]) { pos++; } } this.$nextTick(() => { el.selectionStart = pos; el.selectionEnd = pos; }); } el.value = masking.filled; return; } if (this.type === "number") newValue = parseFloat(newValue); if (this.type === "uuid") { const uuidRegex = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"; if (!newValue.match(uuidRegex) && newValue.length) { this._error = "This is not a valid UUID"; } else { this._error = ""; } } if (this.type === "file") { const fileObj = []; for (const file of el.files) { const formData = new FormData(); formData.append("file", file); try { const result = await fetch("/_uplandjs/uploads", { method: "post", body: formData, headers: { "x-bucket-path": window.location.pathname } }).then((res) => res.json()); fileObj.push(result); } catch (err) { console.debug(err); } } this.value = fileObj; } else if (this.multiple && this.type === "file") { this.value = newValue; } else { this.value = newValue; } }, keyDown(event) { if (!this.mask || !this.value) return; if (event.key === "Backspace") { const { selectionStart } = this.$refs.input; if (selectionStart === 0) return; const startValue = event.target.value; const beforeCursor = startValue.substring(0, selectionStart); const unmaskedEverything = this.mask.unmask.call(this, startValue); const unmaskedBefore = this.mask.unmask.call(this, beforeCursor); const unmaskedAfter = unmaskedEverything.substring(unmaskedBefore.length); const newBefore = unmaskedBefore.substring(0, unmaskedBefore.length - 1); const newValue = newBefore + unmaskedAfter; const masked = this.mask.mask.call(this, newValue); this._maskFilled = masked.filled; this._maskUnfilled = masked.unfilled; this.value = this.mask.unmask.call(this, newValue); const filled = masked.filled; let pos = 0; const beforeLetters = newBefore.split("").filter((x) => x); for (const letter of beforeLetters) { while (filled[pos] && filled[pos] !== letter) { pos++; } if (filled[pos]) { pos++; } } this.$nextTick(() => { event.target.selectionStart = pos; event.target.selectionEnd = pos; }); event.stopPropagation(); event.preventDefault(); } }, showOptions() { this.$refs.inputoptions.style.width = this.$el.clientwidth + "px"; this.$refs.inputoptions.style.top = this.$el.clientheight + "px"; }, hideOptions() { if (this.$refs.inputoptions) { this.$refs.inputoptions.style.display = ""; } }, toggleOptions(event) { event?.stopPropagation(); if (this.disabled) return; this._openOptions = !this._openOptions; if (this._openOptions) { this.showOptions(); } else { this.hideOptions(); } }, selectValue(value) { this.$cncInput.value = value; this.$dispatch("optionselected", { value }); this.toggleOptions(); } }; function buildMask(mask) { return { mask(value) { const masked = applyMask(value, mask); const firstUnfilled = masked.indexOf("_"); const filled = firstUnfilled === -1 ? masked : masked.substring(0, firstUnfilled); const unfilled = firstUnfilled === -1 ? "" : masked.substring(firstUnfilled); return { filled, unfilled }; }, unmask(masked) { return mask.split("").map((c, index) => masked[index] !== c ? masked[index] : null).filter((x) => x).join(""); } }; } function applyMask(rawInput, rawFormat) { let format = rawFormat; if (typeof rawFormat === "function") { const result = rawFormat(rawInput); format = result.format; rawInput = result.value ?? rawInput; } if (!format) return rawInput; const inputChars = rawInput.split(""); const masked = format.split("").map((c) => { switch (c) { case "#": return popDigit() || "_"; case "A": return popLetter() || "_"; case "H": return popHexaDecimal() || "_"; case "*": return inputChars.shift() || "_"; default: return c; } }).join(""); return masked; function popDigit() { const digit = inputChars.shift(); return digit && digit.match(/\d/) ? digit : null; } function popLetter() { const letter = inputChars.shift(); return letter && letter.match(/[a-z]/i) ? letter : null; } function popHexaDecimal() { const letter = inputChars.shift(); return letter && letter.match(/[\da-f]/i) ? letter : null; } } var fields = Object.fromEntries( Object.entries(spec).filter(([name, val]) => { return !name.startsWith("_") && typeof val !== "function"; }) ); var cnc_field_default = { ...fields, label: "", labelPosition: "top", // supports: top, floating, left value: "", type: "string", as: "", helpText: "", noIcon: false, swatches: [], colorWheel: null, //Type boolean // As checkbox checked: false, indeterminate: false, kind: "default", // "default" | "primary" | "danger" | "info" | "success" | "warning" // As toggle enabled: false, //Type string options: [], // As dropdown limit: 0, multiple: false, searchable: false, icon: "", hint: "", create: null, initialText: "", // As radios horizontal: false, // As Checkboxes and radios text: "", // Type longtext resize: "vertical", //('vertical', 'auto', 'none') rows: 4, // Type map pins: [], circles: [], polygons: [], // Type phone defaultPrefix: "1", defaultCountry: null, // Type qr dotColor: "#000", image: "", dotType: "rounded", backgroundColor: "#f8fafc", cornerSquareColor: "#000", cornerSquareType: "square", cornerDotColor: "#000", cornerDotType: "square", imageMargin: 5, //Type range min: 0, max: 10, step: 1, tick: false, noLegend: false, //Type number as rating precision: 1, color: "yellow", // Type upload meta: {}, holidays: [], maxSize: 0, autoUpload: false, removeUpload: false, draggable: false, togglable: true, capture: "", sizes: [100, 200, 300, 400], errors: {}, className: "", _error: "", // TODO: handle this in errors from scope _values: [], _texts: [], _focused: false, get _labelFloatTop() { if (this.labelPosition !== "floating") return false; let empty = !this.value || this._values.length === 0; if (this._values.length === 1) { empty = this._values[0] == ""; } let floatingTop = !empty || this._focused || _allwaysFullTypes.includes(this.type); if (!floatingTop && this.type === "string" && // ['dropdown', 'radio', 'checkbox'].includes(this.as) ["radio", "checkbox"].includes(this.as)) { floatingTop = true; } return floatingTop; }, get _needsFloatingSpace() { return this.labelPosition === "floating" && !["dropdown", "radio", "checkbox"].includes(this.as); }, outerPrefix: false, outerSuffix: false, async init() { await Upland.installWidget("cnc-input-" + this.type); if (this._needsFloatingSpace) this.placeholder = ""; if (!this.$slots.default) { const widgetBuilder = `cncInput${this.type.split("-").map((s) => s[0].toUpperCase() + s.substring(1)).join("")}`; let innerHTML = ""; switch (this.type) { case "string": { if (this._showAdd) { innerHTML = `<cnc-input-${this.type} x-data:widget="${widgetBuilder}($el)" x-prop="$widget" x-prop:value="_values[index]" x-slotted="[]"></cnc-input-${this.type}>`; } else { innerHTML = `<cnc-input-${this.type} x-data:widget="${widgetBuilder}($el)" x-prop="$widget" x-prop:value="value" x-slotted="[]"></cnc-input-${this.type}>`; } } break; case "boolean": { innerHTML = `<cnc-input-${this.type} x-data:widget="${widgetBuilder}($el)" x-prop:text="_texts[index]" x-prop="$widget" x-prop:value="_values[index]" x-slotted="[]"></cnc-input-${this.type}>`; } break; case "date": case "file": case "image": { innerHTML = `<cnc-input-${this.type} x-data:widget="${widgetBuilder}($el)" x-prop="$widget" x-prop:value="value" x-slotted="[]"></cnc-input-${this.type}>`; } break; case "credit-card-number": { innerHTML = `<cnc-input-${this.type} x-data:widget="${widgetBuilder}($el)" x-prop="$widget" x-prop:value="_values[index]" class="w-full" x-slotted="[]"></cnc-input-${this.type}>`; } break; default: { innerHTML = `<cnc-input-${this.type} x-data:widget="${widgetBuilder}($el)" x-prop="$widget" x-prop:value="_values[index]" x-slotted="[]"></cnc-input-${this.type}>`; } } this.$refs.innerInputs?.content.querySelector(".--cnc-field_inputs").insertAdjacentHTML("beforeend", innerHTML); this.$el.querySelectorAll(".--cnc-field_inputs").forEach((el) => { el.insertAdjacentHTML("beforeend", innerHTML); }); } if (typeof this.value === "undefined") { this.value = ""; } if (this.className) { const classes = Array.isArray(this.className) ? this.className.join(",") : this.className; this.$el.classList.add(classes); } if (this.type === "boolean" && this.multiple) { console.warn("Boolean does not support multiple"); } if (this.$slots.outerPrefix) this.outerPrefix = true; if (this.$slots.outerSuffix) this.outerSuffix = true; this._updateValues(); this._updateTexts(); this.$watch("value", () => { this._updateValues(); this._updateTexts(); }); this.$watch("_values", () => { if (this._values.filter((v) => v || v === false || v === 0 || v === "").length) { if (this.multiple) { if (this._showAdd) { this.value = this._values; } } else { this.value = this._values[0]; } } }); this.$watch("_texts", () => { if (this._texts.filter((v) => v || v === false || v === 0 || v === "").length) { if (this.multiple) { if (this._showAdd) { this.text = this._texts; } } else { this.text = this._texts[0]; } } }); if (this.as === "dropdown" && !this.suffixIcon) { this.suffixIcon = "h:chevron-down"; } }, get _showAdd() { if (!this.multiple) return false; switch (this.type) { case "string": { if (["checkboxes", "dropdown"].includes(this.as)) { return false; } return true; } case "date": case "file": case "image": case "timezone": return false; default: return true; } }, get _showBorder() { if (this.type === "number" && this.as === "number") return true; if (_borderlessTypes.includes(this.type)) return false; switch (this.type) { case "string": { if (this.as === "string" || this.as === "textbox") { return true; } if (this.as) { return false; } return true; } default: return true; } }, _getValues() { switch (this.type) { case "date": case "file": case "image": case "timezone": return [1]; case "string": if (this.as === "dropdown") return [1]; default: return this._values; } }, _updateValues() { this._values = Array.isArray(this.value) ? this.value.length ? this.value : [null] : [this.value]; }, _updateTexts() { this._texts = Array.isArray(this.text) ? this.text.length ? this.text : [null] : [this.text]; }, _add(event, fromKeypress = false) { if (this._values.every((v) => v)) { this._values.push(null); this._texts.push(null); this.$nextTick(() => { setTimeout(() => { let lastInputEl; if (fromKeypress) { lastInputEl = this.$el.parentElement.parentElement.querySelector("div.relative:last-of-type"); } else { lastInputEl = this.$el.parentElement.querySelector("div.relative:last-of-type"); } if (lastInputEl) lastInputEl.querySelector("input").focus(); }, 100); }); } }, _remove(index) { this._values.splice(index, 1); this._texts.splice(index, 1); }, get error() { return this.errors?.[this.name]; }, get hasError() { return this.errors && this.errors[this.name]; }, _keypress(event) { if (event.keyCode == 13 && this._showAdd) { console.log("_keypress"); this._add(event, true); } } }; var _borderlessTypes = [ "range", "toggle", "boolean", "radio", "upload", "signature", "code", "file", "image", "date", "avatar" ]; var _allwaysFullTypes = ["byte", "credit-card-number", "file", "image", "signature", "avatar"]; window.process = { env: "dev" }; var triggerEvents = { // focus: 'blur', click: "click.outside", mouseenter: "mouseleave" }; var cnc_tooltip_default = { content: "", placement: "top", _placement: "", // actual placement after floating ui has a go at placing things arrow: true, offset: 6, trigger: "mouseenter", theme: "", interactive: false, showToolTip: false, async init() { if (this.content || this.$slots.content) { const parentEL = this.$refs.reference.parentElement.parentElement; const parentZindex = window.getComputedStyle(parentEL).zIndex; this._update(); this.$watch("showToolTip", (newVal) => { this._update(); if (newVal) { parentEL.style.zIndex = 999; } else { setTimeout(() => { parentEL.style.zIndex = parentZindex || 0; }, 250); } }); if (this.theme == "") { this._updateMode(); this.$watch("$session.mode", () => { console.log(this.$session.mode); this._updateMode(); }); } } }, _updateMode() { if (this.$session.mode === "dark") { this.theme = "light"; } else { this.theme = "dark"; } }, toggle($event, value) { if (this.content || this.$slots.content) { const triggers = this.trigger.split(" ") || []; const eventNames = []; for (const trigger of triggers) { eventNames.push(trigger); eventNames.push(triggerEvents[trigger]); } if (!eventNames.includes($event.type)) return; this.showToolTip = value; } }, async _update() { const referenceEl = this.$refs.reference; const floatingEl = this.$refs.tooltip; const arrowElement = this.$refs.arrow; const { offset, flip, shift, arrow, computePosition } = await this.$bundle("floating-ui.mjs"); const middleware = [offset(this.offset), flip(), shift()]; if (arrowElement) { middleware.push(arrow({ element: arrowElement })); } this.$nextTick(() => { computePosition(referenceEl, floatingEl, { placement: this.placement, middleware }).then(({ x, y, placement, middlewareData }) => { Object.assign(floatingEl.style, { left: `${x}px`, top: `${y}px` }); if (arrowElement) { const { x: arrowX, y: arrowY } = middlewareData.arrow; const staticSide = { top: "bottom", right: "left", bottom: "top", left: "right" }[placement.split("-")[0]]; this._placement = placement.split("-")[0]; Object.assign(arrowElement.style, { left: arrowX != null ? `${arrowX}px` : "", top: arrowY != null ? `${arrowY}px` : "", right: "", bottom: "", [staticSide]: "-4px" }); } }); }); } }; var defaultClasses = { plain: "bg-none hover:text-neutral-700 focus:outline-none shadow-none dark:text-white aria-[pressed=true]:text-white", default: "shadow-sm bg-black/5 hover:bg-black/10 aria-pressed:bg-black/20 hover:text-neutral-900 aria-pressed:text-neutral-900 dark:text-white/70 dark:hover:text-white/80 dark:aria-pressed:text-white dark:bg-white/5 dark:hover:bg-white/10 dark:aria-pressed:bg-white/20", danger: "shadow-sm text-white bg-danger-500 hover:bg-danger-700", primary: "shadow-sm text-white bg-primary-500 hover:bg-primary-700", secondary: "shadow-sm text-white bg-secondary-600 hover:bg-secondary-700" }; var outlineClasses = { plain: "border border-neutral-300 dark:border-neutral-700 bg-none text-neutral-500 dark:text-neutral-300 hover:text-neutral-800 dark:hover:text-white duration-300", default: "shadow-sm border border-neutral-500 dark:border-neutral-600 text-neutral-600 dark:text-neutral-300 hover:bg-neutral-500 hover:text-white dark:hover:text-white duration-300", danger: "shadow-sm border border-danger-500 dark:border-danger-600 text-danger-600 dark:text-danger-500 hover:bg-danger-500 hover:text-white dark:hover:text-white duration-300", primary: "shadow-sm border border-primary-500 dark:border-primary-600 text-primary-600 dark:text-primary-500 hover:bg-primary-500 hover:text-white dark:hover:text-white duration-300", secondary: "shadow-sm border border-secondary-500 dark:border-secondary-600 text-secondary-600 dark:text-secondary-500 hover:bg-secondary-500 hover:text-white dark:hover:text-white duration-300" }; var cnc_button_default = { pressed: false, ring: false, wide: false, caret: false, disabled: false, label: "", icon: "", size: "md", submit: false, kind: "default", shape: "rounded", // circle , square , pill outline: false, value: "", name: "", pulse: false, processing: false, borderline: false, kindToColor: { default: "neutral", plain: "neutral", danger: "danger", warning: "warning", success: "success", info: "info" //primary: 'teal' }, // get styleClasses() { // return styleClasses[this.kind] || styleClasses.default // }, // get outlineClasses() { // return outlineClasses[this.kind] || outlineClasses.default // }, // get ringClasses() { // return ringClasses[this.kind] || ringClasses.default // }, init() { if (!this.kind || this.kind == "") this.kind = "default"; }, styleClasses() { let color = this.kindToColor[this.kind] || this.kind; let classes = ""; if (this.outline) { classes += " " + (outlineClasses[this.kind] ? outlineClasses[this.kind] : `border border-${color}-500 dark:border-${color}-600 text-${color}-600 dark:text-${color}-500 hover:bg-${color}-500 hover:text-${color}-700 dark:hover:text-white duration-300`); } else { classes += " " + (defaultClasses[this.kind] ? defaultClasses[this.kind] : `text-white bg-${color}-500 hover:bg-${color}-600`); } if (this.ring) { classes += ` focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-${color}-500`; } if (this.borderline && this.kind !== "plain" && !this.outline) { classes += ` border border-${color}-400 dark:border-${color}-300`; } if (this.pulse) classes += " animate-pulse"; switch (this.shape) { case "pill": classes += " rounded-xl"; break; case "circle": classes += " rounded-full"; break; case "rectangle": classes += " rounded-none"; break; case "rounded": if (this.size == "sm" || this.size == "xs") { classes += " rounded-sm"; } else { classes += " rounded-md"; } break; default: if (this.size == "sm" || this.size == "xs") { classes += " rounded-sm"; } else { classes += " rounded-md"; } } if (this.disabled || this.processing) { classes += " opacity-50 cursor-not-allowed italic"; } if (this.wide) { classes += " justify-center w-full"; } switch (this.size) { case "xs": classes += " px-1 py-1 text-xs"; break; case "sm": classes += " px-1.5 py-1 text-sm"; break; case "md": classes += " px-2 py-1.5 text-base "; break; case "lg": classes += " px-3 py-1 text-lg"; break; case "xl": classes += " px-3 py-1 text-xl"; break; case "2xl": classes += " px-3 py-1 text-2xl"; break; default: classes += " px-1.5 py-1.5 text-sm"; } return classes; }, searchForClasses(classesString) { let classArray = classesString.split(" "); for (let i = 0; i < classArray.length; i++) { if (classArray[i] === "") continue; let classModifiersArray = classArray[i].split(":"); let searchClass = classModifiersArray[classModifiersArray.length - 1]; let found = this.searchForCss(searchClass); if (!found) console.log("class: ", searchClass, found); } }, searchForCss(searchClassName) { let found = false; for (let i = 0; i < document.styleSheets.length; i++) { let styleSheet = document.styleSheets[i]; try { for (let j = 0; j < styleSheet.cssRules.length; j++) { let rule = styleSheet.cssRules[j]; if (rule.selectorText) { if (rule.selectorText.replace("\\/", "/").includes(searchClassName)) { found = true; } } } if (!found && styleSheet.imports) { for (let k = 0; k < styleSheet.imports.length; k++) { let imp = styleSheet.imports[k]; for (let l = 0; l < imp.cssRules.length; l++) { let rule = imp.cssRules[l]; console.log(rule.selectorText, rule.selectorText.replace("/", "/")); if (rule.selectorText && rule.selectorText.includes(searchClassName)) { found = true; } } } } } catch (err) { } } return found; } }; // <stdin> if (!window.customElements.get("cnc-icon")) { const factory = WidgetData.buildFactory(typeof cnc_icon_default === "undefined" ? {} : cnc_icon_default); Alpine.data("cncIcon", factory); WidgetElement.widgets.add("cnc-icon"); class cncIconWidget extends WidgetElement { } customElements.define("cnc-icon", cncIconWidget); } if (!window.customElements.get("cnc-block")) { const factory = WidgetData.buildFactory(typeof cnc_block_default === "undefined" ? {} : cnc_block_default); Alpine.data("cncBlock", factory); WidgetElement.widgets.add("cnc-block"); class cncBlockWidget extends WidgetElement { } customElements.define("cnc-block", cncBlockWidget); } if (!window.customElements.get("cnc-modal")) { const factory = WidgetData.buildFactory(typeof cnc_modal_default === "undefined" ? {} : cnc_modal_default); Alpine.data("cncModal", factory); WidgetElement.widgets.add("cnc-modal"); class cncModalWidget extends WidgetElement { } customElements.define("cnc-modal", cncModalWidget); } if (!window.customElements.get("cnc-alert")) { const factory = WidgetData.buildFactory(typeof cnc_alert_default === "undefined" ? {} : cnc_alert_default); Alpine.data("cncAlert", factory); WidgetElement.widgets.add("cnc-alert"); class cncAlertWidget extends WidgetElement { } customElements.define("cnc-alert", cncAlertWidget); } if (!window.customElements.get("cnc-field")) { const factory = WidgetData.buildFactory(typeof cnc_field_default === "undefined" ? {} : cnc_field_default); Alpine.data("cncField", factory); WidgetElement.widgets.add("cnc-field"); class cncFieldWidget extends WidgetElement { } customElements.define("cnc-field", cncFieldWidget); } if (!window.customElements.get("cnc-tooltip")) { const factory = WidgetData.buildFactory(typeof cnc_tooltip_default === "undefined" ? {} : cnc_tooltip_default); Alpine.data("cncTooltip", factory); WidgetElement.widgets.add("cnc-tooltip"); class cncTooltipWidget extends WidgetElement { } customElements.define("cnc-tooltip", cncTooltipWidget); } if (!window.customElements.get("cnc-button")) { const factory = WidgetData.buildFactory(typeof cnc_button_default === "undefined" ? {} : cnc_button_default); Alpine.data("cncButton", factory); WidgetElement.widgets.add("cnc-button"); class cncButtonWidget extends WidgetElement { } customElements.define("cnc-button", cncButtonWidget); } })(); </script><style>cnc-icon{display:inline-block;height:var(--size-4);overflow:visible;width:var(--size-4)}cnc-icon svg{overflow:visible}cnc-icon[size=full]{height:100%;width:100%}.text-xs cnc-icon,cnc-icon[size=xs]{height:var(--size-3);width:var(--size-3)}.text-sm cnc-icon,cnc-icon[size=sm]{height:var(--size-3-5);width:var(--size-3-5)}.text-base cnc-icon,cnc-icon[size=md]{height:var(--size-4);width:var(--size-4)}.text-lg cnc-icon,cnc-icon[size=lg]{height:var(--size-6);width:var(--size-6)}.text-xl cnc-icon,cnc-icon[size=xl]{height:var(--size-8);width:var(--size-8)}.text-2xl cnc-icon,cnc-icon[size="2xl"]{height:var(--size-12);width:var(--size-12)}.text-3xl cnc-icon,cnc-icon[size="3xl"]{height:var(--size-16);width:var(--size-16)}cnc-block,cnc-block div.blockcontent{display:flex;flex:1 1 0%;flex-direction:column}cnc-block div.blockcontent{overflow:auto;position:relative}cnc-alert{display:block}cnc-field cnc-input{background-color:inherit!important}cnc-button button>:not([hidden]):not(template)~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(var(--size-1)*(1 - var(--tw-space-x-reverse)));margin-right:calc(var(--size-1)*var(--tw-space-x-reverse))}</style></head> <body x-data="{ opens: true, proseTheme: 'theme1' }" class="prose dark:prose-invert bg-white h-screen" :class="{ [`prose-${proseTheme}`]: true }"><template x-controller="/login/index.mjs"> <app-toast :delay="5000" x-slotted="[]" x-data:widget="appToast($el)"><template><div> <template x-teleport="body"> <div @toast.window.prevent="add($event.detail)" class="z-50"> <div class="fixed bottom-8 right-0 m-5 w-1/2 xl:w-1/5 lg:w-1/4 md:w-2/5 sm:w-1/2 z-50"> <template x-for="notice of _notices" :key="notice.id"> <div x-show="_visible.includes(notice)" x-transition:enter="transition ease-in duration-200" x-transition:enter-start="transform opacity-0 translate-y-2" x-transition:enter-end="transform opacity-100" x-transition:leave="transition ease-out duration-500" x-transition:leave-start="transform translate-x-0 opacity-100" x-transition:leave-end="transform translate-x-full opacity-0" @mouseenter="clearTimeout(notice._timeout)" @mouseleave="notice._timeout = setTimeout(() => remove(notice.id), delay)" style="pointer-events: all" class="mb-2 max-w-md w-full bg-neutral-500 dark:bg-neutral-700 shadow-lg rounded pointer-events-auto py-4 px-5" :class="{ 'text-white bg-neutral-500 dark:bg-neutral-700': notice.kind === 'default', 'text-white bg-danger-400 dark:bg-danger-500': notice.kind === 'danger', 'text-white bg-success-500 dark:bg-success-700': notice.kind === 'success', 'text-white bg-warning-600 dark:bg-warning-800': notice.kind === 'warning', 'text-white bg-info-500 dark:bg-info-700': notice.kind === 'info', 'text-white bg-primary-600 dark:bg-primary-700': notice.kind === 'primary'}"> <div class="flex flex-row items-start"> <div class="pr-4 h-5"> <cnc-icon class="leading-none box-content rounded-full w-5 h-5" :name="notice.icon" x-slotted="[]" x-data:widget="cncIcon($el)"> <span role="img" x-ref="img" :aria-label="label || name" class="fill-current block" style="width: 100%; height: 100%"></span> </cnc-icon> </div> <div class="flex-1"> <div class="font-medium leading-tight" x-text="notice.title"></div> <template x-if="notice.message"> <div class="mt-2 text-sm font-normal" x-text="notice.message"></div> </template> </div> <div class="flex flex-row items-center select-none hover:underline cursor-pointer pl-2" @click="remove(notice.id)"> <span class="text-sm leading-5 mr-1 font-medium" x-t="toast.close">Close</span> <cnc-icon class="leading-none box-content leading-none box-content w-4 h-4" name="app/clear" x-slotted="[]" x-data:widget="cncIcon($el)"><svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon-name="app/clear"> <path d="M18.3 5.70996C18.1131 5.5227 17.8595 5.41747 17.595 5.41747C17.3305 5.41747 17.0768 5.5227 16.89 5.70996L12 10.59L7.10997 5.69996C6.92314 5.5127 6.66949 5.40747 6.40497 5.40747C6.14045 5.40747 5.8868 5.5127 5.69997 5.69996C5.30997 6.08996 5.30997 6.71996 5.69997 7.10996L10.59 12L5.69997 16.89C5.30997 17.28 5.30997 17.91 5.69997 18.3C6.08997 18.69 6.71997 18.69 7.10997 18.3L12 13.41L16.89 18.3C17.28 18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 17.28 18.3 16.89L13.41 12L18.3 7.10996C18.68 6.72996 18.68 6.08996 18.3 5.70996Z" fill="currentColor"></path> </svg></cnc-icon> </div> </div> </div> </template> </div> </div> </template> </div> </template></app-toast> <!-- to keep these classes from being pruned --> <template class="prose-theme1 prose-theme2"></template> <main class="h-full"> <cnc-block name="login_main" href="/login/login" class="h-full w-full overflow-auto h-full w-full" intent="none" x-slotted="[]" x-data:widget="cncBlock($el)" x-ref="content" @resize="_handleResize" @popstate.window="_handleUrlChange"><template></template></cnc-block> <div> <cnc-modal x-prop:open="problemReportFormModalIsOpen" auto-close="off" x-slotted="[&quot;ui&quot;]" x-data:widget="cncModal($el)"><template> <template x-if="open"> <div> <template x-teleport="body"> <div x-teleport.target="" @keydown.window.escape="open = false" x-show="open" class="fixed z-50 inset-0 overflow-y-auto" aria-labelledby="modal-title" x-ref="dialog" aria-modal="true"> <div class="flex items-center justify-center min-h-screen"> <!-- class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" --> <div x-show="open" x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-description="Background overlay, show/hide based on modal state." class="--cnc-modal__backdrop fixed inset-0 dark:bg-black/75 bg-white bg-opacity-75 transition-opacity" @click="_autoClose ? (open = false) : (open = true)" aria-hidden="true"></div> <!-- bg-neutral-500 --> <!-- This element is to trick the browser into centering the modal contents. --> <!-- <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true" >&ZeroWidthSpace;</span > --> <div x-show="open" @click.stop="" x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100" x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" x-description="Modal panel, show/hide based on modal state." class="--cnc-modal__window inline-block align-bottom dark:bg-black bg-white dark:bg-neutral-700 rounded-lg mt-1 text-left shadow-xl transform transition-all mb-64 sm:mb-0" :class="{'px-2 pb-2 sm:by-8 sm:align-middle sm:pb-4 sm:px-4' : !$slots.ui}"> <div class="px-4 py-2 pb-4 w-screen m-2 md:m-0 md:w-120"> <div class="flex flex-row items-center mb-3"> <span class="flex-1 text-xl text-black font-medium" x-t="problemReport.reportAProblem">Report a Problem</span> <div class="flex flex-row items-center text-primary-900 select-none hover:underline cursor-pointer" @click="problemReportFormModalIsOpen = false"> <span class="text-sm mr-1" x-t="opportunities.close">Close</span> <cnc-icon class="leading-none box-content leading-none box-content w-6 h-6" name="app/clear" x-slotted="[]" x-data:widget="cncIcon($el)"><svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon-name="app/clear"> <path d="M18.3 5.70996C18.1131 5.5227 17.8595 5.41747 17.595 5.41747C17.3305 5.41747 17.0768 5.5227 16.89 5.70996L12 10.59L7.10997 5.69996C6.92314 5.5127 6.66949 5.40747 6.40497 5.40747C6.14045 5.40747 5.8868 5.5127 5.69997 5.69996C5.30997 6.08996 5.30997 6.71996 5.69997 7.10996L10.59 12L5.69997 16.89C5.30997 17.28 5.30997 17.91 5.69997 18.3C6.08997 18.69 6.71997 18.69 7.10997 18.3L12 13.41L16.89 18.3C17.28 18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 17.28 18.3 16.89L13.41 12L18.3 7.10996C18.68 6.72996 18.68 6.08996 18.3 5.70996Z" fill="currentColor"></path> </svg></cnc-icon> </div> </div> <div class="max-w-full"> <template x-if="Object.keys(problemReportFormErrors)?.length > 0"> <cnc-alert class="mb-4" kind="danger" title="Failed to send report" :content="problemReportFormErrors.message || $t('problemReport.pleaseReviewYourEntries')" x-slotted="[]" x-data:widget="cncAlert($el)"><template><div x-show="!_closed" x-transition:leave="transition ease-in duration-200" x-transition:leave-end="opacity-0 scale-90" class="p-4 transition-all duration-500" :class="{ 'rounded-md' : !accented, 'bg-primary-50 hover:bg-primary-100 dark:bg-primary-200 dark:hover:bg-primary-300': kind === 'primary', 'bg-info-50 hover:bg-info-100 dark:bg-info-200 dark:hover:bg-info-300': kind === 'info', 'bg-success-50 hover:bg-success-100 dark:bg-success-200 dark:hover:bg-success-300': kind === 'success', 'bg-warning-50 hover:bg-warning-100 dark:bg-warning-200 dark:hover:bg-warning-300': kind === 'warning', 'bg-danger-50 hover:bg-danger-100 dark:bg-danger-200 dark:hover:bg-danger-300': kind === 'danger', 'border-l-4 border-primary-400 dark:border-primary-500': accented &amp;&amp; kind === 'primary', 'border-l-4 border-info-400 dark:border-info-500': accented &amp;&amp; kind === 'info', 'border-l-4 border-success-400 dark:border-success-500': accented &amp;&amp; kind === 'success', 'border-l-4 border-warning-400 dark:border-warning-500': accented &amp;&amp; kind === 'warning', 'border-l-4 border-danger-400 dark:border-danger-500': accented &amp;&amp; kind === 'danger' }"> <div class="flex"> <div class="flex-shrink-0"> <cnc-icon class="leading-none box-content leading-none box-content w-5 h-5" :name="icon? icon :_iconName" :class="{ 'text-primary-400 dark:text-primary-500': kind === 'primary', 'text-info-400 dark:text-info-500': kind === 'info', 'text-success-400 dark:text-success-500': kind === 'success', 'text-warning-400 dark:text-warning-500': kind === 'warning', 'text-danger-400 dark:text-danger-500': kind === 'danger' }" x-slotted="[]" x-data:widget="cncIcon($el)"> <span role="img" x-ref="img" :aria-label="label || name" class="fill-current block" style="width: 100%; height: 100%"></span> </cnc-icon> </div> <div class="ml-3 flex-1"> <div class="text-sm font-medium" :class="{ 'text-primary-600 dark:text-primary-800': kind === 'primary', 'text-primary-600 dark:text-info-800': kind === 'info', 'text-success-600 dark:text-success-800': kind === 'success', 'text-primary-600 dark:text-warning-800': kind === 'warning', 'text-danger-600 dark:text-danger-800': kind === 'danger' }" x-text="title"></div> <div class="mt-2 text-sm" :class="{ 'text-primary-500 dark:text-primary-700': kind === 'primary', 'text-info-500 dark:text-info-700': kind === 'info', 'text-success-600 dark:text-success-800': kind === 'success', 'text-warning-500 dark:text-warning-700': kind === 'warning', 'text-danger-600 dark:text-danger-800': kind === 'danger' }"> <div x-text="content"></div> </div> </div> <template x-if="closable"> <div class="cursor-pointer flex items-center ml-3" @click="close()"> <cnc-icon class="leading-none box-content leading-none box-content w-5 h-5" name="x" :class="{ 'text-primary-400 hover:text-primary-600 dark:text-primary-500 dark:hover:text-primary-700': kind === 'primary', 'text-info-400 hover:text-info-600 dark:text-info-500 dark:hover:text-info-700': kind === 'info', 'text-success-400 hover:text-success-600 dark:text-success-500 dark:hover:text-success-700': kind === 'success', 'text-warning-400 hover:text-warning-600 dark:text-warning-500 dark:hover:text-warning-700': kind === 'warning', 'text-danger-400 hover:text-danger-600 dark:text-danger-500 dark:hover:text-danger-700': kind === 'danger' }" x-slotted="[]" x-data:widget="cncIcon($el)"> <span role="img" x-ref="img" :aria-label="label || name" class="fill-current block" style="width: 100%; height: 100%"></span> </cnc-icon> </div> </template> </div> </div> </template></cnc-alert> </template> <form x-show="!problemReportSubmitted" @submit.prevent="handleSubmitProblemReport" class="grid gap-4"> <template x-if="!problemReportFormData.user"> <cnc-field type="string" size="lg" x-prop:value="problemReportFormData.reporterName" label="Your Name" :disabled="problemReportProcessing" x-prop:errors="problemReportFormErrors" x-slotted="[]" x-data:widget="cncField($el)" class="block"><template> <div class="pt-0 border-none" :class="{ 'mt-3 relative': _needsFloatingSpace, 'block': labelPosition === 'top', 'flex': labelPosition === 'left' }"> <!-- class="grid grid-cols-3 items-start gap-4 border-t border-neutral-200 pt-5 md:block md:pt-0 md:border-none" --> <template x-if="(label || $slots.label) &amp;&amp; (labelPosition !== 'floating')"> <div class="" :class="{ 'mr-2 py-3': labelPosition === 'left' &amp;&amp; type.toLowerCase() !== 'boolean', 'mr-2 py-1.5': labelPosition === 'left' &amp;&amp; type.toLowerCase() == 'boolean' }"> <div class="--cnc-field__label flex flex-nowrap items-center text-neutral-400 dark:text-neutral-400"> <!-- :class="{'absolute bottom-1.5 left-6' : type.toLowerCase() === 'boolean' && as === 'checkbox' || type.toLowerCase() === 'radio' , 'absolute top-0 left-14' : type.toLowerCase() === 'boolean' && as === 'toggle'}" --> <label :for="name" class="block text-sm font-medium" :class="{'text-danger-500 dark:text-danger-600': !!hasError || _error.length}"> <span class="whitespace-nowrap" x-text="label"></span> </label> <template x-if="hint"> <div class="flex text-sm font-medium ml-1"> <cnc-tooltip :content="hint" x-slotted="[&quot;default&quot;]" x-data:widget="cncTooltip($el)" class="inline-flex"><template> <span class="cnc-tooltip__wrapper inline-flex w-full" x-ref="reference" @mouseenter="toggle($event, true)" @mouseleave="toggle($event, false)" @click="toggle($event, true)" @click.outside="if (!$event.target.closest('cnc-tooltip')) { toggle($event, false) }" @focus="toggle($event, true)" @blur="toggle($event, false)"> <cnc-icon name="feather/info" class="leading-none box-content leading-none box-content w-4 h-4 fill-neutral-500 dark:fill-neutral-400" x-slotted="[]" x-data:widget="cncIcon($el)"><svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-icon-name="feather/info"> <circle cx="12" cy="12" r="10"></circle> <line x1="12" y1="16" x2="12" y2="12"></line> <line x1="12" y1="8" x2="12.01" y2="8"></line> </svg></cnc-icon> </span> <div x-ref="tooltip" class="fixed z-50 leading-snug text-sm opacity-0" :class="{'pointer-events-none': !interactive }" x-motion="showToolTip ? { opacity: 1 }: { opacity: 0 }" @motioned.stop=""> <div role="tooltip" class="rounded px-2 py-1 border" :class="{ 'border-neutral-800 bg-neutral-900 text-neutral-100 border-neutral-800': theme === 'dark', 'border-neutral-300 bg-white text-neutral-700': !theme || theme === 'light', 'pointer-events-none': !interactive }"> <span x-text="content"></span> <template x-if="arrow"> <div class="absolute rotate-45 w-2 h-2 border" :class="{ 'bg-neutral-900 border-neutral-800': theme === 'dark', 'bg-white border-neutral-300': theme === 'light', 'border-l-transparent border-t-transparent': _placement === 'top' , 'border-r-transparent border-b-transparent': _placement === 'bottom' , 'border-r-transparent border-t-transparent': _placement === 'right' , 'border-l-transparent border-b-transparent': _placement === 'left' }" x-ref="arrow"></div> </template> </div> </div> </template></cnc-tooltip> </div> </template> <span x-show="required" class="block text-sm font-medium text-danger-600 dark:text-danger-700 ml-1">*</span> <!-- <template x-if="hint"> <div class="flex items-center px-2"> <cnc-tooltip :content="hint" class="w-6 h-6"> <cnc-icon name="b:info-circle" class="w-6 h-6 text-neutral-400 dark:text-neutral-50" :class="{'w-4 h-4' : ['checkboxes' , 'radios' , 'checkbox' , 'radio', 'switch'].includes(as)}" ></cnc-icon> </cnc-tooltip> </div> </template> --> </div> </div> </template> <div class="relative flex flex-col content-center items-stretch" :class="{ 'flex-row flex-grow': labelPosition === 'left' }" @focusin="_focused = true" @focusout="_focused = false"> <template x-for="val, index of _getValues()" x-ref="innerInputs"> <div class="relative flex content-center items-stretch" :class="{'mt-2' : index !== 0, 'mt-1' : labelPosition !== 'left'}"> <template x-if="$slots.outerPrefix"> <div class="inline-flex items-center rounded-l-md border border-r-0 border-neutral-300 dark:border-neutral-600 text-neutral-500 dark:text-neutral-400 bg-neutral-50 dark:bg-neutral-800 fill-neutral-500 dark:fill-neutral-400"> </div> </template> <div @keydown="_keypress" class="--cnc-field_inputs relative w-full focus-within:z-10" :class="{'rounded-l-md': !$slots.outerPrefix, 'rounded-r-md': !$slots.outerSuffix , 'border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-900 focus-within:border-primary-500 dark:focus-within:border-primary-600 focus-within:ring-primary-500 dark:focus-within:ring-primary-600 focus-within:ring-2' : _showBorder, 'p-1': as === 'checkboxes' || as === 'radio' }"> <template x-if="index == 0 &amp;&amp; (label || $slots.label) &amp;&amp; (labelPosition === 'floating')"> <div class="pointer-events-none absolute z-10 left-0 transition-all duration-300" :class="{ '-top-4 text-xs font-medium': _labelFloatTop, 'top-1 left-3 text-xs font-normal': !_labelFloatTop }"> <div class="flex text-neutral-400 dark:text-neutral-400"> <!-- :class="{'absolute bottom-1.5 left-6' : type.toLowerCase() === 'boolean' && as === 'checkbox' || type.toLowerCase() === 'radio' , 'absolute top-0 left-14' : type.toLowerCase() === 'boolean' && as === 'toggle'}" --> <label :for="name" class="block" :class="{ 'text-danger-500 dark:text-danger-600': !!hasError || _error.length }"> <span x-text="label"></span> </label> <span x-show="required" class="block text-sm font-medium text-danger-600 dark:text-danger-700 ml-1">*</span> </div> </div> </template> </div> <template x-if="$slots.outerSuffix"> <div class="inline-flex items-center rounded-r-md border border-l-0 border-neutral-300 dark:border-neutral-600 text-neutral-500 dark:text-neutral-400 bg-neutral-50 dark:bg-neutral-800 fill-neutral-500 dark:fill-neutral-400"> </div> </template> <template x-if="$slots.action"> <div class="inline-flex items-center px-3"> </div> </template> <template x-if="_showAdd &amp;&amp; (_values[index] || _values.length > 1)"> <div class="flex items-center px-2" :class="{'-mt-3': type.toLowerCase() === 'range' || as.toLowerCase() === 'slider'}" @click="_remove(index)"> <cnc-icon class="leading-none box-content leading-none box-content cursor-pointer w-6 h-6 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-500 hover:shadow-sm rounded-full" name="hero/x-mark" x-slotted="[]" x-data:widget="cncIcon($el)"><svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon-name="hero/x-mark"> <path d="M6 18L18 6M6 6L18 18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> </svg></cnc-icon> </div> </template> </div> </template> <template x-if="helpText || $slots.helpText"> <p class="my-1 text-xs text-neutral-500 dark:text-neutral-500"> <span x-text="helpText" class=""></span> </p> </template> <template x-if="_showAdd"> <cnc-button size="xs" icon="hero/plus" @click="_add" label="Add" kind="plain" class="inline-block font-medium mt-1" :class="Alpine.mergeClasses({'w-full' : wide}, {'mt-4': type.toLowerCase() === 'range' || $cncField.as.toLowerCase() === 'slider'})" :disabled="_values.some(v => !v)" x-slotted="[]" x-data:widget="cncButton($el)"><template> <div x-on:click="disabled &amp;&amp; event.stopPropagation()"> <button x-mimic:cnc-button.remove="p-* px-* py-*" ref="button" class="--cnc-button__button inline-flex items-center focus:relative focus:z-10" :class="{[styleClasses()] : true }" :disabled="disabled || processing" :type="submit ? 'submit' : 'button'" :name="name" :value="value" @click="confirm.action ? _confirm = true : _confirm = false" :aria-pressed="pressed"> <template x-if="icon &amp;&amp; !processing"> <cnc-icon slot="prefix" :size="size" :name="icon" class="leading-none box-content leading-none box-content --cnc-button__icon w-6 h-6" x-slotted="[]" x-data:widget="cncIcon($el)"> <span role="img" x-ref="img" :aria-label="label || name" class="fill-current block" style="width: 100%; height: 100%"></span> </cnc-icon> </template> <template x-if="processing"> <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-neutral-500 dark:text-neutral-100" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> </template> <template x-if="label"> <span class="whitespace-nowrap px-0.5" x-text="label"></span> </template> <template x-if="caret"> <cnc-icon size="md" class="leading-none box-content leading-none box-content --cnc-button__caret text-neutral-700 dark:text-neutral-200" name="h:chevron-down" x-slotted="[]" x-data:widget="cncIcon($el)"> <span role="img" x-ref="img" :aria-label="label || name" class="fill-current block" style="width: 100%; height: 100%"></span> </cnc-icon> </template> </button> </div> </template></cnc-button> </template> </div> </div> <template x-if="hasError || _error.length"> <div class="mt-2 text-sm text-neutral-500 dark:text-neutral-200"> <span x-text="error || _error" class="mt-1 text-sm text-danger-500 dark:text-danger-600"></span> </div> </template> <template x-if="$slots.guard"> </template> </template></cnc-field> </template> <template x-if="!problemReportFormData.user"> <cnc-field type="email" size="lg" x-prop:value="problemReportFormData.email" label="Your Email" :disabled="problemReportProcessing" x-prop:errors="problemReportFormErrors" required="" skip-required-validation="" class="block" x-slotted="[]" x-data:widget="cncField($el)"></cnc-field> </template> <div class="flex flex-col" x-show="problemReportFormData.tenderTitle"> <div class="text-sm mb-1 text-neutral-700" x-t="problemReport.opportunity">Opportunity</div> <div class="text-base text-neutral-900 ml-2 line-clamp-2" x-text="problemReportFormData.tenderTitle"></div> </div> <div class="flex flex-col" x-show="problemReportFormData.sourceTitle"> <div class="text-sm mb-1 text-neutral-700" x-t="problemReport.source">Source</div> <div class="text-base text-neutral-900 ml-2 line-clamp-2" x-text="problemReportFormData.sourceTitle"></div> </div> <cnc-field label="Problem Description" type="longtext" size="lg" :required="problemReportFormData.type === 'help'" skip-required-validation="" x-prop:value="problemReportFormData.description" :disabled="problemReportProcessing" x-prop:errors="problemReportFormErrors" class="block" x-slotted="[]" x-data:widget="cncField($el)"></cnc-field> <div class="flex justify-end"> <cnc-button outline="" kind="primary" label="Cancel" @click="problemReportFormModalIsOpen = false" class="inline-block font-medium mr-2" :disabled="problemReportProcessing" :class="{'w-full' : wide}" x-slotted="[]" x-data:widget="cncButton($el)"></cnc-button> <cnc-button kind="primary" label="Send Report" submit="" :processing="problemReportProcessing" class="inline-block font-medium" :class="{'w-full' : wide}" x-slotted="[]" x-data:widget="cncButton($el)"></cnc-button> </div> </form> <div x-show="problemReportSubmitted"> <cnc-alert class="mb-4" kind="success" title="Report Submitted" content="Thank you for reporting a problem." x-slotted="[]" x-data:widget="cncAlert($el)"></cnc-alert> <div class="w-full flex flex-row justify-end"> <cnc-button kind="primary" label="Close" @click="problemReportFormModalIsOpen = false" class="inline-block font-medium" :class="{'w-full' : wide}" x-slotted="[]" x-data:widget="cncButton($el)"></cnc-button> </div> </div> </div> </div> </div> </div> </div> </template> </div> </template> </template></cnc-modal> </div> </main> <style> /* TODO: Figure out how to get rid of this */ .blockcontent { height: 100%; } </style> </template></body></html>