diff --git a/dist/engrid.css b/dist/engrid.css
index e7e6de0..385b026 100644
--- a/dist/engrid.css
+++ b/dist/engrid.css
@@ -19,7 +19,7 @@
*
* ENGRID PAGE TEMPLATE ASSETS
*
- * Date: Wednesday, May 13, 2026 @ 02:46:15 ET
+ * Date: Thursday, May 14, 2026 @ 13:36:49 ET
* By: fernando
* ENGrid styles: v0.25.0
* ENGrid scripts: v0.25.2
diff --git a/dist/engrid.js b/dist/engrid.js
index 0b75df3..0dc8688 100644
--- a/dist/engrid.js
+++ b/dist/engrid.js
@@ -17,7 +17,7 @@
*
* ENGRID PAGE TEMPLATE ASSETS
*
- * Date: Wednesday, May 13, 2026 @ 02:46:15 ET
+ * Date: Thursday, May 14, 2026 @ 13:36:49 ET
* By: fernando
* ENGrid styles: v0.25.0
* ENGrid scripts: v0.25.2
@@ -10957,17875 +10957,38783 @@ tippy.setDefaultProps({
/***/ }),
-/***/ 1234:
-/***/ (() => {
+/***/ 716:
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-/* (ignored) */
+"use strict";
-/***/ })
+// EXPORTS
+__webpack_require__.d(__webpack_exports__, {
+ Ay: () => (/* binding */ tippy_esm)
+});
-/******/ });
-/************************************************************************/
-/******/ // The module cache
-/******/ var __webpack_module_cache__ = {};
-/******/
-/******/ // The require function
-/******/ function __webpack_require__(moduleId) {
-/******/ // Check if module is in cache
-/******/ var cachedModule = __webpack_module_cache__[moduleId];
-/******/ if (cachedModule !== undefined) {
-/******/ return cachedModule.exports;
-/******/ }
-/******/ // Create a new module (and put it into the cache)
-/******/ var module = __webpack_module_cache__[moduleId] = {
-/******/ id: moduleId,
-/******/ loaded: false,
-/******/ exports: {}
-/******/ };
-/******/
-/******/ // Execute the module function
-/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
-/******/ // Flag the module as loaded
-/******/ module.loaded = true;
-/******/
-/******/ // Return the exports of the module
-/******/ return module.exports;
-/******/ }
-/******/
-/************************************************************************/
-/******/ /* webpack/runtime/amd define */
-/******/ (() => {
-/******/ __webpack_require__.amdD = function () {
-/******/ throw new Error('define cannot be used indirect');
-/******/ };
-/******/ })();
-/******/
-/******/ /* webpack/runtime/amd options */
-/******/ (() => {
-/******/ __webpack_require__.amdO = {};
-/******/ })();
-/******/
-/******/ /* webpack/runtime/compat get default export */
-/******/ (() => {
-/******/ // getDefaultExport function for compatibility with non-harmony modules
-/******/ __webpack_require__.n = (module) => {
-/******/ var getter = module && module.__esModule ?
-/******/ () => (module['default']) :
-/******/ () => (module);
-/******/ __webpack_require__.d(getter, { a: getter });
-/******/ return getter;
-/******/ };
-/******/ })();
-/******/
-/******/ /* webpack/runtime/define property getters */
-/******/ (() => {
-/******/ // define getter functions for harmony exports
-/******/ __webpack_require__.d = (exports, definition) => {
-/******/ for(var key in definition) {
-/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
-/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
-/******/ }
-/******/ }
-/******/ };
-/******/ })();
-/******/
-/******/ /* webpack/runtime/hasOwnProperty shorthand */
-/******/ (() => {
-/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
-/******/ })();
-/******/
-/******/ /* webpack/runtime/node module decorator */
-/******/ (() => {
-/******/ __webpack_require__.nmd = (module) => {
-/******/ module.paths = [];
-/******/ if (!module.children) module.children = [];
-/******/ return module;
-/******/ };
-/******/ })();
-/******/
-/************************************************************************/
-var __webpack_exports__ = {};
-// This entry need to be wrapped in an IIFE because it need to be in strict mode.
-(() => {
-"use strict";
+// UNUSED EXPORTS: animateFill, createSingleton, delegate, followCursor, hideAll, inlinePositioning, roundArrow, sticky
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/deprecated.js
-// A way to gracefully handle deprecation.
-// Find and replace HTML Elements, Classes, and more after the DOM is loaded but before any other Javascript fires.
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getWindow.js
+function getWindow(node) {
+ if (node == null) {
+ return window;
+ }
-class Deprecated {
- constructor() {
- let deprecated;
- let replacement;
- // Checks for body-side class
- deprecated = document.querySelector(".body-side");
- if (deprecated) {
- this.warning(deprecated);
- }
- // Checks for backgroundImage class
- deprecated = document.querySelector(".backgroundImage");
- if (deprecated) {
- replacement = "background-image";
- this.replace(deprecated, replacement);
- }
- // Checks for backgroundImageOverlay class
- deprecated = document.querySelector(".backgroundImageOverlay");
- if (deprecated) {
- replacement = "background-image-overlay";
- this.replace(deprecated, replacement);
- }
- }
- warning(deprecated) {
- if (ENGrid.debug)
- console.log("Deprecated: '" + deprecated + "' was detected and nothing was done.");
- }
- replace(deprecated, replacement) {
- if (ENGrid.debug)
- console.log("Deprecated: '" +
- deprecated +
- "' was detected and replaced with '" +
- replacement +
- "'.");
- deprecated.classList.add(replacement);
- deprecated.classList.remove(deprecated);
- }
+ if (node.toString() !== '[object Window]') {
+ var ownerDocument = node.ownerDocument;
+ return ownerDocument ? ownerDocument.defaultView || window : window;
+ }
+
+ return node;
}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/instanceOf.js
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/options.js
-const OptionsDefaults = {
- backgroundImage: "",
- MediaAttribution: true,
- applePay: false,
- CapitalizeFields: false,
- ClickToExpand: true,
- CurrencySymbol: "$",
- CurrencyCode: "USD",
- AddCurrencySymbol: true,
- ThousandsSeparator: "",
- DecimalSeparator: ".",
- DecimalPlaces: 2,
- MinAmount: 1,
- MaxAmount: 100000,
- MinAmountMessage: "Amount must be at least $1",
- MaxAmountMessage: "Amount must be less than $100,000",
- UseAmountValidatorFromEN: false,
- SkipToMainContentLink: true,
- SrcDefer: true,
- SuppressPurchaseEcard: false,
- NeverBounceAPI: null,
- NeverBounceDateField: null,
- NeverBounceStatusField: null,
- NeverBounceDateFormat: "MM/DD/YYYY",
- NeverBounceTimeout: 10000,
- FreshAddress: false,
- ProgressBar: false,
- AutoYear: false,
- TranslateFields: true,
- Debug: false,
- RememberMe: false,
- TidyContact: false,
- RegionLongFormat: "",
- CountryDisable: [],
- Placeholders: false,
- ENValidators: false,
- MobileCTA: false,
- CustomCurrency: false,
- CustomPremium: false,
- VGS: false,
- PostalCodeValidator: false,
- CountryRedirect: false,
- WelcomeBack: false,
- OptInLadder: false,
- StickyNSG: false,
- StickyPrepopulation: false,
- PreferredPaymentMethod: false,
- PageLayouts: [
- "leftleft1col",
- "centerleft1col",
- "centercenter1col",
- "centercenter2col",
- "centerright1col",
- "rightright1col",
- "none",
- ],
-};
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/upsell-options.js
-const UpsellOptionsDefaults = {
- image: "https://picsum.photos/480/650",
- imagePosition: "left",
- title: "Will you change your gift to just {new-amount} a month to boost your impact?",
- paragraph: "Make a monthly pledge today to support us with consistent, reliable resources during emergency moments.",
- yesLabel: "Yes! Process My {new-amount} monthly gift",
- noLabel: "No, thanks. Continue with my {old-amount} one-time gift",
- otherAmount: true,
- otherLabel: "Or enter a different monthly amount:",
- upsellOriginalGiftAmountFieldName: "",
- amountRange: [
- { max: 10, suggestion: 5 },
- { max: 15, suggestion: 7 },
- { max: 20, suggestion: 8 },
- { max: 25, suggestion: 9 },
- { max: 30, suggestion: 10 },
- { max: 35, suggestion: 11 },
- { max: 40, suggestion: 12 },
- { max: 50, suggestion: 14 },
- { max: 100, suggestion: 15 },
- { max: 200, suggestion: 19 },
- { max: 300, suggestion: 29 },
- { max: 500, suggestion: "Math.ceil((amount / 12)/5)*5" },
- ],
- minAmount: 0,
- canClose: true,
- submitOnClose: false,
- oneTime: true,
- annual: false,
- disablePaymentMethods: [],
- skipUpsell: false,
- conversionField: "",
- upsellCheckbox: false,
-};
+function isElement(node) {
+ var OwnElement = getWindow(node).Element;
+ return node instanceof OwnElement || node instanceof Element;
+}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/translate-options.js
-const ptbrTranslation = [
- { field: "supporter.firstName", translation: "Nome" },
- { field: "supporter.lastName", translation: "Sobrenome" },
- { field: "supporter.phoneNumber", translation: "Celular" },
- { field: "supporter.address1", translation: "EndereΓ§o" },
- { field: "supporter.address2", translation: "Complemento" },
- { field: "supporter.postcode", translation: "CEP" },
- { field: "supporter.city", translation: "Cidade" },
- { field: "supporter.region", translation: "Estado" },
- { field: "supporter.country", translation: "PaΓs" },
-];
-const deTranslation = [
- { field: "supporter.address1", translation: "StraΓe, Hausnummer" },
- { field: "supporter.postcode", translation: "Postleitzahl" },
- { field: "supporter.city", translation: "Ort" },
- { field: "supporter.region", translation: "Bundesland" },
- { field: "supporter.country", translation: "Land" },
-];
-const frTranslation = [
- { field: "supporter.address1", translation: "Adresse" },
- { field: "supporter.postcode", translation: "Code Postal" },
- { field: "supporter.city", translation: "Ville" },
- { field: "supporter.region", translation: "RΓ©gion" },
- { field: "supporter.country", translation: "Country" },
-];
-const nlTranslation = [
- { field: "supporter.address1", translation: "Adres" },
- { field: "supporter.postcode", translation: "Postcode" },
- { field: "supporter.city", translation: "Woonplaats" },
- { field: "supporter.region", translation: "Provincie" },
- { field: "supporter.country", translation: "Country" },
-];
-const TranslateOptionsDefaults = {
- BR: ptbrTranslation,
- BRA: ptbrTranslation,
- DE: deTranslation,
- DEU: deTranslation,
- FR: frTranslation,
- FRA: frTranslation,
- NL: nlTranslation,
- NLD: nlTranslation,
-};
+function isHTMLElement(node) {
+ var OwnElement = getWindow(node).HTMLElement;
+ return node instanceof OwnElement || node instanceof HTMLElement;
+}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/exit-intent-options.js
-const ExitIntentOptionsDefaults = {
- enabled: false,
- title: "We are sad that you are leaving",
- text: "Would you mind telling us why you are leaving this page?",
- buttonText: "Send us your comments",
- buttonLink: "https://www.4sitestudios.com/",
- cookieName: "engrid-exit-intent-lightbox",
- cookieDuration: 30,
- triggers: {
- visibilityState: true,
- mousePosition: true,
- },
-};
+function isShadowRoot(node) {
+ // IE 11 has no ShadowRoot
+ if (typeof ShadowRoot === 'undefined') {
+ return false;
+ }
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/frequency-upsell-options.js
-const FrequencyUpsellOptionsDefaults = {
- title: "Before we process your donation...",
- paragraph: "Would you like to make it an annual gift?",
- yesButton: "YES! Process my gift as an annual gift of ${upsell_amount}",
- noButton: "NO! Process my gift as a one-time gift of ${current_amount}",
- upsellFrequency: "annual",
- upsellFromFrequency: ["onetime"],
- customClass: "",
- upsellAmount: (currentAmount) => currentAmount,
- onOpen: () => { },
- onAccept: () => { },
- onDecline: () => { },
-};
+ var OwnElement = getWindow(node).ShadowRoot;
+ return node instanceof OwnElement || node instanceof ShadowRoot;
+}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/iframe-queue-options.js
-/**
- * Configuration interfaces for the Iframe Queue component.
- *
- * The Iframe Queue loads a sequence of embedded Engaging Networks pages
- * one at a time, passes field values into them via `postMessage`, and
- * exposes a global `IframeQueueEvents` instance so external code can
- * subscribe to chain-completion. See iframe-queue.ts for the component.
- *
- * Configuration may be supplied either programmatically (via
- * `IframeQueue.getInstance().enqueue(...).process()`) or declaratively
- * by setting `window.EngridIframeQueue` on the host EN page before
- * the ENgrid bundle loads.
- */
-const iframe_queue_options_IframeQueueOptionsDefaults = {
- items: [],
- autoStart: true,
-};
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/loader.js
-// Ref: https://app.getguru.com/card/iMgx968T/ENgrid-Loader
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/math.js
+var math_max = Math.max;
+var math_min = Math.min;
+var round = Math.round;
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/userAgent.js
+function getUAString() {
+ var uaData = navigator.userAgentData;
-class Loader {
- constructor() {
- this.logger = new logger_EngridLogger("Loader", "gold", "black", "π");
- this.cssElement = document.querySelector('link[href*="engrid."][rel="stylesheet"]');
- this.jsElement = document.querySelector('script[src*="engrid."]');
- }
- // Returns true if ENgrid should reload (that means the current ENgrid is not the right one)
- // Returns false if ENgrid should not reload (that means the current ENgrid is the right one)
- reload() {
- var _a, _b, _c;
- const assets = this.getOption("assets");
- const isLoaded = engrid_ENGrid.getBodyData("loaded");
- let shouldSkipCss = this.getOption("engridcss") === "false";
- let shouldSkipJs = this.getOption("engridjs") === "false";
- if (isLoaded || !assets) {
- if (shouldSkipCss && this.cssElement) {
- this.logger.log("engridcss=false | Removing original stylesheet:", this.cssElement);
- this.cssElement.remove();
- }
- if (shouldSkipJs && this.jsElement) {
- this.logger.log("engridjs=false | Removing original script:", this.jsElement);
- this.jsElement.remove();
- }
- if (shouldSkipCss) {
- this.logger.log("engridcss=false | adding top banner CSS");
- this.addENgridCSSUnloadedCSS();
- }
- if (shouldSkipJs) {
- this.logger.log("engridjs=false | Skipping JS load.");
- this.logger.success("LOADED");
- return true;
- }
- this.logger.success("LOADED");
- return false;
- }
- // Load the right ENgrid
- this.logger.log("RELOADING");
- engrid_ENGrid.setBodyData("loaded", "true"); // Set the loaded flag, so the next time we don't reload
- // Fetch the desired repo, assets location, and override JS/CSS
- const theme = engrid_ENGrid.getBodyData("theme");
- const engrid_repo = (_a = this.getOption("repo-name")) !== null && _a !== void 0 ? _a : `engrid-${theme}`;
- let engrid_js_url = "";
- let engrid_css_url = "";
- switch (assets) {
- case "local":
- this.logger.log("LOADING LOCAL");
- engrid_ENGrid.setBodyData("assets", "local");
- engrid_js_url = `https://${engrid_repo}.test/dist/engrid.js`;
- engrid_css_url = `https://${engrid_repo}.test/dist/engrid.css`;
- break;
- case "flush":
- this.logger.log("FLUSHING CACHE");
- const timestamp = Date.now();
- const jsCurrentURL = new URL(((_b = this.jsElement) === null || _b === void 0 ? void 0 : _b.getAttribute("src")) || "");
- jsCurrentURL.searchParams.set("v", timestamp.toString());
- engrid_js_url = jsCurrentURL.toString();
- const cssCurrentURL = new URL(((_c = this.cssElement) === null || _c === void 0 ? void 0 : _c.getAttribute("href")) || "");
- cssCurrentURL.searchParams.set("v", timestamp.toString());
- engrid_css_url = cssCurrentURL.toString();
- break;
- default:
- this.logger.log("LOADING EXTERNAL");
- engrid_js_url = `https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${engrid_repo}/${assets}/engrid.js`;
- engrid_css_url = `https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${engrid_repo}/${assets}/engrid.css`;
- }
- if (shouldSkipCss && this.cssElement) {
- this.logger.log("engridcss=false | Removing original stylesheet:", this.cssElement);
- this.cssElement.remove();
- }
- if (shouldSkipCss && engrid_css_url && engrid_css_url !== "") {
- this.logger.log("engridcss=false | Skipping injection of stylesheet:", engrid_css_url);
- }
- if (shouldSkipCss) {
- this.logger.log("engridcss=false | adding top banner CSS");
- this.addENgridCSSUnloadedCSS();
- }
- else {
- this.setCssFile(engrid_css_url);
- }
- if (shouldSkipJs && this.jsElement) {
- this.logger.log("engridjs=false | Removing original script:", this.jsElement);
- this.jsElement.remove();
- }
- if (shouldSkipJs && engrid_js_url && engrid_js_url !== "") {
- this.logger.log("engridjs=false | Skipping injection of script:", engrid_js_url);
- }
- if (!shouldSkipJs) {
- this.setJsFile(engrid_js_url);
- }
- // If custom assets aren't defined, we don't need to reload.
- if (!assets) {
- return false;
- }
- return true;
- }
- getOption(key) {
- const urlParam = engrid_ENGrid.getUrlParameter(key);
- if (urlParam && ["assets", "engridcss", "engridjs"].includes(key)) {
- return urlParam;
- }
- else if (window.EngridLoader && window.EngridLoader.hasOwnProperty(key)) {
- return window.EngridLoader[key];
- }
- else if (this.jsElement && this.jsElement.hasAttribute("data-" + key)) {
- return this.jsElement.getAttribute("data-" + key);
- }
- return null;
- }
- setCssFile(url) {
- if (url === "") {
- return;
- }
- if (this.cssElement) {
- this.logger.log("Replacing stylesheet:", url);
- this.cssElement.setAttribute("href", url);
- }
- else {
- this.logger.log("Injecting stylesheet:", url);
- const link = document.createElement("link");
- link.setAttribute("rel", "stylesheet");
- link.setAttribute("type", "text/css");
- link.setAttribute("media", "all");
- link.setAttribute("href", url);
- document.head.appendChild(link);
- }
- }
- setJsFile(url) {
- if (url === "") {
- return;
- }
- this.logger.log("Injecting script:", url);
- const script = document.createElement("script");
- script.setAttribute("src", url);
- document.head.appendChild(script);
- }
- addENgridCSSUnloadedCSS() {
- document.body.insertAdjacentHTML("beforeend", ``);
- }
+
+
+function getBoundingClientRect(element, includeScale, isFixedStrategy) {
+ if (includeScale === void 0) {
+ includeScale = false;
+ }
+
+ if (isFixedStrategy === void 0) {
+ isFixedStrategy = false;
+ }
+
+ var clientRect = element.getBoundingClientRect();
+ var scaleX = 1;
+ var scaleY = 1;
+
+ if (includeScale && isHTMLElement(element)) {
+ scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
+ scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
+ }
+
+ var _ref = isElement(element) ? getWindow(element) : window,
+ visualViewport = _ref.visualViewport;
+
+ var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;
+ var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;
+ var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;
+ var width = clientRect.width / scaleX;
+ var height = clientRect.height / scaleY;
+ return {
+ width: width,
+ height: height,
+ top: y,
+ right: x + width,
+ bottom: y + height,
+ left: x,
+ x: x,
+ y: y
+ };
}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js
-// EXTERNAL MODULE: ./node_modules/@4site/engrid-scripts/node_modules/strongly-typed-events/dist/index.js
-var dist = __webpack_require__(3199);
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/en-form.js
+function getWindowScroll(node) {
+ var win = getWindow(node);
+ var scrollLeft = win.pageXOffset;
+ var scrollTop = win.pageYOffset;
+ return {
+ scrollLeft: scrollLeft,
+ scrollTop: scrollTop
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js
+function getHTMLElementScroll(element) {
+ return {
+ scrollLeft: element.scrollLeft,
+ scrollTop: element.scrollTop
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js
-class en_form_EnForm {
- constructor() {
- this.logger = new logger_EngridLogger("EnForm");
- this._onIntentSubmit = new dist/* SignalDispatcher */.UD();
- this._onSubmit = new dist/* SignalDispatcher */.UD();
- this._onValidate = new dist/* SignalDispatcher */.UD();
- this._onError = new dist/* SignalDispatcher */.UD();
- this.submit = true;
- this.submitPromise = false;
- this.validate = true;
- this.validatePromise = false;
- }
- static getInstance() {
- if (!en_form_EnForm.instance) {
- en_form_EnForm.instance = new en_form_EnForm();
- }
- return en_form_EnForm.instance;
- }
- dispatchIntentSubmit() {
- this._onIntentSubmit.dispatch();
- this.logger.log("dispatchIntentSubmit");
+
+
+function getNodeScroll(node) {
+ if (node === getWindow(node) || !isHTMLElement(node)) {
+ return getWindowScroll(node);
+ } else {
+ return getHTMLElementScroll(node);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getNodeName.js
+function getNodeName(element) {
+ return element ? (element.nodeName || '').toLowerCase() : null;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js
+
+function getDocumentElement(element) {
+ // $FlowFixMe[incompatible-return]: assume body is always available
+ return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
+ element.document) || window.document).documentElement;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js
+
+
+
+function getWindowScrollBarX(element) {
+ // If has a CSS width greater than the viewport, then this will be
+ // incorrect for RTL.
+ // Popper 1 is broken in this case and never had a bug report so let's assume
+ // it's not an issue. I don't think anyone ever specifies width on
+ // anyway.
+ // Browsers where the left scrollbar doesn't cause an issue report `0` for
+ // this (e.g. Edge 2019, IE11, Safari)
+ return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js
+
+function getComputedStyle(element) {
+ return getWindow(element).getComputedStyle(element);
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js
+
+function isScrollParent(element) {
+ // Firefox wants us to check `-x` and `-y` variations as well
+ var _getComputedStyle = getComputedStyle(element),
+ overflow = _getComputedStyle.overflow,
+ overflowX = _getComputedStyle.overflowX,
+ overflowY = _getComputedStyle.overflowY;
+
+ return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js
+
+
+
+
+
+
+
+
+
+function isElementScaled(element) {
+ var rect = element.getBoundingClientRect();
+ var scaleX = round(rect.width) / element.offsetWidth || 1;
+ var scaleY = round(rect.height) / element.offsetHeight || 1;
+ return scaleX !== 1 || scaleY !== 1;
+} // Returns the composite rect of an element relative to its offsetParent.
+// Composite means it takes into account transforms as well as layout.
+
+
+function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
+ if (isFixed === void 0) {
+ isFixed = false;
+ }
+
+ var isOffsetParentAnElement = isHTMLElement(offsetParent);
+ var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);
+ var documentElement = getDocumentElement(offsetParent);
+ var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);
+ var scroll = {
+ scrollLeft: 0,
+ scrollTop: 0
+ };
+ var offsets = {
+ x: 0,
+ y: 0
+ };
+
+ if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
+ if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
+ isScrollParent(documentElement)) {
+ scroll = getNodeScroll(offsetParent);
}
- dispatchSubmit() {
- this._onSubmit.dispatch();
- this.logger.log("dispatchSubmit");
+
+ if (isHTMLElement(offsetParent)) {
+ offsets = getBoundingClientRect(offsetParent, true);
+ offsets.x += offsetParent.clientLeft;
+ offsets.y += offsetParent.clientTop;
+ } else if (documentElement) {
+ offsets.x = getWindowScrollBarX(documentElement);
}
- dispatchValidate() {
- this._onValidate.dispatch();
- this.logger.log("dispatchValidate");
+ }
+
+ return {
+ x: rect.left + scroll.scrollLeft - offsets.x,
+ y: rect.top + scroll.scrollTop - offsets.y,
+ width: rect.width,
+ height: rect.height
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js
+ // Returns the layout rect of an element relative to its offsetParent. Layout
+// means it doesn't take into account transforms.
+
+function getLayoutRect(element) {
+ var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.
+ // Fixes https://github.com/popperjs/popper-core/issues/1223
+
+ var width = element.offsetWidth;
+ var height = element.offsetHeight;
+
+ if (Math.abs(clientRect.width - width) <= 1) {
+ width = clientRect.width;
+ }
+
+ if (Math.abs(clientRect.height - height) <= 1) {
+ height = clientRect.height;
+ }
+
+ return {
+ x: element.offsetLeft,
+ y: element.offsetTop,
+ width: width,
+ height: height
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getParentNode.js
+
+
+
+function getParentNode(element) {
+ if (getNodeName(element) === 'html') {
+ return element;
+ }
+
+ return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
+ // $FlowFixMe[incompatible-return]
+ // $FlowFixMe[prop-missing]
+ element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
+ element.parentNode || ( // DOM Element detected
+ isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
+ // $FlowFixMe[incompatible-call]: HTMLElement is a Node
+ getDocumentElement(element) // fallback
+
+ );
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js
+
+
+
+
+function getScrollParent(node) {
+ if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
+ // $FlowFixMe[incompatible-return]: assume body is always available
+ return node.ownerDocument.body;
+ }
+
+ if (isHTMLElement(node) && isScrollParent(node)) {
+ return node;
+ }
+
+ return getScrollParent(getParentNode(node));
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js
+
+
+
+
+/*
+given a DOM element, return the list of all scroll parents, up the list of ancesors
+until we get to the top window object. This list is what we attach scroll listeners
+to, because if any of these parent elements scroll, we'll need to re-calculate the
+reference element's position.
+*/
+
+function listScrollParents(element, list) {
+ var _element$ownerDocumen;
+
+ if (list === void 0) {
+ list = [];
+ }
+
+ var scrollParent = getScrollParent(element);
+ var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
+ var win = getWindow(scrollParent);
+ var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
+ var updatedList = list.concat(target);
+ return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
+ updatedList.concat(listScrollParents(getParentNode(target)));
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/isTableElement.js
+
+function isTableElement(element) {
+ return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js
+
+
+
+
+
+
+
+
+function getTrueOffsetParent(element) {
+ if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
+ getComputedStyle(element).position === 'fixed') {
+ return null;
+ }
+
+ return element.offsetParent;
+} // `.offsetParent` reports `null` for fixed elements, while absolute elements
+// return the containing block
+
+
+function getContainingBlock(element) {
+ var isFirefox = /firefox/i.test(getUAString());
+ var isIE = /Trident/i.test(getUAString());
+
+ if (isIE && isHTMLElement(element)) {
+ // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
+ var elementCss = getComputedStyle(element);
+
+ if (elementCss.position === 'fixed') {
+ return null;
}
- dispatchError() {
- this._onError.dispatch();
- this.logger.log("dispatchError");
+ }
+
+ var currentNode = getParentNode(element);
+
+ if (isShadowRoot(currentNode)) {
+ currentNode = currentNode.host;
+ }
+
+ while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
+ var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that
+ // create a containing block.
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
+
+ if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
+ return currentNode;
+ } else {
+ currentNode = currentNode.parentNode;
}
- submitForm() {
- const enForm = document.querySelector("form .en__submit button");
- if (enForm) {
- // Add submitting class to modal
- const enModal = document.getElementById("enModal");
- if (enModal)
- enModal.classList.add("is-submitting");
- enForm.click();
- this.logger.log("submitForm");
+ }
+
+ return null;
+} // Gets the closest ancestor positioned element. Handles some edge cases,
+// such as table ancestors and cross browser bugs.
+
+
+function getOffsetParent(element) {
+ var window = getWindow(element);
+ var offsetParent = getTrueOffsetParent(element);
+
+ while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {
+ offsetParent = getTrueOffsetParent(offsetParent);
+ }
+
+ if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {
+ return window;
+ }
+
+ return offsetParent || getContainingBlock(element) || window;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/enums.js
+var enums_top = 'top';
+var bottom = 'bottom';
+var right = 'right';
+var left = 'left';
+var auto = 'auto';
+var basePlacements = [enums_top, bottom, right, left];
+var start = 'start';
+var end = 'end';
+var clippingParents = 'clippingParents';
+var viewport = 'viewport';
+var popper = 'popper';
+var reference = 'reference';
+var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {
+ return acc.concat([placement + "-" + start, placement + "-" + end]);
+}, []);
+var enums_placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {
+ return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
+}, []); // modifiers that need to read the DOM
+
+var beforeRead = 'beforeRead';
+var read = 'read';
+var afterRead = 'afterRead'; // pure-logic modifiers
+
+var beforeMain = 'beforeMain';
+var main = 'main';
+var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)
+
+var beforeWrite = 'beforeWrite';
+var write = 'write';
+var afterWrite = 'afterWrite';
+var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/orderModifiers.js
+ // source: https://stackoverflow.com/questions/49875255
+
+function order(modifiers) {
+ var map = new Map();
+ var visited = new Set();
+ var result = [];
+ modifiers.forEach(function (modifier) {
+ map.set(modifier.name, modifier);
+ }); // On visiting object, check for its dependencies and visit them recursively
+
+ function sort(modifier) {
+ visited.add(modifier.name);
+ var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
+ requires.forEach(function (dep) {
+ if (!visited.has(dep)) {
+ var depModifier = map.get(dep);
+
+ if (depModifier) {
+ sort(depModifier);
}
+ }
+ });
+ result.push(modifier);
+ }
+
+ modifiers.forEach(function (modifier) {
+ if (!visited.has(modifier.name)) {
+ // check for visited object
+ sort(modifier);
}
- /**
- * onIntentSubmit is dispatched when a submit button is clicked,
- * or a digital wallet submission is initiated,
- * but before server-side validation or the actual submit event.
- * This allows you to run code at the moment the user intends to submit,
- * such as triggering data formatting, analytics events, or other pre-submit actions.
- * Actions that rely on fully processed form data or validation results should use the onSubmit event instead.
- * Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
- */
- get onIntentSubmit() {
- return this._onIntentSubmit.asEvent();
- }
- /**
- * onSubmit is dispatched when the form is submitted, after validation has passed.
- * This is the main event to listen to for form submissions, as it indicates that the user has successfully submitted the form and all validation checks have been passed.
- * This event uses window.enOnSubmit, which is called by Engaging Networks' JavaScript when the form is submitted.
- * At the time of writing, enOnSubmit does not trigger when a user submits via a digital wallet, use onIntentSubmit to listen for those submission attempts.
- * Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
- */
- get onSubmit() {
- return this._onSubmit.asEvent();
- }
- /**
- * onValidate is dispatched using window.enOnValidate, which is called by Engaging Networks' JavaScript
- * when the form is being validated, before submission. This only occurs after ENgrid's client-side validation has passed, but before server-side validation.
- */
- get onValidate() {
- return this._onValidate.asEvent();
- }
- /**
- * onError is dispatched using window.enOnError, which is called by Engaging Networks' JavaScript when a server-side validation error occurs on form submission.
- * This allows you to listen for validation errors and respond accordingly, such as displaying custom error messages or triggering analytics events.
- */
- get onError() {
- return this._onError.asEvent();
+ });
+ return result;
+}
+
+function orderModifiers(modifiers) {
+ // order based on dependencies
+ var orderedModifiers = order(modifiers); // order based on phase
+
+ return modifierPhases.reduce(function (acc, phase) {
+ return acc.concat(orderedModifiers.filter(function (modifier) {
+ return modifier.phase === phase;
+ }));
+ }, []);
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/debounce.js
+function debounce(fn) {
+ var pending;
+ return function () {
+ if (!pending) {
+ pending = new Promise(function (resolve) {
+ Promise.resolve().then(function () {
+ pending = undefined;
+ resolve(fn());
+ });
+ });
}
+
+ return pending;
+ };
}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/mergeByName.js
+function mergeByName(modifiers) {
+ var merged = modifiers.reduce(function (merged, current) {
+ var existing = merged[current.name];
+ merged[current.name] = existing ? Object.assign({}, existing, current, {
+ options: Object.assign({}, existing.options, current.options),
+ data: Object.assign({}, existing.data, current.data)
+ }) : current;
+ return merged;
+ }, {}); // IE11 does not support Object.values
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/donation-amount.js
+ return Object.keys(merged).map(function (key) {
+ return merged[key];
+ });
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/createPopper.js
-class DonationAmount {
- constructor(radios = "transaction.donationAmt", other = "transaction.donationAmt.other") {
- this._onAmountChange = new dist/* SimpleEventDispatcher */.IL();
- this._amount = 0;
- this._radios = "";
- this._other = "";
- this._dispatch = true;
- this._other = other;
- this._radios = radios;
- // Watch Radios Inputs for Changes
- document.addEventListener("change", (e) => {
- const element = e.target;
- if (element) {
- if (element.name == radios) {
- this.amount = parseFloat(element.value);
- }
- else if (element.name == other) {
- const cleanedAmount = engrid_ENGrid.cleanAmount(element.value);
- element.value =
- cleanedAmount % 1 != 0
- ? cleanedAmount.toFixed(2)
- : cleanedAmount.toString();
- this.amount = cleanedAmount;
- }
- }
- });
- // Watch Other Amount Field
- const otherField = document.querySelector(`[name='${this._other}']`);
- if (otherField) {
- otherField.addEventListener("keyup", (e) => {
- this.amount = engrid_ENGrid.cleanAmount(otherField.value);
- });
- }
- // Load the current amount
- this.load();
- }
- static getInstance(radios = "transaction.donationAmt", other = "transaction.donationAmt.other") {
- if (!DonationAmount.instance) {
- DonationAmount.instance = new DonationAmount(radios, other);
- }
- return DonationAmount.instance;
- }
- get amount() {
- return this._amount;
- }
- // Every time we set an amount, trigger the onAmountChange event
- set amount(value) {
- this._amount = value || 0;
- if (this._dispatch)
- this._onAmountChange.dispatch(this._amount);
- }
- get onAmountChange() {
- return this._onAmountChange.asEvent();
- }
- // Set amount var with currently selected amount
- load() {
- const currentAmountField = document.querySelector('input[name="' + this._radios + '"]:checked');
- if (currentAmountField) {
- let currentAmountValue = parseFloat(currentAmountField.value || "");
- if (currentAmountValue > 0) {
- this.amount = parseFloat(currentAmountField.value);
- }
- else {
- const otherField = document.querySelector('input[name="' + this._other + '"]');
- currentAmountValue = engrid_ENGrid.cleanAmount(otherField.value);
- this.amount = currentAmountValue;
- }
- }
- else if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationTotal") &&
- engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationFee")) {
- const total = window.EngagingNetworks.require._defined.enjs.getDonationTotal() -
- window.EngagingNetworks.require._defined.enjs.getDonationFee();
- if (total) {
- this.amount = total;
- }
- }
- }
- // Force a new amount
- setAmount(amount, dispatch = true) {
- // Run only if it is a Donation Page with a Donation Amount field
- if (!document.getElementsByName(this._radios).length) {
- return;
- }
- // Set dispatch to be checked by the SET method
- this._dispatch = dispatch;
- // Search for the current amount on radio boxes
- let found = Array.from(document.querySelectorAll('input[name="' + this._radios + '"]')).filter((el) => el instanceof HTMLInputElement && parseInt(el.value) == amount);
- // We found the amount on the radio boxes, so check it
- if (found.length) {
- const amountField = found[0];
- amountField.checked = true;
- // Change Event
- const event = new Event("change", {
- bubbles: true,
- cancelable: true,
- });
- amountField.dispatchEvent(event);
- // Clear OTHER text field
- this.clearOther();
- }
- else {
- const otherField = document.querySelector('input[name="' + this._other + '"]');
- if (otherField) {
- const enFieldOtherAmountRadio = document.querySelector(`.en__field--donationAmt.en__field--withOther .en__field__item:nth-last-child(2) input[name="${this._radios}"]`);
- if (enFieldOtherAmountRadio) {
- enFieldOtherAmountRadio.checked = true;
- }
- otherField.value = parseFloat(amount.toString()).toFixed(2);
- // Change Event
- const event = new Event("change", {
- bubbles: true,
- cancelable: true,
- });
- otherField.dispatchEvent(event);
- const otherWrapper = otherField.parentNode;
- otherWrapper.classList.remove("en__field__item--hidden");
- }
- }
- // Set the new amount and trigger all live variables
- this.amount = amount;
- // Revert dispatch to default value (true)
- this._dispatch = true;
- }
- // Clear Other Field
- clearOther() {
- const otherField = document.querySelector('input[name="' + this._other + '"]');
- otherField.value = "";
- const otherWrapper = otherField.parentNode;
- otherWrapper.classList.add("en__field__item--hidden");
- }
+
+
+
+
+
+
+
+var DEFAULT_OPTIONS = {
+ placement: 'bottom',
+ modifiers: [],
+ strategy: 'absolute'
+};
+
+function areValidElements() {
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ return !args.some(function (element) {
+ return !(element && typeof element.getBoundingClientRect === 'function');
+ });
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/engrid.js
-class engrid_ENGrid {
- constructor() {
- if (!engrid_ENGrid.enForm) {
- throw new Error("Engaging Networks Form Not Found!");
- }
- }
- static get enForm() {
- return document.querySelector("form.en__component");
- }
- static get debug() {
- return !!this.getOption("Debug");
- }
- static get demo() {
- return this.getUrlParameter("mode") === "DEMO";
- }
- // Return any parameter from the URL
- static getUrlParameter(name) {
- const searchParams = new URLSearchParams(window.location.search);
- // Add support for array on the name ending with []
- if (name.endsWith("[]")) {
- let values = [];
- searchParams.forEach((value, key) => {
- if (key.startsWith(name.replace("[]", ""))) {
- values.push(new Object({ [key]: value }));
- }
- });
- return values.length > 0 ? values : null;
- }
- if (searchParams.has(name)) {
- return searchParams.get(name) || true;
- }
- return null;
- }
- static getField(name) {
- // Get the field by name
- return document.querySelector(`[name="${name}"]`);
- }
- // Return the field value from its name. It works on any field type.
- // Multiple values (from checkboxes or multi-select) are returned as single string
- // Separated by ,
- static getFieldValue(name) {
- return new FormData(this.enForm).getAll(name).join(",");
+function popperGenerator(generatorOptions) {
+ if (generatorOptions === void 0) {
+ generatorOptions = {};
+ }
+
+ var _generatorOptions = generatorOptions,
+ _generatorOptions$def = _generatorOptions.defaultModifiers,
+ defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,
+ _generatorOptions$def2 = _generatorOptions.defaultOptions,
+ defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
+ return function createPopper(reference, popper, options) {
+ if (options === void 0) {
+ options = defaultOptions;
}
- // Set a value to any field. If it's a dropdown, radio or checkbox, it selects the proper option matching the value
- static setFieldValue(name, value, parseENDependencies = true, dispatchEvents = false) {
- if (value === engrid_ENGrid.getFieldValue(name))
- return;
- document.getElementsByName(name).forEach((field) => {
- if ("type" in field) {
- switch (field.type) {
- case "select-one":
- case "select-multiple":
- for (const option of field.options) {
- if (option.value == value) {
- option.selected = true;
- if (dispatchEvents) {
- field.dispatchEvent(new Event("change", { bubbles: true }));
- }
- }
- }
- break;
- case "checkbox":
- case "radio":
- if (field.value == value) {
- field.checked = true;
- if (dispatchEvents) {
- field.dispatchEvent(new Event("change", { bubbles: true }));
- }
- }
- break;
- case "textarea":
- case "text":
- default:
- field.value = value;
- if (dispatchEvents) {
- field.dispatchEvent(new Event("change", { bubbles: true }));
- field.dispatchEvent(new Event("blur", { bubbles: true }));
- }
- }
- field.setAttribute("engrid-value-changed", "");
- }
+
+ var state = {
+ placement: 'bottom',
+ orderedModifiers: [],
+ options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
+ modifiersData: {},
+ elements: {
+ reference: reference,
+ popper: popper
+ },
+ attributes: {},
+ styles: {}
+ };
+ var effectCleanupFns = [];
+ var isDestroyed = false;
+ var instance = {
+ state: state,
+ setOptions: function setOptions(setOptionsAction) {
+ var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;
+ cleanupModifierEffects();
+ state.options = Object.assign({}, defaultOptions, state.options, options);
+ state.scrollParents = {
+ reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],
+ popper: listScrollParents(popper)
+ }; // Orders the modifiers based on their dependencies and `phase`
+ // properties
+
+ var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers
+
+ state.orderedModifiers = orderedModifiers.filter(function (m) {
+ return m.enabled;
});
- if (parseENDependencies)
- this.enParseDependencies();
- return;
- }
- // Create a hidden input field
- static createHiddenInput(name, value = "") {
- var _a;
- const formBlock = document.createElement("div");
- formBlock.classList.add("en__component", "en__component--formblock", "hide");
- const textField = document.createElement("div");
- textField.classList.add("en__field", "en__field--text");
- const textElement = document.createElement("div");
- textElement.classList.add("en__field__element", "en__field__element--text");
- const inputField = document.createElement("input");
- inputField.classList.add("en__field__input", "en__field__input--text", "engrid-added-input");
- inputField.setAttribute("name", name);
- inputField.setAttribute("type", "hidden");
- inputField.setAttribute("value", value);
- textElement.appendChild(inputField);
- textField.appendChild(textElement);
- formBlock.appendChild(textField);
- const submitElement = document.querySelector(".en__submit");
- if (submitElement) {
- const lastFormComponent = submitElement.closest(".en__component");
- if (lastFormComponent) {
- // Insert the new field after the submit button
- (_a = lastFormComponent.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(formBlock, lastFormComponent.nextSibling);
- }
+ runModifierEffects();
+ return instance.update();
+ },
+ // Sync update β it will always be executed, even if not necessary. This
+ // is useful for low frequency updates where sync behavior simplifies the
+ // logic.
+ // For high frequency updates (e.g. `resize` and `scroll` events), always
+ // prefer the async Popper#update method
+ forceUpdate: function forceUpdate() {
+ if (isDestroyed) {
+ return;
}
- else {
- engrid_ENGrid.enForm.appendChild(formBlock);
+
+ var _state$elements = state.elements,
+ reference = _state$elements.reference,
+ popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements
+ // anymore
+
+ if (!areValidElements(reference, popper)) {
+ return;
+ } // Store the reference and popper rects to be read by modifiers
+
+
+ state.rects = {
+ reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),
+ popper: getLayoutRect(popper)
+ }; // Modifiers have the ability to reset the current update cycle. The
+ // most common use case for this is the `flip` modifier changing the
+ // placement, which then needs to re-run all the modifiers, because the
+ // logic was previously ran for the previous placement and is therefore
+ // stale/incorrect
+
+ state.reset = false;
+ state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier
+ // is filled with the initial data specified by the modifier. This means
+ // it doesn't persist and is fresh on each update.
+ // To ensure persistent data, use `${name}#persistent`
+
+ state.orderedModifiers.forEach(function (modifier) {
+ return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
+ });
+
+ for (var index = 0; index < state.orderedModifiers.length; index++) {
+ if (state.reset === true) {
+ state.reset = false;
+ index = -1;
+ continue;
+ }
+
+ var _state$orderedModifie = state.orderedModifiers[index],
+ fn = _state$orderedModifie.fn,
+ _state$orderedModifie2 = _state$orderedModifie.options,
+ _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,
+ name = _state$orderedModifie.name;
+
+ if (typeof fn === 'function') {
+ state = fn({
+ state: state,
+ options: _options,
+ name: name,
+ instance: instance
+ }) || state;
+ }
}
- return inputField;
+ },
+ // Async and optimistically optimized update β it will not be executed if
+ // not necessary (debounced to run at most once-per-tick)
+ update: debounce(function () {
+ return new Promise(function (resolve) {
+ instance.forceUpdate();
+ resolve(state);
+ });
+ }),
+ destroy: function destroy() {
+ cleanupModifierEffects();
+ isDestroyed = true;
+ }
+ };
+
+ if (!areValidElements(reference, popper)) {
+ return instance;
}
- // Trigger EN Dependencies
- static enParseDependencies() {
- var _a, _b, _c, _d, _e, _f;
- if (window.EngagingNetworks &&
- typeof ((_e = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enDependencies) === null || _d === void 0 ? void 0 : _d.dependencies) === null || _e === void 0 ? void 0 : _e.parseDependencies) === "function") {
- const customDependencies = [];
- if ("dependencies" in window.EngagingNetworks) {
- const amountContainer = document.querySelector(".en__field--donationAmt");
- if (amountContainer) {
- let amountID = ((_f = [...amountContainer.classList.values()]
- .filter((v) => v.startsWith("en__field--") && Number(v.substring(11)) > 0)
- .toString()
- .match(/\d/g)) === null || _f === void 0 ? void 0 : _f.join("")) || "";
- if (amountID) {
- window.EngagingNetworks.dependencies.forEach((dependency) => {
- if ("actions" in dependency && dependency.actions.length > 0) {
- let amountIdFound = false;
- dependency.actions.forEach((action) => {
- if ("target" in action && action.target == amountID) {
- amountIdFound = true;
- }
- });
- if (!amountIdFound) {
- customDependencies.push(dependency);
- }
- }
- });
- if (customDependencies.length > 0) {
- window.EngagingNetworks.require._defined.enDependencies.dependencies.parseDependencies(customDependencies);
- if (engrid_ENGrid.getOption("Debug"))
- console.log("EN Dependencies Triggered", customDependencies);
- }
- }
- }
- }
+
+ instance.setOptions(options).then(function (state) {
+ if (!isDestroyed && options.onFirstUpdate) {
+ options.onFirstUpdate(state);
+ }
+ }); // Modifiers have the ability to execute arbitrary code before the first
+ // update cycle runs. They will be executed in the same order as the update
+ // cycle. This is useful when a modifier adds some persistent data that
+ // other modifiers need to use, but the modifier is run after the dependent
+ // one.
+
+ function runModifierEffects() {
+ state.orderedModifiers.forEach(function (_ref) {
+ var name = _ref.name,
+ _ref$options = _ref.options,
+ options = _ref$options === void 0 ? {} : _ref$options,
+ effect = _ref.effect;
+
+ if (typeof effect === 'function') {
+ var cleanupFn = effect({
+ state: state,
+ name: name,
+ instance: instance,
+ options: options
+ });
+
+ var noopFn = function noopFn() {};
+
+ effectCleanupFns.push(cleanupFn || noopFn);
}
+ });
}
- // Return the status of the gift process (true if a donation has been made, otherwise false)
- static getGiftProcess() {
- if ("pageJson" in window)
- return window.pageJson.giftProcess;
- return null;
- }
- // Return the page count
- static getPageCount() {
- if ("pageJson" in window)
- return window.pageJson.pageCount;
- return null;
+
+ function cleanupModifierEffects() {
+ effectCleanupFns.forEach(function (fn) {
+ return fn();
+ });
+ effectCleanupFns = [];
}
- // Return the current page number
- static getPageNumber() {
- if ("pageJson" in window)
- return window.pageJson.pageNumber;
- return null;
+
+ return instance;
+ };
+}
+var createPopper = /*#__PURE__*/(/* unused pure expression or super */ null && (popperGenerator())); // eslint-disable-next-line import/no-unused-modules
+
+
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/eventListeners.js
+ // eslint-disable-next-line import/no-unused-modules
+
+var passive = {
+ passive: true
+};
+
+function effect(_ref) {
+ var state = _ref.state,
+ instance = _ref.instance,
+ options = _ref.options;
+ var _options$scroll = options.scroll,
+ scroll = _options$scroll === void 0 ? true : _options$scroll,
+ _options$resize = options.resize,
+ resize = _options$resize === void 0 ? true : _options$resize;
+ var window = getWindow(state.elements.popper);
+ var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
+
+ if (scroll) {
+ scrollParents.forEach(function (scrollParent) {
+ scrollParent.addEventListener('scroll', instance.update, passive);
+ });
+ }
+
+ if (resize) {
+ window.addEventListener('resize', instance.update, passive);
+ }
+
+ return function () {
+ if (scroll) {
+ scrollParents.forEach(function (scrollParent) {
+ scrollParent.removeEventListener('scroll', instance.update, passive);
+ });
}
- static isThankYouPage() {
- return this.getPageNumber() === this.getPageCount();
+
+ if (resize) {
+ window.removeEventListener('resize', instance.update, passive);
}
- // Return the current page ID
- static getPageID() {
- if ("pageJson" in window)
+ };
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const eventListeners = ({
+ name: 'eventListeners',
+ enabled: true,
+ phase: 'write',
+ fn: function fn() {},
+ effect: effect,
+ data: {}
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getBasePlacement.js
+
+function getBasePlacement(placement) {
+ return placement.split('-')[0];
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getVariation.js
+function getVariation(placement) {
+ return placement.split('-')[1];
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js
+function getMainAxisFromPlacement(placement) {
+ return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/computeOffsets.js
+
+
+
+
+function computeOffsets(_ref) {
+ var reference = _ref.reference,
+ element = _ref.element,
+ placement = _ref.placement;
+ var basePlacement = placement ? getBasePlacement(placement) : null;
+ var variation = placement ? getVariation(placement) : null;
+ var commonX = reference.x + reference.width / 2 - element.width / 2;
+ var commonY = reference.y + reference.height / 2 - element.height / 2;
+ var offsets;
+
+ switch (basePlacement) {
+ case enums_top:
+ offsets = {
+ x: commonX,
+ y: reference.y - element.height
+ };
+ break;
+
+ case bottom:
+ offsets = {
+ x: commonX,
+ y: reference.y + reference.height
+ };
+ break;
+
+ case right:
+ offsets = {
+ x: reference.x + reference.width,
+ y: commonY
+ };
+ break;
+
+ case left:
+ offsets = {
+ x: reference.x - element.width,
+ y: commonY
+ };
+ break;
+
+ default:
+ offsets = {
+ x: reference.x,
+ y: reference.y
+ };
+ }
+
+ var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
+
+ if (mainAxis != null) {
+ var len = mainAxis === 'y' ? 'height' : 'width';
+
+ switch (variation) {
+ case start:
+ offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);
+ break;
+
+ case end:
+ offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);
+ break;
+
+ default:
+ }
+ }
+
+ return offsets;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/popperOffsets.js
+
+
+function popperOffsets(_ref) {
+ var state = _ref.state,
+ name = _ref.name;
+ // Offsets are the actual position the popper needs to have to be
+ // properly positioned near its reference element
+ // This is the most basic placement, and will be adjusted by
+ // the modifiers in the next step
+ state.modifiersData[name] = computeOffsets({
+ reference: state.rects.reference,
+ element: state.rects.popper,
+ strategy: 'absolute',
+ placement: state.placement
+ });
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_popperOffsets = ({
+ name: 'popperOffsets',
+ enabled: true,
+ phase: 'read',
+ fn: popperOffsets,
+ data: {}
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/computeStyles.js
+
+
+
+
+
+
+
+ // eslint-disable-next-line import/no-unused-modules
+
+var unsetSides = {
+ top: 'auto',
+ right: 'auto',
+ bottom: 'auto',
+ left: 'auto'
+}; // Round the offsets to the nearest suitable subpixel based on the DPR.
+// Zooming can change the DPR, but it seems to report a value that will
+// cleanly divide the values into the appropriate subpixels.
+
+function roundOffsetsByDPR(_ref, win) {
+ var x = _ref.x,
+ y = _ref.y;
+ var dpr = win.devicePixelRatio || 1;
+ return {
+ x: round(x * dpr) / dpr || 0,
+ y: round(y * dpr) / dpr || 0
+ };
+}
+
+function mapToStyles(_ref2) {
+ var _Object$assign2;
+
+ var popper = _ref2.popper,
+ popperRect = _ref2.popperRect,
+ placement = _ref2.placement,
+ variation = _ref2.variation,
+ offsets = _ref2.offsets,
+ position = _ref2.position,
+ gpuAcceleration = _ref2.gpuAcceleration,
+ adaptive = _ref2.adaptive,
+ roundOffsets = _ref2.roundOffsets,
+ isFixed = _ref2.isFixed;
+ var _offsets$x = offsets.x,
+ x = _offsets$x === void 0 ? 0 : _offsets$x,
+ _offsets$y = offsets.y,
+ y = _offsets$y === void 0 ? 0 : _offsets$y;
+
+ var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({
+ x: x,
+ y: y
+ }) : {
+ x: x,
+ y: y
+ };
+
+ x = _ref3.x;
+ y = _ref3.y;
+ var hasX = offsets.hasOwnProperty('x');
+ var hasY = offsets.hasOwnProperty('y');
+ var sideX = left;
+ var sideY = enums_top;
+ var win = window;
+
+ if (adaptive) {
+ var offsetParent = getOffsetParent(popper);
+ var heightProp = 'clientHeight';
+ var widthProp = 'clientWidth';
+
+ if (offsetParent === getWindow(popper)) {
+ offsetParent = getDocumentElement(popper);
+
+ if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {
+ heightProp = 'scrollHeight';
+ widthProp = 'scrollWidth';
+ }
+ } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
+
+
+ offsetParent = offsetParent;
+
+ if (placement === enums_top || (placement === left || placement === right) && variation === end) {
+ sideY = bottom;
+ var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]
+ offsetParent[heightProp];
+ y -= offsetY - popperRect.height;
+ y *= gpuAcceleration ? 1 : -1;
+ }
+
+ if (placement === left || (placement === enums_top || placement === bottom) && variation === end) {
+ sideX = right;
+ var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]
+ offsetParent[widthProp];
+ x -= offsetX - popperRect.width;
+ x *= gpuAcceleration ? 1 : -1;
+ }
+ }
+
+ var commonStyles = Object.assign({
+ position: position
+ }, adaptive && unsetSides);
+
+ var _ref4 = roundOffsets === true ? roundOffsetsByDPR({
+ x: x,
+ y: y
+ }, getWindow(popper)) : {
+ x: x,
+ y: y
+ };
+
+ x = _ref4.x;
+ y = _ref4.y;
+
+ if (gpuAcceleration) {
+ var _Object$assign;
+
+ return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
+ }
+
+ return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
+}
+
+function computeStyles(_ref5) {
+ var state = _ref5.state,
+ options = _ref5.options;
+ var _options$gpuAccelerat = options.gpuAcceleration,
+ gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
+ _options$adaptive = options.adaptive,
+ adaptive = _options$adaptive === void 0 ? true : _options$adaptive,
+ _options$roundOffsets = options.roundOffsets,
+ roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
+ var commonStyles = {
+ placement: getBasePlacement(state.placement),
+ variation: getVariation(state.placement),
+ popper: state.elements.popper,
+ popperRect: state.rects.popper,
+ gpuAcceleration: gpuAcceleration,
+ isFixed: state.options.strategy === 'fixed'
+ };
+
+ if (state.modifiersData.popperOffsets != null) {
+ state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
+ offsets: state.modifiersData.popperOffsets,
+ position: state.options.strategy,
+ adaptive: adaptive,
+ roundOffsets: roundOffsets
+ })));
+ }
+
+ if (state.modifiersData.arrow != null) {
+ state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
+ offsets: state.modifiersData.arrow,
+ position: 'absolute',
+ adaptive: false,
+ roundOffsets: roundOffsets
+ })));
+ }
+
+ state.attributes.popper = Object.assign({}, state.attributes.popper, {
+ 'data-popper-placement': state.placement
+ });
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_computeStyles = ({
+ name: 'computeStyles',
+ enabled: true,
+ phase: 'beforeWrite',
+ fn: computeStyles,
+ data: {}
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/applyStyles.js
+
+ // This modifier takes the styles prepared by the `computeStyles` modifier
+// and applies them to the HTMLElements such as popper and arrow
+
+function applyStyles(_ref) {
+ var state = _ref.state;
+ Object.keys(state.elements).forEach(function (name) {
+ var style = state.styles[name] || {};
+ var attributes = state.attributes[name] || {};
+ var element = state.elements[name]; // arrow is optional + virtual elements
+
+ if (!isHTMLElement(element) || !getNodeName(element)) {
+ return;
+ } // Flow doesn't support to extend this property, but it's the most
+ // effective way to apply styles to an HTMLElement
+ // $FlowFixMe[cannot-write]
+
+
+ Object.assign(element.style, style);
+ Object.keys(attributes).forEach(function (name) {
+ var value = attributes[name];
+
+ if (value === false) {
+ element.removeAttribute(name);
+ } else {
+ element.setAttribute(name, value === true ? '' : value);
+ }
+ });
+ });
+}
+
+function applyStyles_effect(_ref2) {
+ var state = _ref2.state;
+ var initialStyles = {
+ popper: {
+ position: state.options.strategy,
+ left: '0',
+ top: '0',
+ margin: '0'
+ },
+ arrow: {
+ position: 'absolute'
+ },
+ reference: {}
+ };
+ Object.assign(state.elements.popper.style, initialStyles.popper);
+ state.styles = initialStyles;
+
+ if (state.elements.arrow) {
+ Object.assign(state.elements.arrow.style, initialStyles.arrow);
+ }
+
+ return function () {
+ Object.keys(state.elements).forEach(function (name) {
+ var element = state.elements[name];
+ var attributes = state.attributes[name] || {};
+ var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them
+
+ var style = styleProperties.reduce(function (style, property) {
+ style[property] = '';
+ return style;
+ }, {}); // arrow is optional + virtual elements
+
+ if (!isHTMLElement(element) || !getNodeName(element)) {
+ return;
+ }
+
+ Object.assign(element.style, style);
+ Object.keys(attributes).forEach(function (attribute) {
+ element.removeAttribute(attribute);
+ });
+ });
+ };
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_applyStyles = ({
+ name: 'applyStyles',
+ enabled: true,
+ phase: 'write',
+ fn: applyStyles,
+ effect: applyStyles_effect,
+ requires: ['computeStyles']
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/offset.js
+
+ // eslint-disable-next-line import/no-unused-modules
+
+function distanceAndSkiddingToXY(placement, rects, offset) {
+ var basePlacement = getBasePlacement(placement);
+ var invertDistance = [left, enums_top].indexOf(basePlacement) >= 0 ? -1 : 1;
+
+ var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {
+ placement: placement
+ })) : offset,
+ skidding = _ref[0],
+ distance = _ref[1];
+
+ skidding = skidding || 0;
+ distance = (distance || 0) * invertDistance;
+ return [left, right].indexOf(basePlacement) >= 0 ? {
+ x: distance,
+ y: skidding
+ } : {
+ x: skidding,
+ y: distance
+ };
+}
+
+function offset(_ref2) {
+ var state = _ref2.state,
+ options = _ref2.options,
+ name = _ref2.name;
+ var _options$offset = options.offset,
+ offset = _options$offset === void 0 ? [0, 0] : _options$offset;
+ var data = enums_placements.reduce(function (acc, placement) {
+ acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
+ return acc;
+ }, {});
+ var _data$state$placement = data[state.placement],
+ x = _data$state$placement.x,
+ y = _data$state$placement.y;
+
+ if (state.modifiersData.popperOffsets != null) {
+ state.modifiersData.popperOffsets.x += x;
+ state.modifiersData.popperOffsets.y += y;
+ }
+
+ state.modifiersData[name] = data;
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_offset = ({
+ name: 'offset',
+ enabled: true,
+ phase: 'main',
+ requires: ['popperOffsets'],
+ fn: offset
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getOppositePlacement.js
+var hash = {
+ left: 'right',
+ right: 'left',
+ bottom: 'top',
+ top: 'bottom'
+};
+function getOppositePlacement(placement) {
+ return placement.replace(/left|right|bottom|top/g, function (matched) {
+ return hash[matched];
+ });
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js
+var getOppositeVariationPlacement_hash = {
+ start: 'end',
+ end: 'start'
+};
+function getOppositeVariationPlacement(placement) {
+ return placement.replace(/start|end/g, function (matched) {
+ return getOppositeVariationPlacement_hash[matched];
+ });
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js
+
+
+
+
+function getViewportRect(element, strategy) {
+ var win = getWindow(element);
+ var html = getDocumentElement(element);
+ var visualViewport = win.visualViewport;
+ var width = html.clientWidth;
+ var height = html.clientHeight;
+ var x = 0;
+ var y = 0;
+
+ if (visualViewport) {
+ width = visualViewport.width;
+ height = visualViewport.height;
+ var layoutViewport = isLayoutViewport();
+
+ if (layoutViewport || !layoutViewport && strategy === 'fixed') {
+ x = visualViewport.offsetLeft;
+ y = visualViewport.offsetTop;
+ }
+ }
+
+ return {
+ width: width,
+ height: height,
+ x: x + getWindowScrollBarX(element),
+ y: y
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js
+
+
+
+
+ // Gets the entire size of the scrollable document area, even extending outside
+// of the `` and `
` rect bounds if horizontally scrollable
+
+function getDocumentRect(element) {
+ var _element$ownerDocumen;
+
+ var html = getDocumentElement(element);
+ var winScroll = getWindowScroll(element);
+ var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
+ var width = math_max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
+ var height = math_max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
+ var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
+ var y = -winScroll.scrollTop;
+
+ if (getComputedStyle(body || html).direction === 'rtl') {
+ x += math_max(html.clientWidth, body ? body.clientWidth : 0) - width;
+ }
+
+ return {
+ width: width,
+ height: height,
+ x: x,
+ y: y
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/contains.js
+
+function contains(parent, child) {
+ var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method
+
+ if (parent.contains(child)) {
+ return true;
+ } // then fallback to custom implementation with Shadow DOM support
+ else if (rootNode && isShadowRoot(rootNode)) {
+ var next = child;
+
+ do {
+ if (next && parent.isSameNode(next)) {
+ return true;
+ } // $FlowFixMe[prop-missing]: need a better way to handle this...
+
+
+ next = next.parentNode || next.host;
+ } while (next);
+ } // Give up, the result is false
+
+
+ return false;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/rectToClientRect.js
+function rectToClientRect(rect) {
+ return Object.assign({}, rect, {
+ left: rect.x,
+ top: rect.y,
+ right: rect.x + rect.width,
+ bottom: rect.y + rect.height
+ });
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function getInnerBoundingClientRect(element, strategy) {
+ var rect = getBoundingClientRect(element, false, strategy === 'fixed');
+ rect.top = rect.top + element.clientTop;
+ rect.left = rect.left + element.clientLeft;
+ rect.bottom = rect.top + element.clientHeight;
+ rect.right = rect.left + element.clientWidth;
+ rect.width = element.clientWidth;
+ rect.height = element.clientHeight;
+ rect.x = rect.left;
+ rect.y = rect.top;
+ return rect;
+}
+
+function getClientRectFromMixedType(element, clippingParent, strategy) {
+ return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
+} // A "clipping parent" is an overflowable container with the characteristic of
+// clipping (or hiding) overflowing elements with a position different from
+// `initial`
+
+
+function getClippingParents(element) {
+ var clippingParents = listScrollParents(getParentNode(element));
+ var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;
+ var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
+
+ if (!isElement(clipperElement)) {
+ return [];
+ } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414
+
+
+ return clippingParents.filter(function (clippingParent) {
+ return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
+ });
+} // Gets the maximum area that the element is visible in due to any number of
+// clipping parents
+
+
+function getClippingRect(element, boundary, rootBoundary, strategy) {
+ var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
+ var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
+ var firstClippingParent = clippingParents[0];
+ var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
+ var rect = getClientRectFromMixedType(element, clippingParent, strategy);
+ accRect.top = math_max(rect.top, accRect.top);
+ accRect.right = math_min(rect.right, accRect.right);
+ accRect.bottom = math_min(rect.bottom, accRect.bottom);
+ accRect.left = math_max(rect.left, accRect.left);
+ return accRect;
+ }, getClientRectFromMixedType(element, firstClippingParent, strategy));
+ clippingRect.width = clippingRect.right - clippingRect.left;
+ clippingRect.height = clippingRect.bottom - clippingRect.top;
+ clippingRect.x = clippingRect.left;
+ clippingRect.y = clippingRect.top;
+ return clippingRect;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getFreshSideObject.js
+function getFreshSideObject() {
+ return {
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ };
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/mergePaddingObject.js
+
+function mergePaddingObject(paddingObject) {
+ return Object.assign({}, getFreshSideObject(), paddingObject);
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/expandToHashMap.js
+function expandToHashMap(value, keys) {
+ return keys.reduce(function (hashMap, key) {
+ hashMap[key] = value;
+ return hashMap;
+ }, {});
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/detectOverflow.js
+
+
+
+
+
+
+
+
+ // eslint-disable-next-line import/no-unused-modules
+
+function detectOverflow(state, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var _options = options,
+ _options$placement = _options.placement,
+ placement = _options$placement === void 0 ? state.placement : _options$placement,
+ _options$strategy = _options.strategy,
+ strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,
+ _options$boundary = _options.boundary,
+ boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,
+ _options$rootBoundary = _options.rootBoundary,
+ rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,
+ _options$elementConte = _options.elementContext,
+ elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,
+ _options$altBoundary = _options.altBoundary,
+ altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,
+ _options$padding = _options.padding,
+ padding = _options$padding === void 0 ? 0 : _options$padding;
+ var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+ var altContext = elementContext === popper ? reference : popper;
+ var popperRect = state.rects.popper;
+ var element = state.elements[altBoundary ? altContext : elementContext];
+ var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);
+ var referenceClientRect = getBoundingClientRect(state.elements.reference);
+ var popperOffsets = computeOffsets({
+ reference: referenceClientRect,
+ element: popperRect,
+ strategy: 'absolute',
+ placement: placement
+ });
+ var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));
+ var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect
+ // 0 or negative = within the clipping rect
+
+ var overflowOffsets = {
+ top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
+ bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
+ left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
+ right: elementClientRect.right - clippingClientRect.right + paddingObject.right
+ };
+ var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element
+
+ if (elementContext === popper && offsetData) {
+ var offset = offsetData[placement];
+ Object.keys(overflowOffsets).forEach(function (key) {
+ var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
+ var axis = [enums_top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
+ overflowOffsets[key] += offset[axis] * multiply;
+ });
+ }
+
+ return overflowOffsets;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js
+
+
+
+
+function computeAutoPlacement(state, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var _options = options,
+ placement = _options.placement,
+ boundary = _options.boundary,
+ rootBoundary = _options.rootBoundary,
+ padding = _options.padding,
+ flipVariations = _options.flipVariations,
+ _options$allowedAutoP = _options.allowedAutoPlacements,
+ allowedAutoPlacements = _options$allowedAutoP === void 0 ? enums_placements : _options$allowedAutoP;
+ var variation = getVariation(placement);
+ var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {
+ return getVariation(placement) === variation;
+ }) : basePlacements;
+ var allowedPlacements = placements.filter(function (placement) {
+ return allowedAutoPlacements.indexOf(placement) >= 0;
+ });
+
+ if (allowedPlacements.length === 0) {
+ allowedPlacements = placements;
+ } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...
+
+
+ var overflows = allowedPlacements.reduce(function (acc, placement) {
+ acc[placement] = detectOverflow(state, {
+ placement: placement,
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ padding: padding
+ })[getBasePlacement(placement)];
+ return acc;
+ }, {});
+ return Object.keys(overflows).sort(function (a, b) {
+ return overflows[a] - overflows[b];
+ });
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/flip.js
+
+
+
+
+
+
+ // eslint-disable-next-line import/no-unused-modules
+
+function getExpandedFallbackPlacements(placement) {
+ if (getBasePlacement(placement) === auto) {
+ return [];
+ }
+
+ var oppositePlacement = getOppositePlacement(placement);
+ return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
+}
+
+function flip(_ref) {
+ var state = _ref.state,
+ options = _ref.options,
+ name = _ref.name;
+
+ if (state.modifiersData[name]._skip) {
+ return;
+ }
+
+ var _options$mainAxis = options.mainAxis,
+ checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+ _options$altAxis = options.altAxis,
+ checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,
+ specifiedFallbackPlacements = options.fallbackPlacements,
+ padding = options.padding,
+ boundary = options.boundary,
+ rootBoundary = options.rootBoundary,
+ altBoundary = options.altBoundary,
+ _options$flipVariatio = options.flipVariations,
+ flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,
+ allowedAutoPlacements = options.allowedAutoPlacements;
+ var preferredPlacement = state.options.placement;
+ var basePlacement = getBasePlacement(preferredPlacement);
+ var isBasePlacement = basePlacement === preferredPlacement;
+ var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
+ var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {
+ return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {
+ placement: placement,
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ padding: padding,
+ flipVariations: flipVariations,
+ allowedAutoPlacements: allowedAutoPlacements
+ }) : placement);
+ }, []);
+ var referenceRect = state.rects.reference;
+ var popperRect = state.rects.popper;
+ var checksMap = new Map();
+ var makeFallbackChecks = true;
+ var firstFittingPlacement = placements[0];
+
+ for (var i = 0; i < placements.length; i++) {
+ var placement = placements[i];
+
+ var _basePlacement = getBasePlacement(placement);
+
+ var isStartVariation = getVariation(placement) === start;
+ var isVertical = [enums_top, bottom].indexOf(_basePlacement) >= 0;
+ var len = isVertical ? 'width' : 'height';
+ var overflow = detectOverflow(state, {
+ placement: placement,
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ altBoundary: altBoundary,
+ padding: padding
+ });
+ var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : enums_top;
+
+ if (referenceRect[len] > popperRect[len]) {
+ mainVariationSide = getOppositePlacement(mainVariationSide);
+ }
+
+ var altVariationSide = getOppositePlacement(mainVariationSide);
+ var checks = [];
+
+ if (checkMainAxis) {
+ checks.push(overflow[_basePlacement] <= 0);
+ }
+
+ if (checkAltAxis) {
+ checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
+ }
+
+ if (checks.every(function (check) {
+ return check;
+ })) {
+ firstFittingPlacement = placement;
+ makeFallbackChecks = false;
+ break;
+ }
+
+ checksMap.set(placement, checks);
+ }
+
+ if (makeFallbackChecks) {
+ // `2` may be desired in some cases β research later
+ var numberOfChecks = flipVariations ? 3 : 1;
+
+ var _loop = function _loop(_i) {
+ var fittingPlacement = placements.find(function (placement) {
+ var checks = checksMap.get(placement);
+
+ if (checks) {
+ return checks.slice(0, _i).every(function (check) {
+ return check;
+ });
+ }
+ });
+
+ if (fittingPlacement) {
+ firstFittingPlacement = fittingPlacement;
+ return "break";
+ }
+ };
+
+ for (var _i = numberOfChecks; _i > 0; _i--) {
+ var _ret = _loop(_i);
+
+ if (_ret === "break") break;
+ }
+ }
+
+ if (state.placement !== firstFittingPlacement) {
+ state.modifiersData[name]._skip = true;
+ state.placement = firstFittingPlacement;
+ state.reset = true;
+ }
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_flip = ({
+ name: 'flip',
+ enabled: true,
+ phase: 'main',
+ fn: flip,
+ requiresIfExists: ['offset'],
+ data: {
+ _skip: false
+ }
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/getAltAxis.js
+function getAltAxis(axis) {
+ return axis === 'x' ? 'y' : 'x';
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/utils/within.js
+
+function within(min, value, max) {
+ return math_max(min, math_min(value, max));
+}
+function withinMaxClamp(min, value, max) {
+ var v = within(min, value, max);
+ return v > max ? max : v;
+}
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/preventOverflow.js
+
+
+
+
+
+
+
+
+
+
+
+
+function preventOverflow(_ref) {
+ var state = _ref.state,
+ options = _ref.options,
+ name = _ref.name;
+ var _options$mainAxis = options.mainAxis,
+ checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+ _options$altAxis = options.altAxis,
+ checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
+ boundary = options.boundary,
+ rootBoundary = options.rootBoundary,
+ altBoundary = options.altBoundary,
+ padding = options.padding,
+ _options$tether = options.tether,
+ tether = _options$tether === void 0 ? true : _options$tether,
+ _options$tetherOffset = options.tetherOffset,
+ tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
+ var overflow = detectOverflow(state, {
+ boundary: boundary,
+ rootBoundary: rootBoundary,
+ padding: padding,
+ altBoundary: altBoundary
+ });
+ var basePlacement = getBasePlacement(state.placement);
+ var variation = getVariation(state.placement);
+ var isBasePlacement = !variation;
+ var mainAxis = getMainAxisFromPlacement(basePlacement);
+ var altAxis = getAltAxis(mainAxis);
+ var popperOffsets = state.modifiersData.popperOffsets;
+ var referenceRect = state.rects.reference;
+ var popperRect = state.rects.popper;
+ var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {
+ placement: state.placement
+ })) : tetherOffset;
+ var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {
+ mainAxis: tetherOffsetValue,
+ altAxis: tetherOffsetValue
+ } : Object.assign({
+ mainAxis: 0,
+ altAxis: 0
+ }, tetherOffsetValue);
+ var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;
+ var data = {
+ x: 0,
+ y: 0
+ };
+
+ if (!popperOffsets) {
+ return;
+ }
+
+ if (checkMainAxis) {
+ var _offsetModifierState$;
+
+ var mainSide = mainAxis === 'y' ? enums_top : left;
+ var altSide = mainAxis === 'y' ? bottom : right;
+ var len = mainAxis === 'y' ? 'height' : 'width';
+ var offset = popperOffsets[mainAxis];
+ var min = offset + overflow[mainSide];
+ var max = offset - overflow[altSide];
+ var additive = tether ? -popperRect[len] / 2 : 0;
+ var minLen = variation === start ? referenceRect[len] : popperRect[len];
+ var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
+ // outside the reference bounds
+
+ var arrowElement = state.elements.arrow;
+ var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
+ width: 0,
+ height: 0
+ };
+ var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
+ var arrowPaddingMin = arrowPaddingObject[mainSide];
+ var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
+ // to include its full size in the calculation. If the reference is small
+ // and near the edge of a boundary, the popper can overflow even if the
+ // reference is not overflowing as well (e.g. virtual elements with no
+ // width or height)
+
+ var arrowLen = within(0, referenceRect[len], arrowRect[len]);
+ var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;
+ var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;
+ var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
+ var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
+ var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;
+ var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;
+ var tetherMax = offset + maxOffset - offsetModifierValue;
+ var preventedOffset = within(tether ? math_min(min, tetherMin) : min, offset, tether ? math_max(max, tetherMax) : max);
+ popperOffsets[mainAxis] = preventedOffset;
+ data[mainAxis] = preventedOffset - offset;
+ }
+
+ if (checkAltAxis) {
+ var _offsetModifierState$2;
+
+ var _mainSide = mainAxis === 'x' ? enums_top : left;
+
+ var _altSide = mainAxis === 'x' ? bottom : right;
+
+ var _offset = popperOffsets[altAxis];
+
+ var _len = altAxis === 'y' ? 'height' : 'width';
+
+ var _min = _offset + overflow[_mainSide];
+
+ var _max = _offset - overflow[_altSide];
+
+ var isOriginSide = [enums_top, left].indexOf(basePlacement) !== -1;
+
+ var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;
+
+ var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;
+
+ var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;
+
+ var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);
+
+ popperOffsets[altAxis] = _preventedOffset;
+ data[altAxis] = _preventedOffset - _offset;
+ }
+
+ state.modifiersData[name] = data;
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_preventOverflow = ({
+ name: 'preventOverflow',
+ enabled: true,
+ phase: 'main',
+ fn: preventOverflow,
+ requiresIfExists: ['offset']
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/arrow.js
+
+
+
+
+
+
+
+
+ // eslint-disable-next-line import/no-unused-modules
+
+var toPaddingObject = function toPaddingObject(padding, state) {
+ padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {
+ placement: state.placement
+ })) : padding;
+ return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+};
+
+function arrow(_ref) {
+ var _state$modifiersData$;
+
+ var state = _ref.state,
+ name = _ref.name,
+ options = _ref.options;
+ var arrowElement = state.elements.arrow;
+ var popperOffsets = state.modifiersData.popperOffsets;
+ var basePlacement = getBasePlacement(state.placement);
+ var axis = getMainAxisFromPlacement(basePlacement);
+ var isVertical = [left, right].indexOf(basePlacement) >= 0;
+ var len = isVertical ? 'height' : 'width';
+
+ if (!arrowElement || !popperOffsets) {
+ return;
+ }
+
+ var paddingObject = toPaddingObject(options.padding, state);
+ var arrowRect = getLayoutRect(arrowElement);
+ var minProp = axis === 'y' ? enums_top : left;
+ var maxProp = axis === 'y' ? bottom : right;
+ var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];
+ var startDiff = popperOffsets[axis] - state.rects.reference[axis];
+ var arrowOffsetParent = getOffsetParent(arrowElement);
+ var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
+ var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is
+ // outside of the popper bounds
+
+ var min = paddingObject[minProp];
+ var max = clientSize - arrowRect[len] - paddingObject[maxProp];
+ var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
+ var offset = within(min, center, max); // Prevents breaking syntax highlighting...
+
+ var axisProp = axis;
+ state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);
+}
+
+function arrow_effect(_ref2) {
+ var state = _ref2.state,
+ options = _ref2.options;
+ var _options$element = options.element,
+ arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;
+
+ if (arrowElement == null) {
+ return;
+ } // CSS selector
+
+
+ if (typeof arrowElement === 'string') {
+ arrowElement = state.elements.popper.querySelector(arrowElement);
+
+ if (!arrowElement) {
+ return;
+ }
+ }
+
+ if (!contains(state.elements.popper, arrowElement)) {
+ return;
+ }
+
+ state.elements.arrow = arrowElement;
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_arrow = ({
+ name: 'arrow',
+ enabled: true,
+ phase: 'main',
+ fn: arrow,
+ effect: arrow_effect,
+ requires: ['popperOffsets'],
+ requiresIfExists: ['preventOverflow']
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/modifiers/hide.js
+
+
+
+function getSideOffsets(overflow, rect, preventedOffsets) {
+ if (preventedOffsets === void 0) {
+ preventedOffsets = {
+ x: 0,
+ y: 0
+ };
+ }
+
+ return {
+ top: overflow.top - rect.height - preventedOffsets.y,
+ right: overflow.right - rect.width + preventedOffsets.x,
+ bottom: overflow.bottom - rect.height + preventedOffsets.y,
+ left: overflow.left - rect.width - preventedOffsets.x
+ };
+}
+
+function isAnySideFullyClipped(overflow) {
+ return [enums_top, right, bottom, left].some(function (side) {
+ return overflow[side] >= 0;
+ });
+}
+
+function hide(_ref) {
+ var state = _ref.state,
+ name = _ref.name;
+ var referenceRect = state.rects.reference;
+ var popperRect = state.rects.popper;
+ var preventedOffsets = state.modifiersData.preventOverflow;
+ var referenceOverflow = detectOverflow(state, {
+ elementContext: 'reference'
+ });
+ var popperAltOverflow = detectOverflow(state, {
+ altBoundary: true
+ });
+ var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
+ var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
+ var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
+ var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
+ state.modifiersData[name] = {
+ referenceClippingOffsets: referenceClippingOffsets,
+ popperEscapeOffsets: popperEscapeOffsets,
+ isReferenceHidden: isReferenceHidden,
+ hasPopperEscaped: hasPopperEscaped
+ };
+ state.attributes.popper = Object.assign({}, state.attributes.popper, {
+ 'data-popper-reference-hidden': isReferenceHidden,
+ 'data-popper-escaped': hasPopperEscaped
+ });
+} // eslint-disable-next-line import/no-unused-modules
+
+
+/* harmony default export */ const modifiers_hide = ({
+ name: 'hide',
+ enabled: true,
+ phase: 'main',
+ requiresIfExists: ['preventOverflow'],
+ fn: hide
+});
+;// CONCATENATED MODULE: ../engrid/node_modules/@popperjs/core/lib/popper.js
+
+
+
+
+
+
+
+
+
+
+var defaultModifiers = [eventListeners, modifiers_popperOffsets, modifiers_computeStyles, modifiers_applyStyles, modifiers_offset, modifiers_flip, modifiers_preventOverflow, modifiers_arrow, modifiers_hide];
+var popper_createPopper = /*#__PURE__*/popperGenerator({
+ defaultModifiers: defaultModifiers
+}); // eslint-disable-next-line import/no-unused-modules
+
+ // eslint-disable-next-line import/no-unused-modules
+
+ // eslint-disable-next-line import/no-unused-modules
+
+
+;// CONCATENATED MODULE: ../engrid/node_modules/tippy.js/dist/tippy.esm.js
+/**!
+* tippy.js v6.3.7
+* (c) 2017-2021 atomiks
+* MIT License
+*/
+
+
+var ROUND_ARROW = ' ';
+var BOX_CLASS = "tippy-box";
+var CONTENT_CLASS = "tippy-content";
+var BACKDROP_CLASS = "tippy-backdrop";
+var ARROW_CLASS = "tippy-arrow";
+var SVG_ARROW_CLASS = "tippy-svg-arrow";
+var TOUCH_OPTIONS = {
+ passive: true,
+ capture: true
+};
+var TIPPY_DEFAULT_APPEND_TO = function TIPPY_DEFAULT_APPEND_TO() {
+ return document.body;
+};
+
+function tippy_esm_hasOwnProperty(obj, key) {
+ return {}.hasOwnProperty.call(obj, key);
+}
+function getValueAtIndexOrReturn(value, index, defaultValue) {
+ if (Array.isArray(value)) {
+ var v = value[index];
+ return v == null ? Array.isArray(defaultValue) ? defaultValue[index] : defaultValue : v;
+ }
+
+ return value;
+}
+function isType(value, type) {
+ var str = {}.toString.call(value);
+ return str.indexOf('[object') === 0 && str.indexOf(type + "]") > -1;
+}
+function invokeWithArgsOrReturn(value, args) {
+ return typeof value === 'function' ? value.apply(void 0, args) : value;
+}
+function tippy_esm_debounce(fn, ms) {
+ // Avoid wrapping in `setTimeout` if ms is 0 anyway
+ if (ms === 0) {
+ return fn;
+ }
+
+ var timeout;
+ return function (arg) {
+ clearTimeout(timeout);
+ timeout = setTimeout(function () {
+ fn(arg);
+ }, ms);
+ };
+}
+function removeProperties(obj, keys) {
+ var clone = Object.assign({}, obj);
+ keys.forEach(function (key) {
+ delete clone[key];
+ });
+ return clone;
+}
+function splitBySpaces(value) {
+ return value.split(/\s+/).filter(Boolean);
+}
+function normalizeToArray(value) {
+ return [].concat(value);
+}
+function pushIfUnique(arr, value) {
+ if (arr.indexOf(value) === -1) {
+ arr.push(value);
+ }
+}
+function unique(arr) {
+ return arr.filter(function (item, index) {
+ return arr.indexOf(item) === index;
+ });
+}
+function tippy_esm_getBasePlacement(placement) {
+ return placement.split('-')[0];
+}
+function arrayFrom(value) {
+ return [].slice.call(value);
+}
+function removeUndefinedProps(obj) {
+ return Object.keys(obj).reduce(function (acc, key) {
+ if (obj[key] !== undefined) {
+ acc[key] = obj[key];
+ }
+
+ return acc;
+ }, {});
+}
+
+function div() {
+ return document.createElement('div');
+}
+function tippy_esm_isElement(value) {
+ return ['Element', 'Fragment'].some(function (type) {
+ return isType(value, type);
+ });
+}
+function isNodeList(value) {
+ return isType(value, 'NodeList');
+}
+function isMouseEvent(value) {
+ return isType(value, 'MouseEvent');
+}
+function isReferenceElement(value) {
+ return !!(value && value._tippy && value._tippy.reference === value);
+}
+function getArrayOfElements(value) {
+ if (tippy_esm_isElement(value)) {
+ return [value];
+ }
+
+ if (isNodeList(value)) {
+ return arrayFrom(value);
+ }
+
+ if (Array.isArray(value)) {
+ return value;
+ }
+
+ return arrayFrom(document.querySelectorAll(value));
+}
+function setTransitionDuration(els, value) {
+ els.forEach(function (el) {
+ if (el) {
+ el.style.transitionDuration = value + "ms";
+ }
+ });
+}
+function setVisibilityState(els, state) {
+ els.forEach(function (el) {
+ if (el) {
+ el.setAttribute('data-state', state);
+ }
+ });
+}
+function getOwnerDocument(elementOrElements) {
+ var _element$ownerDocumen;
+
+ var _normalizeToArray = normalizeToArray(elementOrElements),
+ element = _normalizeToArray[0]; // Elements created via a have an ownerDocument with no reference to the body
+
+
+ return element != null && (_element$ownerDocumen = element.ownerDocument) != null && _element$ownerDocumen.body ? element.ownerDocument : document;
+}
+function isCursorOutsideInteractiveBorder(popperTreeData, event) {
+ var clientX = event.clientX,
+ clientY = event.clientY;
+ return popperTreeData.every(function (_ref) {
+ var popperRect = _ref.popperRect,
+ popperState = _ref.popperState,
+ props = _ref.props;
+ var interactiveBorder = props.interactiveBorder;
+ var basePlacement = tippy_esm_getBasePlacement(popperState.placement);
+ var offsetData = popperState.modifiersData.offset;
+
+ if (!offsetData) {
+ return true;
+ }
+
+ var topDistance = basePlacement === 'bottom' ? offsetData.top.y : 0;
+ var bottomDistance = basePlacement === 'top' ? offsetData.bottom.y : 0;
+ var leftDistance = basePlacement === 'right' ? offsetData.left.x : 0;
+ var rightDistance = basePlacement === 'left' ? offsetData.right.x : 0;
+ var exceedsTop = popperRect.top - clientY + topDistance > interactiveBorder;
+ var exceedsBottom = clientY - popperRect.bottom - bottomDistance > interactiveBorder;
+ var exceedsLeft = popperRect.left - clientX + leftDistance > interactiveBorder;
+ var exceedsRight = clientX - popperRect.right - rightDistance > interactiveBorder;
+ return exceedsTop || exceedsBottom || exceedsLeft || exceedsRight;
+ });
+}
+function updateTransitionEndListener(box, action, listener) {
+ var method = action + "EventListener"; // some browsers apparently support `transition` (unprefixed) but only fire
+ // `webkitTransitionEnd`...
+
+ ['transitionend', 'webkitTransitionEnd'].forEach(function (event) {
+ box[method](event, listener);
+ });
+}
+/**
+ * Compared to xxx.contains, this function works for dom structures with shadow
+ * dom
+ */
+
+function actualContains(parent, child) {
+ var target = child;
+
+ while (target) {
+ var _target$getRootNode;
+
+ if (parent.contains(target)) {
+ return true;
+ }
+
+ target = target.getRootNode == null ? void 0 : (_target$getRootNode = target.getRootNode()) == null ? void 0 : _target$getRootNode.host;
+ }
+
+ return false;
+}
+
+var currentInput = {
+ isTouch: false
+};
+var lastMouseMoveTime = 0;
+/**
+ * When a `touchstart` event is fired, it's assumed the user is using touch
+ * input. We'll bind a `mousemove` event listener to listen for mouse input in
+ * the future. This way, the `isTouch` property is fully dynamic and will handle
+ * hybrid devices that use a mix of touch + mouse input.
+ */
+
+function onDocumentTouchStart() {
+ if (currentInput.isTouch) {
+ return;
+ }
+
+ currentInput.isTouch = true;
+
+ if (window.performance) {
+ document.addEventListener('mousemove', onDocumentMouseMove);
+ }
+}
+/**
+ * When two `mousemove` event are fired consecutively within 20ms, it's assumed
+ * the user is using mouse input again. `mousemove` can fire on touch devices as
+ * well, but very rarely that quickly.
+ */
+
+function onDocumentMouseMove() {
+ var now = performance.now();
+
+ if (now - lastMouseMoveTime < 20) {
+ currentInput.isTouch = false;
+ document.removeEventListener('mousemove', onDocumentMouseMove);
+ }
+
+ lastMouseMoveTime = now;
+}
+/**
+ * When an element is in focus and has a tippy, leaving the tab/window and
+ * returning causes it to show again. For mouse users this is unexpected, but
+ * for keyboard use it makes sense.
+ * TODO: find a better technique to solve this problem
+ */
+
+function onWindowBlur() {
+ var activeElement = document.activeElement;
+
+ if (isReferenceElement(activeElement)) {
+ var instance = activeElement._tippy;
+
+ if (activeElement.blur && !instance.state.isVisible) {
+ activeElement.blur();
+ }
+ }
+}
+function bindGlobalEventListeners() {
+ document.addEventListener('touchstart', onDocumentTouchStart, TOUCH_OPTIONS);
+ window.addEventListener('blur', onWindowBlur);
+}
+
+var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
+var isIE11 = isBrowser ? // @ts-ignore
+!!window.msCrypto : false;
+
+function createMemoryLeakWarning(method) {
+ var txt = method === 'destroy' ? 'n already-' : ' ';
+ return [method + "() was called on a" + txt + "destroyed instance. This is a no-op but", 'indicates a potential memory leak.'].join(' ');
+}
+function clean(value) {
+ var spacesAndTabs = /[ \t]{2,}/g;
+ var lineStartWithSpaces = /^[ \t]*/gm;
+ return value.replace(spacesAndTabs, ' ').replace(lineStartWithSpaces, '').trim();
+}
+
+function getDevMessage(message) {
+ return clean("\n %ctippy.js\n\n %c" + clean(message) + "\n\n %c\uD83D\uDC77\u200D This is a development-only message. It will be removed in production.\n ");
+}
+
+function getFormattedMessage(message) {
+ return [getDevMessage(message), // title
+ 'color: #00C584; font-size: 1.3em; font-weight: bold;', // message
+ 'line-height: 1.5', // footer
+ 'color: #a6a095;'];
+} // Assume warnings and errors never have the same message
+
+var visitedMessages;
+
+if (false) {}
+
+function resetVisitedMessages() {
+ visitedMessages = new Set();
+}
+function warnWhen(condition, message) {
+ if (condition && !visitedMessages.has(message)) {
+ var _console;
+
+ visitedMessages.add(message);
+
+ (_console = console).warn.apply(_console, getFormattedMessage(message));
+ }
+}
+function errorWhen(condition, message) {
+ if (condition && !visitedMessages.has(message)) {
+ var _console2;
+
+ visitedMessages.add(message);
+
+ (_console2 = console).error.apply(_console2, getFormattedMessage(message));
+ }
+}
+function validateTargets(targets) {
+ var didPassFalsyValue = !targets;
+ var didPassPlainObject = Object.prototype.toString.call(targets) === '[object Object]' && !targets.addEventListener;
+ errorWhen(didPassFalsyValue, ['tippy() was passed', '`' + String(targets) + '`', 'as its targets (first) argument. Valid types are: String, Element,', 'Element[], or NodeList.'].join(' '));
+ errorWhen(didPassPlainObject, ['tippy() was passed a plain object which is not supported as an argument', 'for virtual positioning. Use props.getReferenceClientRect instead.'].join(' '));
+}
+
+var pluginProps = {
+ animateFill: false,
+ followCursor: false,
+ inlinePositioning: false,
+ sticky: false
+};
+var renderProps = {
+ allowHTML: false,
+ animation: 'fade',
+ arrow: true,
+ content: '',
+ inertia: false,
+ maxWidth: 350,
+ role: 'tooltip',
+ theme: '',
+ zIndex: 9999
+};
+var defaultProps = Object.assign({
+ appendTo: TIPPY_DEFAULT_APPEND_TO,
+ aria: {
+ content: 'auto',
+ expanded: 'auto'
+ },
+ delay: 0,
+ duration: [300, 250],
+ getReferenceClientRect: null,
+ hideOnClick: true,
+ ignoreAttributes: false,
+ interactive: false,
+ interactiveBorder: 2,
+ interactiveDebounce: 0,
+ moveTransition: '',
+ offset: [0, 10],
+ onAfterUpdate: function onAfterUpdate() {},
+ onBeforeUpdate: function onBeforeUpdate() {},
+ onCreate: function onCreate() {},
+ onDestroy: function onDestroy() {},
+ onHidden: function onHidden() {},
+ onHide: function onHide() {},
+ onMount: function onMount() {},
+ onShow: function onShow() {},
+ onShown: function onShown() {},
+ onTrigger: function onTrigger() {},
+ onUntrigger: function onUntrigger() {},
+ onClickOutside: function onClickOutside() {},
+ placement: 'top',
+ plugins: [],
+ popperOptions: {},
+ render: null,
+ showOnCreate: false,
+ touch: true,
+ trigger: 'mouseenter focus',
+ triggerTarget: null
+}, pluginProps, renderProps);
+var defaultKeys = Object.keys(defaultProps);
+var setDefaultProps = function setDefaultProps(partialProps) {
+ /* istanbul ignore else */
+ if (false) {}
+
+ var keys = Object.keys(partialProps);
+ keys.forEach(function (key) {
+ defaultProps[key] = partialProps[key];
+ });
+};
+function getExtendedPassedProps(passedProps) {
+ var plugins = passedProps.plugins || [];
+ var pluginProps = plugins.reduce(function (acc, plugin) {
+ var name = plugin.name,
+ defaultValue = plugin.defaultValue;
+
+ if (name) {
+ var _name;
+
+ acc[name] = passedProps[name] !== undefined ? passedProps[name] : (_name = defaultProps[name]) != null ? _name : defaultValue;
+ }
+
+ return acc;
+ }, {});
+ return Object.assign({}, passedProps, pluginProps);
+}
+function getDataAttributeProps(reference, plugins) {
+ var propKeys = plugins ? Object.keys(getExtendedPassedProps(Object.assign({}, defaultProps, {
+ plugins: plugins
+ }))) : defaultKeys;
+ var props = propKeys.reduce(function (acc, key) {
+ var valueAsString = (reference.getAttribute("data-tippy-" + key) || '').trim();
+
+ if (!valueAsString) {
+ return acc;
+ }
+
+ if (key === 'content') {
+ acc[key] = valueAsString;
+ } else {
+ try {
+ acc[key] = JSON.parse(valueAsString);
+ } catch (e) {
+ acc[key] = valueAsString;
+ }
+ }
+
+ return acc;
+ }, {});
+ return props;
+}
+function evaluateProps(reference, props) {
+ var out = Object.assign({}, props, {
+ content: invokeWithArgsOrReturn(props.content, [reference])
+ }, props.ignoreAttributes ? {} : getDataAttributeProps(reference, props.plugins));
+ out.aria = Object.assign({}, defaultProps.aria, out.aria);
+ out.aria = {
+ expanded: out.aria.expanded === 'auto' ? props.interactive : out.aria.expanded,
+ content: out.aria.content === 'auto' ? props.interactive ? null : 'describedby' : out.aria.content
+ };
+ return out;
+}
+function validateProps(partialProps, plugins) {
+ if (partialProps === void 0) {
+ partialProps = {};
+ }
+
+ if (plugins === void 0) {
+ plugins = [];
+ }
+
+ var keys = Object.keys(partialProps);
+ keys.forEach(function (prop) {
+ var nonPluginProps = removeProperties(defaultProps, Object.keys(pluginProps));
+ var didPassUnknownProp = !tippy_esm_hasOwnProperty(nonPluginProps, prop); // Check if the prop exists in `plugins`
+
+ if (didPassUnknownProp) {
+ didPassUnknownProp = plugins.filter(function (plugin) {
+ return plugin.name === prop;
+ }).length === 0;
+ }
+
+ warnWhen(didPassUnknownProp, ["`" + prop + "`", "is not a valid prop. You may have spelled it incorrectly, or if it's", 'a plugin, forgot to pass it in an array as props.plugins.', '\n\n', 'All props: https://atomiks.github.io/tippyjs/v6/all-props/\n', 'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/'].join(' '));
+ });
+}
+
+var innerHTML = function innerHTML() {
+ return 'innerHTML';
+};
+
+function dangerouslySetInnerHTML(element, html) {
+ element[innerHTML()] = html;
+}
+
+function createArrowElement(value) {
+ var arrow = div();
+
+ if (value === true) {
+ arrow.className = ARROW_CLASS;
+ } else {
+ arrow.className = SVG_ARROW_CLASS;
+
+ if (tippy_esm_isElement(value)) {
+ arrow.appendChild(value);
+ } else {
+ dangerouslySetInnerHTML(arrow, value);
+ }
+ }
+
+ return arrow;
+}
+
+function setContent(content, props) {
+ if (tippy_esm_isElement(props.content)) {
+ dangerouslySetInnerHTML(content, '');
+ content.appendChild(props.content);
+ } else if (typeof props.content !== 'function') {
+ if (props.allowHTML) {
+ dangerouslySetInnerHTML(content, props.content);
+ } else {
+ content.textContent = props.content;
+ }
+ }
+}
+function getChildren(popper) {
+ var box = popper.firstElementChild;
+ var boxChildren = arrayFrom(box.children);
+ return {
+ box: box,
+ content: boxChildren.find(function (node) {
+ return node.classList.contains(CONTENT_CLASS);
+ }),
+ arrow: boxChildren.find(function (node) {
+ return node.classList.contains(ARROW_CLASS) || node.classList.contains(SVG_ARROW_CLASS);
+ }),
+ backdrop: boxChildren.find(function (node) {
+ return node.classList.contains(BACKDROP_CLASS);
+ })
+ };
+}
+function render(instance) {
+ var popper = div();
+ var box = div();
+ box.className = BOX_CLASS;
+ box.setAttribute('data-state', 'hidden');
+ box.setAttribute('tabindex', '-1');
+ var content = div();
+ content.className = CONTENT_CLASS;
+ content.setAttribute('data-state', 'hidden');
+ setContent(content, instance.props);
+ popper.appendChild(box);
+ box.appendChild(content);
+ onUpdate(instance.props, instance.props);
+
+ function onUpdate(prevProps, nextProps) {
+ var _getChildren = getChildren(popper),
+ box = _getChildren.box,
+ content = _getChildren.content,
+ arrow = _getChildren.arrow;
+
+ if (nextProps.theme) {
+ box.setAttribute('data-theme', nextProps.theme);
+ } else {
+ box.removeAttribute('data-theme');
+ }
+
+ if (typeof nextProps.animation === 'string') {
+ box.setAttribute('data-animation', nextProps.animation);
+ } else {
+ box.removeAttribute('data-animation');
+ }
+
+ if (nextProps.inertia) {
+ box.setAttribute('data-inertia', '');
+ } else {
+ box.removeAttribute('data-inertia');
+ }
+
+ box.style.maxWidth = typeof nextProps.maxWidth === 'number' ? nextProps.maxWidth + "px" : nextProps.maxWidth;
+
+ if (nextProps.role) {
+ box.setAttribute('role', nextProps.role);
+ } else {
+ box.removeAttribute('role');
+ }
+
+ if (prevProps.content !== nextProps.content || prevProps.allowHTML !== nextProps.allowHTML) {
+ setContent(content, instance.props);
+ }
+
+ if (nextProps.arrow) {
+ if (!arrow) {
+ box.appendChild(createArrowElement(nextProps.arrow));
+ } else if (prevProps.arrow !== nextProps.arrow) {
+ box.removeChild(arrow);
+ box.appendChild(createArrowElement(nextProps.arrow));
+ }
+ } else if (arrow) {
+ box.removeChild(arrow);
+ }
+ }
+
+ return {
+ popper: popper,
+ onUpdate: onUpdate
+ };
+} // Runtime check to identify if the render function is the default one; this
+// way we can apply default CSS transitions logic and it can be tree-shaken away
+
+render.$$tippy = true;
+
+var idCounter = 1;
+var mouseMoveListeners = []; // Used by `hideAll()`
+
+var mountedInstances = [];
+function createTippy(reference, passedProps) {
+ var props = evaluateProps(reference, Object.assign({}, defaultProps, getExtendedPassedProps(removeUndefinedProps(passedProps)))); // ===========================================================================
+ // π Private members
+ // ===========================================================================
+
+ var showTimeout;
+ var hideTimeout;
+ var scheduleHideAnimationFrame;
+ var isVisibleFromClick = false;
+ var didHideDueToDocumentMouseDown = false;
+ var didTouchMove = false;
+ var ignoreOnFirstUpdate = false;
+ var lastTriggerEvent;
+ var currentTransitionEndListener;
+ var onFirstUpdate;
+ var listeners = [];
+ var debouncedOnMouseMove = tippy_esm_debounce(onMouseMove, props.interactiveDebounce);
+ var currentTarget; // ===========================================================================
+ // π Public members
+ // ===========================================================================
+
+ var id = idCounter++;
+ var popperInstance = null;
+ var plugins = unique(props.plugins);
+ var state = {
+ // Is the instance currently enabled?
+ isEnabled: true,
+ // Is the tippy currently showing and not transitioning out?
+ isVisible: false,
+ // Has the instance been destroyed?
+ isDestroyed: false,
+ // Is the tippy currently mounted to the DOM?
+ isMounted: false,
+ // Has the tippy finished transitioning in?
+ isShown: false
+ };
+ var instance = {
+ // properties
+ id: id,
+ reference: reference,
+ popper: div(),
+ popperInstance: popperInstance,
+ props: props,
+ state: state,
+ plugins: plugins,
+ // methods
+ clearDelayTimeouts: clearDelayTimeouts,
+ setProps: setProps,
+ setContent: setContent,
+ show: show,
+ hide: hide,
+ hideWithInteractivity: hideWithInteractivity,
+ enable: enable,
+ disable: disable,
+ unmount: unmount,
+ destroy: destroy
+ }; // TODO: Investigate why this early return causes a TDZ error in the tests β
+ // it doesn't seem to happen in the browser
+
+ /* istanbul ignore if */
+
+ if (!props.render) {
+ if (false) {}
+
+ return instance;
+ } // ===========================================================================
+ // Initial mutations
+ // ===========================================================================
+
+
+ var _props$render = props.render(instance),
+ popper = _props$render.popper,
+ onUpdate = _props$render.onUpdate;
+
+ popper.setAttribute('data-tippy-root', '');
+ popper.id = "tippy-" + instance.id;
+ instance.popper = popper;
+ reference._tippy = instance;
+ popper._tippy = instance;
+ var pluginsHooks = plugins.map(function (plugin) {
+ return plugin.fn(instance);
+ });
+ var hasAriaExpanded = reference.hasAttribute('aria-expanded');
+ addListeners();
+ handleAriaExpandedAttribute();
+ handleStyles();
+ invokeHook('onCreate', [instance]);
+
+ if (props.showOnCreate) {
+ scheduleShow();
+ } // Prevent a tippy with a delay from hiding if the cursor left then returned
+ // before it started hiding
+
+
+ popper.addEventListener('mouseenter', function () {
+ if (instance.props.interactive && instance.state.isVisible) {
+ instance.clearDelayTimeouts();
+ }
+ });
+ popper.addEventListener('mouseleave', function () {
+ if (instance.props.interactive && instance.props.trigger.indexOf('mouseenter') >= 0) {
+ getDocument().addEventListener('mousemove', debouncedOnMouseMove);
+ }
+ });
+ return instance; // ===========================================================================
+ // π Private methods
+ // ===========================================================================
+
+ function getNormalizedTouchSettings() {
+ var touch = instance.props.touch;
+ return Array.isArray(touch) ? touch : [touch, 0];
+ }
+
+ function getIsCustomTouchBehavior() {
+ return getNormalizedTouchSettings()[0] === 'hold';
+ }
+
+ function getIsDefaultRenderFn() {
+ var _instance$props$rende;
+
+ // @ts-ignore
+ return !!((_instance$props$rende = instance.props.render) != null && _instance$props$rende.$$tippy);
+ }
+
+ function getCurrentTarget() {
+ return currentTarget || reference;
+ }
+
+ function getDocument() {
+ var parent = getCurrentTarget().parentNode;
+ return parent ? getOwnerDocument(parent) : document;
+ }
+
+ function getDefaultTemplateChildren() {
+ return getChildren(popper);
+ }
+
+ function getDelay(isShow) {
+ // For touch or keyboard input, force `0` delay for UX reasons
+ // Also if the instance is mounted but not visible (transitioning out),
+ // ignore delay
+ if (instance.state.isMounted && !instance.state.isVisible || currentInput.isTouch || lastTriggerEvent && lastTriggerEvent.type === 'focus') {
+ return 0;
+ }
+
+ return getValueAtIndexOrReturn(instance.props.delay, isShow ? 0 : 1, defaultProps.delay);
+ }
+
+ function handleStyles(fromHide) {
+ if (fromHide === void 0) {
+ fromHide = false;
+ }
+
+ popper.style.pointerEvents = instance.props.interactive && !fromHide ? '' : 'none';
+ popper.style.zIndex = "" + instance.props.zIndex;
+ }
+
+ function invokeHook(hook, args, shouldInvokePropsHook) {
+ if (shouldInvokePropsHook === void 0) {
+ shouldInvokePropsHook = true;
+ }
+
+ pluginsHooks.forEach(function (pluginHooks) {
+ if (pluginHooks[hook]) {
+ pluginHooks[hook].apply(pluginHooks, args);
+ }
+ });
+
+ if (shouldInvokePropsHook) {
+ var _instance$props;
+
+ (_instance$props = instance.props)[hook].apply(_instance$props, args);
+ }
+ }
+
+ function handleAriaContentAttribute() {
+ var aria = instance.props.aria;
+
+ if (!aria.content) {
+ return;
+ }
+
+ var attr = "aria-" + aria.content;
+ var id = popper.id;
+ var nodes = normalizeToArray(instance.props.triggerTarget || reference);
+ nodes.forEach(function (node) {
+ var currentValue = node.getAttribute(attr);
+
+ if (instance.state.isVisible) {
+ node.setAttribute(attr, currentValue ? currentValue + " " + id : id);
+ } else {
+ var nextValue = currentValue && currentValue.replace(id, '').trim();
+
+ if (nextValue) {
+ node.setAttribute(attr, nextValue);
+ } else {
+ node.removeAttribute(attr);
+ }
+ }
+ });
+ }
+
+ function handleAriaExpandedAttribute() {
+ if (hasAriaExpanded || !instance.props.aria.expanded) {
+ return;
+ }
+
+ var nodes = normalizeToArray(instance.props.triggerTarget || reference);
+ nodes.forEach(function (node) {
+ if (instance.props.interactive) {
+ node.setAttribute('aria-expanded', instance.state.isVisible && node === getCurrentTarget() ? 'true' : 'false');
+ } else {
+ node.removeAttribute('aria-expanded');
+ }
+ });
+ }
+
+ function cleanupInteractiveMouseListeners() {
+ getDocument().removeEventListener('mousemove', debouncedOnMouseMove);
+ mouseMoveListeners = mouseMoveListeners.filter(function (listener) {
+ return listener !== debouncedOnMouseMove;
+ });
+ }
+
+ function onDocumentPress(event) {
+ // Moved finger to scroll instead of an intentional tap outside
+ if (currentInput.isTouch) {
+ if (didTouchMove || event.type === 'mousedown') {
+ return;
+ }
+ }
+
+ var actualTarget = event.composedPath && event.composedPath()[0] || event.target; // Clicked on interactive popper
+
+ if (instance.props.interactive && actualContains(popper, actualTarget)) {
+ return;
+ } // Clicked on the event listeners target
+
+
+ if (normalizeToArray(instance.props.triggerTarget || reference).some(function (el) {
+ return actualContains(el, actualTarget);
+ })) {
+ if (currentInput.isTouch) {
+ return;
+ }
+
+ if (instance.state.isVisible && instance.props.trigger.indexOf('click') >= 0) {
+ return;
+ }
+ } else {
+ invokeHook('onClickOutside', [instance, event]);
+ }
+
+ if (instance.props.hideOnClick === true) {
+ instance.clearDelayTimeouts();
+ instance.hide(); // `mousedown` event is fired right before `focus` if pressing the
+ // currentTarget. This lets a tippy with `focus` trigger know that it
+ // should not show
+
+ didHideDueToDocumentMouseDown = true;
+ setTimeout(function () {
+ didHideDueToDocumentMouseDown = false;
+ }); // The listener gets added in `scheduleShow()`, but this may be hiding it
+ // before it shows, and hide()'s early bail-out behavior can prevent it
+ // from being cleaned up
+
+ if (!instance.state.isMounted) {
+ removeDocumentPress();
+ }
+ }
+ }
+
+ function onTouchMove() {
+ didTouchMove = true;
+ }
+
+ function onTouchStart() {
+ didTouchMove = false;
+ }
+
+ function addDocumentPress() {
+ var doc = getDocument();
+ doc.addEventListener('mousedown', onDocumentPress, true);
+ doc.addEventListener('touchend', onDocumentPress, TOUCH_OPTIONS);
+ doc.addEventListener('touchstart', onTouchStart, TOUCH_OPTIONS);
+ doc.addEventListener('touchmove', onTouchMove, TOUCH_OPTIONS);
+ }
+
+ function removeDocumentPress() {
+ var doc = getDocument();
+ doc.removeEventListener('mousedown', onDocumentPress, true);
+ doc.removeEventListener('touchend', onDocumentPress, TOUCH_OPTIONS);
+ doc.removeEventListener('touchstart', onTouchStart, TOUCH_OPTIONS);
+ doc.removeEventListener('touchmove', onTouchMove, TOUCH_OPTIONS);
+ }
+
+ function onTransitionedOut(duration, callback) {
+ onTransitionEnd(duration, function () {
+ if (!instance.state.isVisible && popper.parentNode && popper.parentNode.contains(popper)) {
+ callback();
+ }
+ });
+ }
+
+ function onTransitionedIn(duration, callback) {
+ onTransitionEnd(duration, callback);
+ }
+
+ function onTransitionEnd(duration, callback) {
+ var box = getDefaultTemplateChildren().box;
+
+ function listener(event) {
+ if (event.target === box) {
+ updateTransitionEndListener(box, 'remove', listener);
+ callback();
+ }
+ } // Make callback synchronous if duration is 0
+ // `transitionend` won't fire otherwise
+
+
+ if (duration === 0) {
+ return callback();
+ }
+
+ updateTransitionEndListener(box, 'remove', currentTransitionEndListener);
+ updateTransitionEndListener(box, 'add', listener);
+ currentTransitionEndListener = listener;
+ }
+
+ function on(eventType, handler, options) {
+ if (options === void 0) {
+ options = false;
+ }
+
+ var nodes = normalizeToArray(instance.props.triggerTarget || reference);
+ nodes.forEach(function (node) {
+ node.addEventListener(eventType, handler, options);
+ listeners.push({
+ node: node,
+ eventType: eventType,
+ handler: handler,
+ options: options
+ });
+ });
+ }
+
+ function addListeners() {
+ if (getIsCustomTouchBehavior()) {
+ on('touchstart', onTrigger, {
+ passive: true
+ });
+ on('touchend', onMouseLeave, {
+ passive: true
+ });
+ }
+
+ splitBySpaces(instance.props.trigger).forEach(function (eventType) {
+ if (eventType === 'manual') {
+ return;
+ }
+
+ on(eventType, onTrigger);
+
+ switch (eventType) {
+ case 'mouseenter':
+ on('mouseleave', onMouseLeave);
+ break;
+
+ case 'focus':
+ on(isIE11 ? 'focusout' : 'blur', onBlurOrFocusOut);
+ break;
+
+ case 'focusin':
+ on('focusout', onBlurOrFocusOut);
+ break;
+ }
+ });
+ }
+
+ function removeListeners() {
+ listeners.forEach(function (_ref) {
+ var node = _ref.node,
+ eventType = _ref.eventType,
+ handler = _ref.handler,
+ options = _ref.options;
+ node.removeEventListener(eventType, handler, options);
+ });
+ listeners = [];
+ }
+
+ function onTrigger(event) {
+ var _lastTriggerEvent;
+
+ var shouldScheduleClickHide = false;
+
+ if (!instance.state.isEnabled || isEventListenerStopped(event) || didHideDueToDocumentMouseDown) {
+ return;
+ }
+
+ var wasFocused = ((_lastTriggerEvent = lastTriggerEvent) == null ? void 0 : _lastTriggerEvent.type) === 'focus';
+ lastTriggerEvent = event;
+ currentTarget = event.currentTarget;
+ handleAriaExpandedAttribute();
+
+ if (!instance.state.isVisible && isMouseEvent(event)) {
+ // If scrolling, `mouseenter` events can be fired if the cursor lands
+ // over a new target, but `mousemove` events don't get fired. This
+ // causes interactive tooltips to get stuck open until the cursor is
+ // moved
+ mouseMoveListeners.forEach(function (listener) {
+ return listener(event);
+ });
+ } // Toggle show/hide when clicking click-triggered tooltips
+
+
+ if (event.type === 'click' && (instance.props.trigger.indexOf('mouseenter') < 0 || isVisibleFromClick) && instance.props.hideOnClick !== false && instance.state.isVisible) {
+ shouldScheduleClickHide = true;
+ } else {
+ scheduleShow(event);
+ }
+
+ if (event.type === 'click') {
+ isVisibleFromClick = !shouldScheduleClickHide;
+ }
+
+ if (shouldScheduleClickHide && !wasFocused) {
+ scheduleHide(event);
+ }
+ }
+
+ function onMouseMove(event) {
+ var target = event.target;
+ var isCursorOverReferenceOrPopper = getCurrentTarget().contains(target) || popper.contains(target);
+
+ if (event.type === 'mousemove' && isCursorOverReferenceOrPopper) {
+ return;
+ }
+
+ var popperTreeData = getNestedPopperTree().concat(popper).map(function (popper) {
+ var _instance$popperInsta;
+
+ var instance = popper._tippy;
+ var state = (_instance$popperInsta = instance.popperInstance) == null ? void 0 : _instance$popperInsta.state;
+
+ if (state) {
+ return {
+ popperRect: popper.getBoundingClientRect(),
+ popperState: state,
+ props: props
+ };
+ }
+
+ return null;
+ }).filter(Boolean);
+
+ if (isCursorOutsideInteractiveBorder(popperTreeData, event)) {
+ cleanupInteractiveMouseListeners();
+ scheduleHide(event);
+ }
+ }
+
+ function onMouseLeave(event) {
+ var shouldBail = isEventListenerStopped(event) || instance.props.trigger.indexOf('click') >= 0 && isVisibleFromClick;
+
+ if (shouldBail) {
+ return;
+ }
+
+ if (instance.props.interactive) {
+ instance.hideWithInteractivity(event);
+ return;
+ }
+
+ scheduleHide(event);
+ }
+
+ function onBlurOrFocusOut(event) {
+ if (instance.props.trigger.indexOf('focusin') < 0 && event.target !== getCurrentTarget()) {
+ return;
+ } // If focus was moved to within the popper
+
+
+ if (instance.props.interactive && event.relatedTarget && popper.contains(event.relatedTarget)) {
+ return;
+ }
+
+ scheduleHide(event);
+ }
+
+ function isEventListenerStopped(event) {
+ return currentInput.isTouch ? getIsCustomTouchBehavior() !== event.type.indexOf('touch') >= 0 : false;
+ }
+
+ function createPopperInstance() {
+ destroyPopperInstance();
+ var _instance$props2 = instance.props,
+ popperOptions = _instance$props2.popperOptions,
+ placement = _instance$props2.placement,
+ offset = _instance$props2.offset,
+ getReferenceClientRect = _instance$props2.getReferenceClientRect,
+ moveTransition = _instance$props2.moveTransition;
+ var arrow = getIsDefaultRenderFn() ? getChildren(popper).arrow : null;
+ var computedReference = getReferenceClientRect ? {
+ getBoundingClientRect: getReferenceClientRect,
+ contextElement: getReferenceClientRect.contextElement || getCurrentTarget()
+ } : reference;
+ var tippyModifier = {
+ name: '$$tippy',
+ enabled: true,
+ phase: 'beforeWrite',
+ requires: ['computeStyles'],
+ fn: function fn(_ref2) {
+ var state = _ref2.state;
+
+ if (getIsDefaultRenderFn()) {
+ var _getDefaultTemplateCh = getDefaultTemplateChildren(),
+ box = _getDefaultTemplateCh.box;
+
+ ['placement', 'reference-hidden', 'escaped'].forEach(function (attr) {
+ if (attr === 'placement') {
+ box.setAttribute('data-placement', state.placement);
+ } else {
+ if (state.attributes.popper["data-popper-" + attr]) {
+ box.setAttribute("data-" + attr, '');
+ } else {
+ box.removeAttribute("data-" + attr);
+ }
+ }
+ });
+ state.attributes.popper = {};
+ }
+ }
+ };
+ var modifiers = [{
+ name: 'offset',
+ options: {
+ offset: offset
+ }
+ }, {
+ name: 'preventOverflow',
+ options: {
+ padding: {
+ top: 2,
+ bottom: 2,
+ left: 5,
+ right: 5
+ }
+ }
+ }, {
+ name: 'flip',
+ options: {
+ padding: 5
+ }
+ }, {
+ name: 'computeStyles',
+ options: {
+ adaptive: !moveTransition
+ }
+ }, tippyModifier];
+
+ if (getIsDefaultRenderFn() && arrow) {
+ modifiers.push({
+ name: 'arrow',
+ options: {
+ element: arrow,
+ padding: 3
+ }
+ });
+ }
+
+ modifiers.push.apply(modifiers, (popperOptions == null ? void 0 : popperOptions.modifiers) || []);
+ instance.popperInstance = popper_createPopper(computedReference, popper, Object.assign({}, popperOptions, {
+ placement: placement,
+ onFirstUpdate: onFirstUpdate,
+ modifiers: modifiers
+ }));
+ }
+
+ function destroyPopperInstance() {
+ if (instance.popperInstance) {
+ instance.popperInstance.destroy();
+ instance.popperInstance = null;
+ }
+ }
+
+ function mount() {
+ var appendTo = instance.props.appendTo;
+ var parentNode; // By default, we'll append the popper to the triggerTargets's parentNode so
+ // it's directly after the reference element so the elements inside the
+ // tippy can be tabbed to
+ // If there are clipping issues, the user can specify a different appendTo
+ // and ensure focus management is handled correctly manually
+
+ var node = getCurrentTarget();
+
+ if (instance.props.interactive && appendTo === TIPPY_DEFAULT_APPEND_TO || appendTo === 'parent') {
+ parentNode = node.parentNode;
+ } else {
+ parentNode = invokeWithArgsOrReturn(appendTo, [node]);
+ } // The popper element needs to exist on the DOM before its position can be
+ // updated as Popper needs to read its dimensions
+
+
+ if (!parentNode.contains(popper)) {
+ parentNode.appendChild(popper);
+ }
+
+ instance.state.isMounted = true;
+ createPopperInstance();
+ /* istanbul ignore else */
+
+ if (false) {}
+ }
+
+ function getNestedPopperTree() {
+ return arrayFrom(popper.querySelectorAll('[data-tippy-root]'));
+ }
+
+ function scheduleShow(event) {
+ instance.clearDelayTimeouts();
+
+ if (event) {
+ invokeHook('onTrigger', [instance, event]);
+ }
+
+ addDocumentPress();
+ var delay = getDelay(true);
+
+ var _getNormalizedTouchSe = getNormalizedTouchSettings(),
+ touchValue = _getNormalizedTouchSe[0],
+ touchDelay = _getNormalizedTouchSe[1];
+
+ if (currentInput.isTouch && touchValue === 'hold' && touchDelay) {
+ delay = touchDelay;
+ }
+
+ if (delay) {
+ showTimeout = setTimeout(function () {
+ instance.show();
+ }, delay);
+ } else {
+ instance.show();
+ }
+ }
+
+ function scheduleHide(event) {
+ instance.clearDelayTimeouts();
+ invokeHook('onUntrigger', [instance, event]);
+
+ if (!instance.state.isVisible) {
+ removeDocumentPress();
+ return;
+ } // For interactive tippies, scheduleHide is added to a document.body handler
+ // from onMouseLeave so must intercept scheduled hides from mousemove/leave
+ // events when trigger contains mouseenter and click, and the tip is
+ // currently shown as a result of a click.
+
+
+ if (instance.props.trigger.indexOf('mouseenter') >= 0 && instance.props.trigger.indexOf('click') >= 0 && ['mouseleave', 'mousemove'].indexOf(event.type) >= 0 && isVisibleFromClick) {
+ return;
+ }
+
+ var delay = getDelay(false);
+
+ if (delay) {
+ hideTimeout = setTimeout(function () {
+ if (instance.state.isVisible) {
+ instance.hide();
+ }
+ }, delay);
+ } else {
+ // Fixes a `transitionend` problem when it fires 1 frame too
+ // late sometimes, we don't want hide() to be called.
+ scheduleHideAnimationFrame = requestAnimationFrame(function () {
+ instance.hide();
+ });
+ }
+ } // ===========================================================================
+ // π Public methods
+ // ===========================================================================
+
+
+ function enable() {
+ instance.state.isEnabled = true;
+ }
+
+ function disable() {
+ // Disabling the instance should also hide it
+ // https://github.com/atomiks/tippy.js-react/issues/106
+ instance.hide();
+ instance.state.isEnabled = false;
+ }
+
+ function clearDelayTimeouts() {
+ clearTimeout(showTimeout);
+ clearTimeout(hideTimeout);
+ cancelAnimationFrame(scheduleHideAnimationFrame);
+ }
+
+ function setProps(partialProps) {
+ /* istanbul ignore else */
+ if (false) {}
+
+ if (instance.state.isDestroyed) {
+ return;
+ }
+
+ invokeHook('onBeforeUpdate', [instance, partialProps]);
+ removeListeners();
+ var prevProps = instance.props;
+ var nextProps = evaluateProps(reference, Object.assign({}, prevProps, removeUndefinedProps(partialProps), {
+ ignoreAttributes: true
+ }));
+ instance.props = nextProps;
+ addListeners();
+
+ if (prevProps.interactiveDebounce !== nextProps.interactiveDebounce) {
+ cleanupInteractiveMouseListeners();
+ debouncedOnMouseMove = tippy_esm_debounce(onMouseMove, nextProps.interactiveDebounce);
+ } // Ensure stale aria-expanded attributes are removed
+
+
+ if (prevProps.triggerTarget && !nextProps.triggerTarget) {
+ normalizeToArray(prevProps.triggerTarget).forEach(function (node) {
+ node.removeAttribute('aria-expanded');
+ });
+ } else if (nextProps.triggerTarget) {
+ reference.removeAttribute('aria-expanded');
+ }
+
+ handleAriaExpandedAttribute();
+ handleStyles();
+
+ if (onUpdate) {
+ onUpdate(prevProps, nextProps);
+ }
+
+ if (instance.popperInstance) {
+ createPopperInstance(); // Fixes an issue with nested tippies if they are all getting re-rendered,
+ // and the nested ones get re-rendered first.
+ // https://github.com/atomiks/tippyjs-react/issues/177
+ // TODO: find a cleaner / more efficient solution(!)
+
+ getNestedPopperTree().forEach(function (nestedPopper) {
+ // React (and other UI libs likely) requires a rAF wrapper as it flushes
+ // its work in one
+ requestAnimationFrame(nestedPopper._tippy.popperInstance.forceUpdate);
+ });
+ }
+
+ invokeHook('onAfterUpdate', [instance, partialProps]);
+ }
+
+ function setContent(content) {
+ instance.setProps({
+ content: content
+ });
+ }
+
+ function show() {
+ /* istanbul ignore else */
+ if (false) {} // Early bail-out
+
+
+ var isAlreadyVisible = instance.state.isVisible;
+ var isDestroyed = instance.state.isDestroyed;
+ var isDisabled = !instance.state.isEnabled;
+ var isTouchAndTouchDisabled = currentInput.isTouch && !instance.props.touch;
+ var duration = getValueAtIndexOrReturn(instance.props.duration, 0, defaultProps.duration);
+
+ if (isAlreadyVisible || isDestroyed || isDisabled || isTouchAndTouchDisabled) {
+ return;
+ } // Normalize `disabled` behavior across browsers.
+ // Firefox allows events on disabled elements, but Chrome doesn't.
+ // Using a wrapper element (i.e. ) is recommended.
+
+
+ if (getCurrentTarget().hasAttribute('disabled')) {
+ return;
+ }
+
+ invokeHook('onShow', [instance], false);
+
+ if (instance.props.onShow(instance) === false) {
+ return;
+ }
+
+ instance.state.isVisible = true;
+
+ if (getIsDefaultRenderFn()) {
+ popper.style.visibility = 'visible';
+ }
+
+ handleStyles();
+ addDocumentPress();
+
+ if (!instance.state.isMounted) {
+ popper.style.transition = 'none';
+ } // If flipping to the opposite side after hiding at least once, the
+ // animation will use the wrong placement without resetting the duration
+
+
+ if (getIsDefaultRenderFn()) {
+ var _getDefaultTemplateCh2 = getDefaultTemplateChildren(),
+ box = _getDefaultTemplateCh2.box,
+ content = _getDefaultTemplateCh2.content;
+
+ setTransitionDuration([box, content], 0);
+ }
+
+ onFirstUpdate = function onFirstUpdate() {
+ var _instance$popperInsta2;
+
+ if (!instance.state.isVisible || ignoreOnFirstUpdate) {
+ return;
+ }
+
+ ignoreOnFirstUpdate = true; // reflow
+
+ void popper.offsetHeight;
+ popper.style.transition = instance.props.moveTransition;
+
+ if (getIsDefaultRenderFn() && instance.props.animation) {
+ var _getDefaultTemplateCh3 = getDefaultTemplateChildren(),
+ _box = _getDefaultTemplateCh3.box,
+ _content = _getDefaultTemplateCh3.content;
+
+ setTransitionDuration([_box, _content], duration);
+ setVisibilityState([_box, _content], 'visible');
+ }
+
+ handleAriaContentAttribute();
+ handleAriaExpandedAttribute();
+ pushIfUnique(mountedInstances, instance); // certain modifiers (e.g. `maxSize`) require a second update after the
+ // popper has been positioned for the first time
+
+ (_instance$popperInsta2 = instance.popperInstance) == null ? void 0 : _instance$popperInsta2.forceUpdate();
+ invokeHook('onMount', [instance]);
+
+ if (instance.props.animation && getIsDefaultRenderFn()) {
+ onTransitionedIn(duration, function () {
+ instance.state.isShown = true;
+ invokeHook('onShown', [instance]);
+ });
+ }
+ };
+
+ mount();
+ }
+
+ function hide() {
+ /* istanbul ignore else */
+ if (false) {} // Early bail-out
+
+
+ var isAlreadyHidden = !instance.state.isVisible;
+ var isDestroyed = instance.state.isDestroyed;
+ var isDisabled = !instance.state.isEnabled;
+ var duration = getValueAtIndexOrReturn(instance.props.duration, 1, defaultProps.duration);
+
+ if (isAlreadyHidden || isDestroyed || isDisabled) {
+ return;
+ }
+
+ invokeHook('onHide', [instance], false);
+
+ if (instance.props.onHide(instance) === false) {
+ return;
+ }
+
+ instance.state.isVisible = false;
+ instance.state.isShown = false;
+ ignoreOnFirstUpdate = false;
+ isVisibleFromClick = false;
+
+ if (getIsDefaultRenderFn()) {
+ popper.style.visibility = 'hidden';
+ }
+
+ cleanupInteractiveMouseListeners();
+ removeDocumentPress();
+ handleStyles(true);
+
+ if (getIsDefaultRenderFn()) {
+ var _getDefaultTemplateCh4 = getDefaultTemplateChildren(),
+ box = _getDefaultTemplateCh4.box,
+ content = _getDefaultTemplateCh4.content;
+
+ if (instance.props.animation) {
+ setTransitionDuration([box, content], duration);
+ setVisibilityState([box, content], 'hidden');
+ }
+ }
+
+ handleAriaContentAttribute();
+ handleAriaExpandedAttribute();
+
+ if (instance.props.animation) {
+ if (getIsDefaultRenderFn()) {
+ onTransitionedOut(duration, instance.unmount);
+ }
+ } else {
+ instance.unmount();
+ }
+ }
+
+ function hideWithInteractivity(event) {
+ /* istanbul ignore else */
+ if (false) {}
+
+ getDocument().addEventListener('mousemove', debouncedOnMouseMove);
+ pushIfUnique(mouseMoveListeners, debouncedOnMouseMove);
+ debouncedOnMouseMove(event);
+ }
+
+ function unmount() {
+ /* istanbul ignore else */
+ if (false) {}
+
+ if (instance.state.isVisible) {
+ instance.hide();
+ }
+
+ if (!instance.state.isMounted) {
+ return;
+ }
+
+ destroyPopperInstance(); // If a popper is not interactive, it will be appended outside the popper
+ // tree by default. This seems mainly for interactive tippies, but we should
+ // find a workaround if possible
+
+ getNestedPopperTree().forEach(function (nestedPopper) {
+ nestedPopper._tippy.unmount();
+ });
+
+ if (popper.parentNode) {
+ popper.parentNode.removeChild(popper);
+ }
+
+ mountedInstances = mountedInstances.filter(function (i) {
+ return i !== instance;
+ });
+ instance.state.isMounted = false;
+ invokeHook('onHidden', [instance]);
+ }
+
+ function destroy() {
+ /* istanbul ignore else */
+ if (false) {}
+
+ if (instance.state.isDestroyed) {
+ return;
+ }
+
+ instance.clearDelayTimeouts();
+ instance.unmount();
+ removeListeners();
+ delete reference._tippy;
+ instance.state.isDestroyed = true;
+ invokeHook('onDestroy', [instance]);
+ }
+}
+
+function tippy(targets, optionalProps) {
+ if (optionalProps === void 0) {
+ optionalProps = {};
+ }
+
+ var plugins = defaultProps.plugins.concat(optionalProps.plugins || []);
+ /* istanbul ignore else */
+
+ if (false) {}
+
+ bindGlobalEventListeners();
+ var passedProps = Object.assign({}, optionalProps, {
+ plugins: plugins
+ });
+ var elements = getArrayOfElements(targets);
+ /* istanbul ignore else */
+
+ if (false) { var isMoreThanOneReferenceElement, isSingleContentElement; }
+
+ var instances = elements.reduce(function (acc, reference) {
+ var instance = reference && createTippy(reference, passedProps);
+
+ if (instance) {
+ acc.push(instance);
+ }
+
+ return acc;
+ }, []);
+ return tippy_esm_isElement(targets) ? instances[0] : instances;
+}
+
+tippy.defaultProps = defaultProps;
+tippy.setDefaultProps = setDefaultProps;
+tippy.currentInput = currentInput;
+var hideAll = function hideAll(_temp) {
+ var _ref = _temp === void 0 ? {} : _temp,
+ excludedReferenceOrInstance = _ref.exclude,
+ duration = _ref.duration;
+
+ mountedInstances.forEach(function (instance) {
+ var isExcluded = false;
+
+ if (excludedReferenceOrInstance) {
+ isExcluded = isReferenceElement(excludedReferenceOrInstance) ? instance.reference === excludedReferenceOrInstance : instance.popper === excludedReferenceOrInstance.popper;
+ }
+
+ if (!isExcluded) {
+ var originalDuration = instance.props.duration;
+ instance.setProps({
+ duration: duration
+ });
+ instance.hide();
+
+ if (!instance.state.isDestroyed) {
+ instance.setProps({
+ duration: originalDuration
+ });
+ }
+ }
+ });
+};
+
+// every time the popper is destroyed (i.e. a new target), removing the styles
+// and causing transitions to break for singletons when the console is open, but
+// most notably for non-transform styles being used, `gpuAcceleration: false`.
+
+var applyStylesModifier = Object.assign({}, modifiers_applyStyles, {
+ effect: function effect(_ref) {
+ var state = _ref.state;
+ var initialStyles = {
+ popper: {
+ position: state.options.strategy,
+ left: '0',
+ top: '0',
+ margin: '0'
+ },
+ arrow: {
+ position: 'absolute'
+ },
+ reference: {}
+ };
+ Object.assign(state.elements.popper.style, initialStyles.popper);
+ state.styles = initialStyles;
+
+ if (state.elements.arrow) {
+ Object.assign(state.elements.arrow.style, initialStyles.arrow);
+ } // intentionally return no cleanup function
+ // return () => { ... }
+
+ }
+});
+
+var createSingleton = function createSingleton(tippyInstances, optionalProps) {
+ var _optionalProps$popper;
+
+ if (optionalProps === void 0) {
+ optionalProps = {};
+ }
+
+ /* istanbul ignore else */
+ if (false) {}
+
+ var individualInstances = tippyInstances;
+ var references = [];
+ var triggerTargets = [];
+ var currentTarget;
+ var overrides = optionalProps.overrides;
+ var interceptSetPropsCleanups = [];
+ var shownOnCreate = false;
+
+ function setTriggerTargets() {
+ triggerTargets = individualInstances.map(function (instance) {
+ return normalizeToArray(instance.props.triggerTarget || instance.reference);
+ }).reduce(function (acc, item) {
+ return acc.concat(item);
+ }, []);
+ }
+
+ function setReferences() {
+ references = individualInstances.map(function (instance) {
+ return instance.reference;
+ });
+ }
+
+ function enableInstances(isEnabled) {
+ individualInstances.forEach(function (instance) {
+ if (isEnabled) {
+ instance.enable();
+ } else {
+ instance.disable();
+ }
+ });
+ }
+
+ function interceptSetProps(singleton) {
+ return individualInstances.map(function (instance) {
+ var originalSetProps = instance.setProps;
+
+ instance.setProps = function (props) {
+ originalSetProps(props);
+
+ if (instance.reference === currentTarget) {
+ singleton.setProps(props);
+ }
+ };
+
+ return function () {
+ instance.setProps = originalSetProps;
+ };
+ });
+ } // have to pass singleton, as it maybe undefined on first call
+
+
+ function prepareInstance(singleton, target) {
+ var index = triggerTargets.indexOf(target); // bail-out
+
+ if (target === currentTarget) {
+ return;
+ }
+
+ currentTarget = target;
+ var overrideProps = (overrides || []).concat('content').reduce(function (acc, prop) {
+ acc[prop] = individualInstances[index].props[prop];
+ return acc;
+ }, {});
+ singleton.setProps(Object.assign({}, overrideProps, {
+ getReferenceClientRect: typeof overrideProps.getReferenceClientRect === 'function' ? overrideProps.getReferenceClientRect : function () {
+ var _references$index;
+
+ return (_references$index = references[index]) == null ? void 0 : _references$index.getBoundingClientRect();
+ }
+ }));
+ }
+
+ enableInstances(false);
+ setReferences();
+ setTriggerTargets();
+ var plugin = {
+ fn: function fn() {
+ return {
+ onDestroy: function onDestroy() {
+ enableInstances(true);
+ },
+ onHidden: function onHidden() {
+ currentTarget = null;
+ },
+ onClickOutside: function onClickOutside(instance) {
+ if (instance.props.showOnCreate && !shownOnCreate) {
+ shownOnCreate = true;
+ currentTarget = null;
+ }
+ },
+ onShow: function onShow(instance) {
+ if (instance.props.showOnCreate && !shownOnCreate) {
+ shownOnCreate = true;
+ prepareInstance(instance, references[0]);
+ }
+ },
+ onTrigger: function onTrigger(instance, event) {
+ prepareInstance(instance, event.currentTarget);
+ }
+ };
+ }
+ };
+ var singleton = tippy(div(), Object.assign({}, removeProperties(optionalProps, ['overrides']), {
+ plugins: [plugin].concat(optionalProps.plugins || []),
+ triggerTarget: triggerTargets,
+ popperOptions: Object.assign({}, optionalProps.popperOptions, {
+ modifiers: [].concat(((_optionalProps$popper = optionalProps.popperOptions) == null ? void 0 : _optionalProps$popper.modifiers) || [], [applyStylesModifier])
+ })
+ }));
+ var originalShow = singleton.show;
+
+ singleton.show = function (target) {
+ originalShow(); // first time, showOnCreate or programmatic call with no params
+ // default to showing first instance
+
+ if (!currentTarget && target == null) {
+ return prepareInstance(singleton, references[0]);
+ } // triggered from event (do nothing as prepareInstance already called by onTrigger)
+ // programmatic call with no params when already visible (do nothing again)
+
+
+ if (currentTarget && target == null) {
+ return;
+ } // target is index of instance
+
+
+ if (typeof target === 'number') {
+ return references[target] && prepareInstance(singleton, references[target]);
+ } // target is a child tippy instance
+
+
+ if (individualInstances.indexOf(target) >= 0) {
+ var ref = target.reference;
+ return prepareInstance(singleton, ref);
+ } // target is a ReferenceElement
+
+
+ if (references.indexOf(target) >= 0) {
+ return prepareInstance(singleton, target);
+ }
+ };
+
+ singleton.showNext = function () {
+ var first = references[0];
+
+ if (!currentTarget) {
+ return singleton.show(0);
+ }
+
+ var index = references.indexOf(currentTarget);
+ singleton.show(references[index + 1] || first);
+ };
+
+ singleton.showPrevious = function () {
+ var last = references[references.length - 1];
+
+ if (!currentTarget) {
+ return singleton.show(last);
+ }
+
+ var index = references.indexOf(currentTarget);
+ var target = references[index - 1] || last;
+ singleton.show(target);
+ };
+
+ var originalSetProps = singleton.setProps;
+
+ singleton.setProps = function (props) {
+ overrides = props.overrides || overrides;
+ originalSetProps(props);
+ };
+
+ singleton.setInstances = function (nextInstances) {
+ enableInstances(true);
+ interceptSetPropsCleanups.forEach(function (fn) {
+ return fn();
+ });
+ individualInstances = nextInstances;
+ enableInstances(false);
+ setReferences();
+ setTriggerTargets();
+ interceptSetPropsCleanups = interceptSetProps(singleton);
+ singleton.setProps({
+ triggerTarget: triggerTargets
+ });
+ };
+
+ interceptSetPropsCleanups = interceptSetProps(singleton);
+ return singleton;
+};
+
+var BUBBLING_EVENTS_MAP = {
+ mouseover: 'mouseenter',
+ focusin: 'focus',
+ click: 'click'
+};
+/**
+ * Creates a delegate instance that controls the creation of tippy instances
+ * for child elements (`target` CSS selector).
+ */
+
+function delegate(targets, props) {
+ /* istanbul ignore else */
+ if (false) {}
+
+ var listeners = [];
+ var childTippyInstances = [];
+ var disabled = false;
+ var target = props.target;
+ var nativeProps = removeProperties(props, ['target']);
+ var parentProps = Object.assign({}, nativeProps, {
+ trigger: 'manual',
+ touch: false
+ });
+ var childProps = Object.assign({
+ touch: defaultProps.touch
+ }, nativeProps, {
+ showOnCreate: true
+ });
+ var returnValue = tippy(targets, parentProps);
+ var normalizedReturnValue = normalizeToArray(returnValue);
+
+ function onTrigger(event) {
+ if (!event.target || disabled) {
+ return;
+ }
+
+ var targetNode = event.target.closest(target);
+
+ if (!targetNode) {
+ return;
+ } // Get relevant trigger with fallbacks:
+ // 1. Check `data-tippy-trigger` attribute on target node
+ // 2. Fallback to `trigger` passed to `delegate()`
+ // 3. Fallback to `defaultProps.trigger`
+
+
+ var trigger = targetNode.getAttribute('data-tippy-trigger') || props.trigger || defaultProps.trigger; // @ts-ignore
+
+ if (targetNode._tippy) {
+ return;
+ }
+
+ if (event.type === 'touchstart' && typeof childProps.touch === 'boolean') {
+ return;
+ }
+
+ if (event.type !== 'touchstart' && trigger.indexOf(BUBBLING_EVENTS_MAP[event.type]) < 0) {
+ return;
+ }
+
+ var instance = tippy(targetNode, childProps);
+
+ if (instance) {
+ childTippyInstances = childTippyInstances.concat(instance);
+ }
+ }
+
+ function on(node, eventType, handler, options) {
+ if (options === void 0) {
+ options = false;
+ }
+
+ node.addEventListener(eventType, handler, options);
+ listeners.push({
+ node: node,
+ eventType: eventType,
+ handler: handler,
+ options: options
+ });
+ }
+
+ function addEventListeners(instance) {
+ var reference = instance.reference;
+ on(reference, 'touchstart', onTrigger, TOUCH_OPTIONS);
+ on(reference, 'mouseover', onTrigger);
+ on(reference, 'focusin', onTrigger);
+ on(reference, 'click', onTrigger);
+ }
+
+ function removeEventListeners() {
+ listeners.forEach(function (_ref) {
+ var node = _ref.node,
+ eventType = _ref.eventType,
+ handler = _ref.handler,
+ options = _ref.options;
+ node.removeEventListener(eventType, handler, options);
+ });
+ listeners = [];
+ }
+
+ function applyMutations(instance) {
+ var originalDestroy = instance.destroy;
+ var originalEnable = instance.enable;
+ var originalDisable = instance.disable;
+
+ instance.destroy = function (shouldDestroyChildInstances) {
+ if (shouldDestroyChildInstances === void 0) {
+ shouldDestroyChildInstances = true;
+ }
+
+ if (shouldDestroyChildInstances) {
+ childTippyInstances.forEach(function (instance) {
+ instance.destroy();
+ });
+ }
+
+ childTippyInstances = [];
+ removeEventListeners();
+ originalDestroy();
+ };
+
+ instance.enable = function () {
+ originalEnable();
+ childTippyInstances.forEach(function (instance) {
+ return instance.enable();
+ });
+ disabled = false;
+ };
+
+ instance.disable = function () {
+ originalDisable();
+ childTippyInstances.forEach(function (instance) {
+ return instance.disable();
+ });
+ disabled = true;
+ };
+
+ addEventListeners(instance);
+ }
+
+ normalizedReturnValue.forEach(applyMutations);
+ return returnValue;
+}
+
+var animateFill = {
+ name: 'animateFill',
+ defaultValue: false,
+ fn: function fn(instance) {
+ var _instance$props$rende;
+
+ // @ts-ignore
+ if (!((_instance$props$rende = instance.props.render) != null && _instance$props$rende.$$tippy)) {
+ if (false) {}
+
+ return {};
+ }
+
+ var _getChildren = getChildren(instance.popper),
+ box = _getChildren.box,
+ content = _getChildren.content;
+
+ var backdrop = instance.props.animateFill ? createBackdropElement() : null;
+ return {
+ onCreate: function onCreate() {
+ if (backdrop) {
+ box.insertBefore(backdrop, box.firstElementChild);
+ box.setAttribute('data-animatefill', '');
+ box.style.overflow = 'hidden';
+ instance.setProps({
+ arrow: false,
+ animation: 'shift-away'
+ });
+ }
+ },
+ onMount: function onMount() {
+ if (backdrop) {
+ var transitionDuration = box.style.transitionDuration;
+ var duration = Number(transitionDuration.replace('ms', '')); // The content should fade in after the backdrop has mostly filled the
+ // tooltip element. `clip-path` is the other alternative but is not
+ // well-supported and is buggy on some devices.
+
+ content.style.transitionDelay = Math.round(duration / 10) + "ms";
+ backdrop.style.transitionDuration = transitionDuration;
+ setVisibilityState([backdrop], 'visible');
+ }
+ },
+ onShow: function onShow() {
+ if (backdrop) {
+ backdrop.style.transitionDuration = '0ms';
+ }
+ },
+ onHide: function onHide() {
+ if (backdrop) {
+ setVisibilityState([backdrop], 'hidden');
+ }
+ }
+ };
+ }
+};
+
+function createBackdropElement() {
+ var backdrop = div();
+ backdrop.className = BACKDROP_CLASS;
+ setVisibilityState([backdrop], 'hidden');
+ return backdrop;
+}
+
+var mouseCoords = {
+ clientX: 0,
+ clientY: 0
+};
+var activeInstances = [];
+
+function storeMouseCoords(_ref) {
+ var clientX = _ref.clientX,
+ clientY = _ref.clientY;
+ mouseCoords = {
+ clientX: clientX,
+ clientY: clientY
+ };
+}
+
+function addMouseCoordsListener(doc) {
+ doc.addEventListener('mousemove', storeMouseCoords);
+}
+
+function removeMouseCoordsListener(doc) {
+ doc.removeEventListener('mousemove', storeMouseCoords);
+}
+
+var followCursor = {
+ name: 'followCursor',
+ defaultValue: false,
+ fn: function fn(instance) {
+ var reference = instance.reference;
+ var doc = getOwnerDocument(instance.props.triggerTarget || reference);
+ var isInternalUpdate = false;
+ var wasFocusEvent = false;
+ var isUnmounted = true;
+ var prevProps = instance.props;
+
+ function getIsInitialBehavior() {
+ return instance.props.followCursor === 'initial' && instance.state.isVisible;
+ }
+
+ function addListener() {
+ doc.addEventListener('mousemove', onMouseMove);
+ }
+
+ function removeListener() {
+ doc.removeEventListener('mousemove', onMouseMove);
+ }
+
+ function unsetGetReferenceClientRect() {
+ isInternalUpdate = true;
+ instance.setProps({
+ getReferenceClientRect: null
+ });
+ isInternalUpdate = false;
+ }
+
+ function onMouseMove(event) {
+ // If the instance is interactive, avoid updating the position unless it's
+ // over the reference element
+ var isCursorOverReference = event.target ? reference.contains(event.target) : true;
+ var followCursor = instance.props.followCursor;
+ var clientX = event.clientX,
+ clientY = event.clientY;
+ var rect = reference.getBoundingClientRect();
+ var relativeX = clientX - rect.left;
+ var relativeY = clientY - rect.top;
+
+ if (isCursorOverReference || !instance.props.interactive) {
+ instance.setProps({
+ // @ts-ignore - unneeded DOMRect properties
+ getReferenceClientRect: function getReferenceClientRect() {
+ var rect = reference.getBoundingClientRect();
+ var x = clientX;
+ var y = clientY;
+
+ if (followCursor === 'initial') {
+ x = rect.left + relativeX;
+ y = rect.top + relativeY;
+ }
+
+ var top = followCursor === 'horizontal' ? rect.top : y;
+ var right = followCursor === 'vertical' ? rect.right : x;
+ var bottom = followCursor === 'horizontal' ? rect.bottom : y;
+ var left = followCursor === 'vertical' ? rect.left : x;
+ return {
+ width: right - left,
+ height: bottom - top,
+ top: top,
+ right: right,
+ bottom: bottom,
+ left: left
+ };
+ }
+ });
+ }
+ }
+
+ function create() {
+ if (instance.props.followCursor) {
+ activeInstances.push({
+ instance: instance,
+ doc: doc
+ });
+ addMouseCoordsListener(doc);
+ }
+ }
+
+ function destroy() {
+ activeInstances = activeInstances.filter(function (data) {
+ return data.instance !== instance;
+ });
+
+ if (activeInstances.filter(function (data) {
+ return data.doc === doc;
+ }).length === 0) {
+ removeMouseCoordsListener(doc);
+ }
+ }
+
+ return {
+ onCreate: create,
+ onDestroy: destroy,
+ onBeforeUpdate: function onBeforeUpdate() {
+ prevProps = instance.props;
+ },
+ onAfterUpdate: function onAfterUpdate(_, _ref2) {
+ var followCursor = _ref2.followCursor;
+
+ if (isInternalUpdate) {
+ return;
+ }
+
+ if (followCursor !== undefined && prevProps.followCursor !== followCursor) {
+ destroy();
+
+ if (followCursor) {
+ create();
+
+ if (instance.state.isMounted && !wasFocusEvent && !getIsInitialBehavior()) {
+ addListener();
+ }
+ } else {
+ removeListener();
+ unsetGetReferenceClientRect();
+ }
+ }
+ },
+ onMount: function onMount() {
+ if (instance.props.followCursor && !wasFocusEvent) {
+ if (isUnmounted) {
+ onMouseMove(mouseCoords);
+ isUnmounted = false;
+ }
+
+ if (!getIsInitialBehavior()) {
+ addListener();
+ }
+ }
+ },
+ onTrigger: function onTrigger(_, event) {
+ if (isMouseEvent(event)) {
+ mouseCoords = {
+ clientX: event.clientX,
+ clientY: event.clientY
+ };
+ }
+
+ wasFocusEvent = event.type === 'focus';
+ },
+ onHidden: function onHidden() {
+ if (instance.props.followCursor) {
+ unsetGetReferenceClientRect();
+ removeListener();
+ isUnmounted = true;
+ }
+ }
+ };
+ }
+};
+
+function getProps(props, modifier) {
+ var _props$popperOptions;
+
+ return {
+ popperOptions: Object.assign({}, props.popperOptions, {
+ modifiers: [].concat((((_props$popperOptions = props.popperOptions) == null ? void 0 : _props$popperOptions.modifiers) || []).filter(function (_ref) {
+ var name = _ref.name;
+ return name !== modifier.name;
+ }), [modifier])
+ })
+ };
+}
+
+var inlinePositioning = {
+ name: 'inlinePositioning',
+ defaultValue: false,
+ fn: function fn(instance) {
+ var reference = instance.reference;
+
+ function isEnabled() {
+ return !!instance.props.inlinePositioning;
+ }
+
+ var placement;
+ var cursorRectIndex = -1;
+ var isInternalUpdate = false;
+ var triedPlacements = [];
+ var modifier = {
+ name: 'tippyInlinePositioning',
+ enabled: true,
+ phase: 'afterWrite',
+ fn: function fn(_ref2) {
+ var state = _ref2.state;
+
+ if (isEnabled()) {
+ if (triedPlacements.indexOf(state.placement) !== -1) {
+ triedPlacements = [];
+ }
+
+ if (placement !== state.placement && triedPlacements.indexOf(state.placement) === -1) {
+ triedPlacements.push(state.placement);
+ instance.setProps({
+ // @ts-ignore - unneeded DOMRect properties
+ getReferenceClientRect: function getReferenceClientRect() {
+ return _getReferenceClientRect(state.placement);
+ }
+ });
+ }
+
+ placement = state.placement;
+ }
+ }
+ };
+
+ function _getReferenceClientRect(placement) {
+ return getInlineBoundingClientRect(tippy_esm_getBasePlacement(placement), reference.getBoundingClientRect(), arrayFrom(reference.getClientRects()), cursorRectIndex);
+ }
+
+ function setInternalProps(partialProps) {
+ isInternalUpdate = true;
+ instance.setProps(partialProps);
+ isInternalUpdate = false;
+ }
+
+ function addModifier() {
+ if (!isInternalUpdate) {
+ setInternalProps(getProps(instance.props, modifier));
+ }
+ }
+
+ return {
+ onCreate: addModifier,
+ onAfterUpdate: addModifier,
+ onTrigger: function onTrigger(_, event) {
+ if (isMouseEvent(event)) {
+ var rects = arrayFrom(instance.reference.getClientRects());
+ var cursorRect = rects.find(function (rect) {
+ return rect.left - 2 <= event.clientX && rect.right + 2 >= event.clientX && rect.top - 2 <= event.clientY && rect.bottom + 2 >= event.clientY;
+ });
+ var index = rects.indexOf(cursorRect);
+ cursorRectIndex = index > -1 ? index : cursorRectIndex;
+ }
+ },
+ onHidden: function onHidden() {
+ cursorRectIndex = -1;
+ }
+ };
+ }
+};
+function getInlineBoundingClientRect(currentBasePlacement, boundingRect, clientRects, cursorRectIndex) {
+ // Not an inline element, or placement is not yet known
+ if (clientRects.length < 2 || currentBasePlacement === null) {
+ return boundingRect;
+ } // There are two rects and they are disjoined
+
+
+ if (clientRects.length === 2 && cursorRectIndex >= 0 && clientRects[0].left > clientRects[1].right) {
+ return clientRects[cursorRectIndex] || boundingRect;
+ }
+
+ switch (currentBasePlacement) {
+ case 'top':
+ case 'bottom':
+ {
+ var firstRect = clientRects[0];
+ var lastRect = clientRects[clientRects.length - 1];
+ var isTop = currentBasePlacement === 'top';
+ var top = firstRect.top;
+ var bottom = lastRect.bottom;
+ var left = isTop ? firstRect.left : lastRect.left;
+ var right = isTop ? firstRect.right : lastRect.right;
+ var width = right - left;
+ var height = bottom - top;
+ return {
+ top: top,
+ bottom: bottom,
+ left: left,
+ right: right,
+ width: width,
+ height: height
+ };
+ }
+
+ case 'left':
+ case 'right':
+ {
+ var minLeft = Math.min.apply(Math, clientRects.map(function (rects) {
+ return rects.left;
+ }));
+ var maxRight = Math.max.apply(Math, clientRects.map(function (rects) {
+ return rects.right;
+ }));
+ var measureRects = clientRects.filter(function (rect) {
+ return currentBasePlacement === 'left' ? rect.left === minLeft : rect.right === maxRight;
+ });
+ var _top = measureRects[0].top;
+ var _bottom = measureRects[measureRects.length - 1].bottom;
+ var _left = minLeft;
+ var _right = maxRight;
+
+ var _width = _right - _left;
+
+ var _height = _bottom - _top;
+
+ return {
+ top: _top,
+ bottom: _bottom,
+ left: _left,
+ right: _right,
+ width: _width,
+ height: _height
+ };
+ }
+
+ default:
+ {
+ return boundingRect;
+ }
+ }
+}
+
+var sticky = {
+ name: 'sticky',
+ defaultValue: false,
+ fn: function fn(instance) {
+ var reference = instance.reference,
+ popper = instance.popper;
+
+ function getReference() {
+ return instance.popperInstance ? instance.popperInstance.state.elements.reference : reference;
+ }
+
+ function shouldCheck(value) {
+ return instance.props.sticky === true || instance.props.sticky === value;
+ }
+
+ var prevRefRect = null;
+ var prevPopRect = null;
+
+ function updatePosition() {
+ var currentRefRect = shouldCheck('reference') ? getReference().getBoundingClientRect() : null;
+ var currentPopRect = shouldCheck('popper') ? popper.getBoundingClientRect() : null;
+
+ if (currentRefRect && areRectsDifferent(prevRefRect, currentRefRect) || currentPopRect && areRectsDifferent(prevPopRect, currentPopRect)) {
+ if (instance.popperInstance) {
+ instance.popperInstance.update();
+ }
+ }
+
+ prevRefRect = currentRefRect;
+ prevPopRect = currentPopRect;
+
+ if (instance.state.isMounted) {
+ requestAnimationFrame(updatePosition);
+ }
+ }
+
+ return {
+ onMount: function onMount() {
+ if (instance.props.sticky) {
+ updatePosition();
+ }
+ }
+ };
+ }
+};
+
+function areRectsDifferent(rectA, rectB) {
+ if (rectA && rectB) {
+ return rectA.top !== rectB.top || rectA.right !== rectB.right || rectA.bottom !== rectB.bottom || rectA.left !== rectB.left;
+ }
+
+ return true;
+}
+
+tippy.setDefaultProps({
+ render: render
+});
+
+/* harmony default export */ const tippy_esm = (tippy);
+
+//# sourceMappingURL=tippy.esm.js.map
+
+
+/***/ }),
+
+/***/ 7986:
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+// A library of seedable RNGs implemented in Javascript.
+//
+// Usage:
+//
+// var seedrandom = require('seedrandom');
+// var random = seedrandom(1); // or any seed.
+// var x = random(); // 0 <= x < 1. Every bit is random.
+// var x = random.quick(); // 0 <= x < 1. 32 bits of randomness.
+
+// alea, a 53-bit multiply-with-carry generator by Johannes BaagΓΈe.
+// Period: ~2^116
+// Reported to pass all BigCrush tests.
+var alea = __webpack_require__(8243);
+
+// xor128, a pure xor-shift generator by George Marsaglia.
+// Period: 2^128-1.
+// Reported to fail: MatrixRank and LinearComp.
+var xor128 = __webpack_require__(9270);
+
+// xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl.
+// Period: 2^192-2^32
+// Reported to fail: CollisionOver, SimpPoker, and LinearComp.
+var xorwow = __webpack_require__(8572);
+
+// xorshift7, by FranΓ§ois Panneton and Pierre L'ecuyer, takes
+// a different approach: it adds robustness by allowing more shifts
+// than Marsaglia's original three. It is a 7-shift generator
+// with 256 bits, that passes BigCrush with no systmatic failures.
+// Period 2^256-1.
+// No systematic BigCrush failures reported.
+var xorshift7 = __webpack_require__(3006);
+
+// xor4096, by Richard Brent, is a 4096-bit xor-shift with a
+// very long period that also adds a Weyl generator. It also passes
+// BigCrush with no systematic failures. Its long period may
+// be useful if you have many generators and need to avoid
+// collisions.
+// Period: 2^4128-2^32.
+// No systematic BigCrush failures reported.
+var xor4096 = __webpack_require__(2388);
+
+// Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random
+// number generator derived from ChaCha, a modern stream cipher.
+// https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf
+// Period: ~2^127
+// No systematic BigCrush failures reported.
+var tychei = __webpack_require__(7954);
+
+// The original ARC4-based prng included in this library.
+// Period: ~2^1600
+var sr = __webpack_require__(4938);
+
+sr.alea = alea;
+sr.xor128 = xor128;
+sr.xorwow = xorwow;
+sr.xorshift7 = xorshift7;
+sr.xor4096 = xor4096;
+sr.tychei = tychei;
+
+module.exports = sr;
+
+
+/***/ }),
+
+/***/ 8243:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;// A port of an algorithm by Johannes BaagΓΈe , 2010
+// http://baagoe.com/en/RandomMusings/javascript/
+// https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
+// Original work is under MIT license -
+
+// Copyright (C) 2010 by Johannes BaagΓΈe
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+
+(function(global, module, define) {
+
+function Alea(seed) {
+ var me = this, mash = Mash();
+
+ me.next = function() {
+ var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32
+ me.s0 = me.s1;
+ me.s1 = me.s2;
+ return me.s2 = t - (me.c = t | 0);
+ };
+
+ // Apply the seeding algorithm from Baagoe.
+ me.c = 1;
+ me.s0 = mash(' ');
+ me.s1 = mash(' ');
+ me.s2 = mash(' ');
+ me.s0 -= mash(seed);
+ if (me.s0 < 0) { me.s0 += 1; }
+ me.s1 -= mash(seed);
+ if (me.s1 < 0) { me.s1 += 1; }
+ me.s2 -= mash(seed);
+ if (me.s2 < 0) { me.s2 += 1; }
+ mash = null;
+}
+
+function copy(f, t) {
+ t.c = f.c;
+ t.s0 = f.s0;
+ t.s1 = f.s1;
+ t.s2 = f.s2;
+ return t;
+}
+
+function impl(seed, opts) {
+ var xg = new Alea(seed),
+ state = opts && opts.state,
+ prng = xg.next;
+ prng.int32 = function() { return (xg.next() * 0x100000000) | 0; }
+ prng.double = function() {
+ return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
+ };
+ prng.quick = prng;
+ if (state) {
+ if (typeof(state) == 'object') copy(state, xg);
+ prng.state = function() { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+function Mash() {
+ var n = 0xefc8249d;
+
+ var mash = function(data) {
+ data = data.toString();
+ for (var i = 0; i < data.length; i++) {
+ n += data.charCodeAt(i);
+ var h = 0.02519603282416938 * n;
+ n = h >>> 0;
+ h -= n;
+ h *= n;
+ n = h >>> 0;
+ h -= n;
+ n += h * 0x100000000; // 2^32
+ }
+ return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
+ };
+
+ return mash;
+}
+
+
+if (module && module.exports) {
+ module.exports = impl;
+} else if (__webpack_require__.amdD && __webpack_require__.amdO) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return impl; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+} else {
+ this.alea = impl;
+}
+
+})(
+ this,
+ true && module, // present in node.js
+ __webpack_require__.amdD // present with an AMD loader
+);
+
+
+
+
+/***/ }),
+
+/***/ 7954:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;// A Javascript implementaion of the "Tyche-i" prng algorithm by
+// Samuel Neves and Filipe Araujo.
+// See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf
+
+(function(global, module, define) {
+
+function XorGen(seed) {
+ var me = this, strseed = '';
+
+ // Set up generator function.
+ me.next = function() {
+ var b = me.b, c = me.c, d = me.d, a = me.a;
+ b = (b << 25) ^ (b >>> 7) ^ c;
+ c = (c - d) | 0;
+ d = (d << 24) ^ (d >>> 8) ^ a;
+ a = (a - b) | 0;
+ me.b = b = (b << 20) ^ (b >>> 12) ^ c;
+ me.c = c = (c - d) | 0;
+ me.d = (d << 16) ^ (c >>> 16) ^ a;
+ return me.a = (a - b) | 0;
+ };
+
+ /* The following is non-inverted tyche, which has better internal
+ * bit diffusion, but which is about 25% slower than tyche-i in JS.
+ me.next = function() {
+ var a = me.a, b = me.b, c = me.c, d = me.d;
+ a = (me.a + me.b | 0) >>> 0;
+ d = me.d ^ a; d = d << 16 ^ d >>> 16;
+ c = me.c + d | 0;
+ b = me.b ^ c; b = b << 12 ^ d >>> 20;
+ me.a = a = a + b | 0;
+ d = d ^ a; me.d = d = d << 8 ^ d >>> 24;
+ me.c = c = c + d | 0;
+ b = b ^ c;
+ return me.b = (b << 7 ^ b >>> 25);
+ }
+ */
+
+ me.a = 0;
+ me.b = 0;
+ me.c = 2654435769 | 0;
+ me.d = 1367130551;
+
+ if (seed === Math.floor(seed)) {
+ // Integer seed.
+ me.a = (seed / 0x100000000) | 0;
+ me.b = seed | 0;
+ } else {
+ // String seed.
+ strseed += seed;
+ }
+
+ // Mix in string seed, then discard an initial batch of 64 values.
+ for (var k = 0; k < strseed.length + 20; k++) {
+ me.b ^= strseed.charCodeAt(k) | 0;
+ me.next();
+ }
+}
+
+function copy(f, t) {
+ t.a = f.a;
+ t.b = f.b;
+ t.c = f.c;
+ t.d = f.d;
+ return t;
+};
+
+function impl(seed, opts) {
+ var xg = new XorGen(seed),
+ state = opts && opts.state,
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
+ prng.double = function() {
+ do {
+ var top = xg.next() >>> 11,
+ bot = (xg.next() >>> 0) / 0x100000000,
+ result = (top + bot) / (1 << 21);
+ } while (result === 0);
+ return result;
+ };
+ prng.int32 = xg.next;
+ prng.quick = prng;
+ if (state) {
+ if (typeof(state) == 'object') copy(state, xg);
+ prng.state = function() { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+if (module && module.exports) {
+ module.exports = impl;
+} else if (__webpack_require__.amdD && __webpack_require__.amdO) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return impl; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+} else {
+ this.tychei = impl;
+}
+
+})(
+ this,
+ true && module, // present in node.js
+ __webpack_require__.amdD // present with an AMD loader
+);
+
+
+
+
+/***/ }),
+
+/***/ 9270:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;// A Javascript implementaion of the "xor128" prng algorithm by
+// George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper
+
+(function(global, module, define) {
+
+function XorGen(seed) {
+ var me = this, strseed = '';
+
+ me.x = 0;
+ me.y = 0;
+ me.z = 0;
+ me.w = 0;
+
+ // Set up generator function.
+ me.next = function() {
+ var t = me.x ^ (me.x << 11);
+ me.x = me.y;
+ me.y = me.z;
+ me.z = me.w;
+ return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8);
+ };
+
+ if (seed === (seed | 0)) {
+ // Integer seed.
+ me.x = seed;
+ } else {
+ // String seed.
+ strseed += seed;
+ }
+
+ // Mix in string seed, then discard an initial batch of 64 values.
+ for (var k = 0; k < strseed.length + 64; k++) {
+ me.x ^= strseed.charCodeAt(k) | 0;
+ me.next();
+ }
+}
+
+function copy(f, t) {
+ t.x = f.x;
+ t.y = f.y;
+ t.z = f.z;
+ t.w = f.w;
+ return t;
+}
+
+function impl(seed, opts) {
+ var xg = new XorGen(seed),
+ state = opts && opts.state,
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
+ prng.double = function() {
+ do {
+ var top = xg.next() >>> 11,
+ bot = (xg.next() >>> 0) / 0x100000000,
+ result = (top + bot) / (1 << 21);
+ } while (result === 0);
+ return result;
+ };
+ prng.int32 = xg.next;
+ prng.quick = prng;
+ if (state) {
+ if (typeof(state) == 'object') copy(state, xg);
+ prng.state = function() { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+if (module && module.exports) {
+ module.exports = impl;
+} else if (__webpack_require__.amdD && __webpack_require__.amdO) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return impl; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+} else {
+ this.xor128 = impl;
+}
+
+})(
+ this,
+ true && module, // present in node.js
+ __webpack_require__.amdD // present with an AMD loader
+);
+
+
+
+
+/***/ }),
+
+/***/ 2388:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;// A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm.
+//
+// This fast non-cryptographic random number generator is designed for
+// use in Monte-Carlo algorithms. It combines a long-period xorshift
+// generator with a Weyl generator, and it passes all common batteries
+// of stasticial tests for randomness while consuming only a few nanoseconds
+// for each prng generated. For background on the generator, see Brent's
+// paper: "Some long-period random number generators using shifts and xors."
+// http://arxiv.org/pdf/1004.3115v1.pdf
+//
+// Usage:
+//
+// var xor4096 = require('xor4096');
+// random = xor4096(1); // Seed with int32 or string.
+// assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits.
+// assert.equal(random.int32(), 1806534897); // signed int32, 32 bits.
+//
+// For nonzero numeric keys, this impelementation provides a sequence
+// identical to that by Brent's xorgens 3 implementaion in C. This
+// implementation also provides for initalizing the generator with
+// string seeds, or for saving and restoring the state of the generator.
+//
+// On Chrome, this prng benchmarks about 2.1 times slower than
+// Javascript's built-in Math.random().
+
+(function(global, module, define) {
+
+function XorGen(seed) {
+ var me = this;
+
+ // Set up generator function.
+ me.next = function() {
+ var w = me.w,
+ X = me.X, i = me.i, t, v;
+ // Update Weyl generator.
+ me.w = w = (w + 0x61c88647) | 0;
+ // Update xor generator.
+ v = X[(i + 34) & 127];
+ t = X[i = ((i + 1) & 127)];
+ v ^= v << 13;
+ t ^= t << 17;
+ v ^= v >>> 15;
+ t ^= t >>> 12;
+ // Update Xor generator array state.
+ v = X[i] = v ^ t;
+ me.i = i;
+ // Result is the combination.
+ return (v + (w ^ (w >>> 16))) | 0;
+ };
+
+ function init(me, seed) {
+ var t, v, i, j, w, X = [], limit = 128;
+ if (seed === (seed | 0)) {
+ // Numeric seeds initialize v, which is used to generates X.
+ v = seed;
+ seed = null;
+ } else {
+ // String seeds are mixed into v and X one character at a time.
+ seed = seed + '\0';
+ v = 0;
+ limit = Math.max(limit, seed.length);
+ }
+ // Initialize circular array and weyl value.
+ for (i = 0, j = -32; j < limit; ++j) {
+ // Put the unicode characters into the array, and shuffle them.
+ if (seed) v ^= seed.charCodeAt((j + 32) % seed.length);
+ // After 32 shuffles, take v as the starting w value.
+ if (j === 0) w = v;
+ v ^= v << 10;
+ v ^= v >>> 15;
+ v ^= v << 4;
+ v ^= v >>> 13;
+ if (j >= 0) {
+ w = (w + 0x61c88647) | 0; // Weyl.
+ t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array.
+ i = (0 == t) ? i + 1 : 0; // Count zeroes.
+ }
+ }
+ // We have detected all zeroes; make the key nonzero.
+ if (i >= 128) {
+ X[(seed && seed.length || 0) & 127] = -1;
+ }
+ // Run the generator 512 times to further mix the state before using it.
+ // Factoring this as a function slows the main generator, so it is just
+ // unrolled here. The weyl generator is not advanced while warming up.
+ i = 127;
+ for (j = 4 * 128; j > 0; --j) {
+ v = X[(i + 34) & 127];
+ t = X[i = ((i + 1) & 127)];
+ v ^= v << 13;
+ t ^= t << 17;
+ v ^= v >>> 15;
+ t ^= t >>> 12;
+ X[i] = v ^ t;
+ }
+ // Storing state as object members is faster than using closure variables.
+ me.w = w;
+ me.X = X;
+ me.i = i;
+ }
+
+ init(me, seed);
+}
+
+function copy(f, t) {
+ t.i = f.i;
+ t.w = f.w;
+ t.X = f.X.slice();
+ return t;
+};
+
+function impl(seed, opts) {
+ if (seed == null) seed = +(new Date);
+ var xg = new XorGen(seed),
+ state = opts && opts.state,
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
+ prng.double = function() {
+ do {
+ var top = xg.next() >>> 11,
+ bot = (xg.next() >>> 0) / 0x100000000,
+ result = (top + bot) / (1 << 21);
+ } while (result === 0);
+ return result;
+ };
+ prng.int32 = xg.next;
+ prng.quick = prng;
+ if (state) {
+ if (state.X) copy(state, xg);
+ prng.state = function() { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+if (module && module.exports) {
+ module.exports = impl;
+} else if (__webpack_require__.amdD && __webpack_require__.amdO) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return impl; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+} else {
+ this.xor4096 = impl;
+}
+
+})(
+ this, // window object or global
+ true && module, // present in node.js
+ __webpack_require__.amdD // present with an AMD loader
+);
+
+
+/***/ }),
+
+/***/ 3006:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;// A Javascript implementaion of the "xorshift7" algorithm by
+// FranΓ§ois Panneton and Pierre L'ecuyer:
+// "On the Xorgshift Random Number Generators"
+// http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf
+
+(function(global, module, define) {
+
+function XorGen(seed) {
+ var me = this;
+
+ // Set up generator function.
+ me.next = function() {
+ // Update xor generator.
+ var X = me.x, i = me.i, t, v, w;
+ t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24);
+ t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10);
+ t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3);
+ t = X[(i + 4) & 7]; v ^= t ^ (t << 7);
+ t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9);
+ X[i] = v;
+ me.i = (i + 1) & 7;
+ return v;
+ };
+
+ function init(me, seed) {
+ var j, w, X = [];
+
+ if (seed === (seed | 0)) {
+ // Seed state array using a 32-bit integer.
+ w = X[0] = seed;
+ } else {
+ // Seed state using a string.
+ seed = '' + seed;
+ for (j = 0; j < seed.length; ++j) {
+ X[j & 7] = (X[j & 7] << 15) ^
+ (seed.charCodeAt(j) + X[(j + 1) & 7] << 13);
+ }
+ }
+ // Enforce an array length of 8, not all zeroes.
+ while (X.length < 8) X.push(0);
+ for (j = 0; j < 8 && X[j] === 0; ++j);
+ if (j == 8) w = X[7] = -1; else w = X[j];
+
+ me.x = X;
+ me.i = 0;
+
+ // Discard an initial 256 values.
+ for (j = 256; j > 0; --j) {
+ me.next();
+ }
+ }
+
+ init(me, seed);
+}
+
+function copy(f, t) {
+ t.x = f.x.slice();
+ t.i = f.i;
+ return t;
+}
+
+function impl(seed, opts) {
+ if (seed == null) seed = +(new Date);
+ var xg = new XorGen(seed),
+ state = opts && opts.state,
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
+ prng.double = function() {
+ do {
+ var top = xg.next() >>> 11,
+ bot = (xg.next() >>> 0) / 0x100000000,
+ result = (top + bot) / (1 << 21);
+ } while (result === 0);
+ return result;
+ };
+ prng.int32 = xg.next;
+ prng.quick = prng;
+ if (state) {
+ if (state.x) copy(state, xg);
+ prng.state = function() { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+if (module && module.exports) {
+ module.exports = impl;
+} else if (__webpack_require__.amdD && __webpack_require__.amdO) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return impl; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+} else {
+ this.xorshift7 = impl;
+}
+
+})(
+ this,
+ true && module, // present in node.js
+ __webpack_require__.amdD // present with an AMD loader
+);
+
+
+
+/***/ }),
+
+/***/ 8572:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;// A Javascript implementaion of the "xorwow" prng algorithm by
+// George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper
+
+(function(global, module, define) {
+
+function XorGen(seed) {
+ var me = this, strseed = '';
+
+ // Set up generator function.
+ me.next = function() {
+ var t = (me.x ^ (me.x >>> 2));
+ me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v;
+ return (me.d = (me.d + 362437 | 0)) +
+ (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0;
+ };
+
+ me.x = 0;
+ me.y = 0;
+ me.z = 0;
+ me.w = 0;
+ me.v = 0;
+
+ if (seed === (seed | 0)) {
+ // Integer seed.
+ me.x = seed;
+ } else {
+ // String seed.
+ strseed += seed;
+ }
+
+ // Mix in string seed, then discard an initial batch of 64 values.
+ for (var k = 0; k < strseed.length + 64; k++) {
+ me.x ^= strseed.charCodeAt(k) | 0;
+ if (k == strseed.length) {
+ me.d = me.x << 10 ^ me.x >>> 4;
+ }
+ me.next();
+ }
+}
+
+function copy(f, t) {
+ t.x = f.x;
+ t.y = f.y;
+ t.z = f.z;
+ t.w = f.w;
+ t.v = f.v;
+ t.d = f.d;
+ return t;
+}
+
+function impl(seed, opts) {
+ var xg = new XorGen(seed),
+ state = opts && opts.state,
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
+ prng.double = function() {
+ do {
+ var top = xg.next() >>> 11,
+ bot = (xg.next() >>> 0) / 0x100000000,
+ result = (top + bot) / (1 << 21);
+ } while (result === 0);
+ return result;
+ };
+ prng.int32 = xg.next;
+ prng.quick = prng;
+ if (state) {
+ if (typeof(state) == 'object') copy(state, xg);
+ prng.state = function() { return copy(xg, {}); }
+ }
+ return prng;
+}
+
+if (module && module.exports) {
+ module.exports = impl;
+} else if (__webpack_require__.amdD && __webpack_require__.amdO) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return impl; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+} else {
+ this.xorwow = impl;
+}
+
+})(
+ this,
+ true && module, // present in node.js
+ __webpack_require__.amdD // present with an AMD loader
+);
+
+
+
+
+/***/ }),
+
+/***/ 4938:
+/***/ ((module, exports, __webpack_require__) => {
+
+var __WEBPACK_AMD_DEFINE_RESULT__;/*
+Copyright 2014 David Bau.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+(function (pool, math) {
+//
+// The following constants are related to IEEE 754 limits.
+//
+
+// Detect the global object, even if operating in strict mode.
+// http://stackoverflow.com/a/14387057/265298
+var global = (0, eval)('this'),
+ width = 256, // each RC4 output is 0 <= x < 256
+ chunks = 6, // at least six RC4 outputs for each double
+ digits = 52, // there are 52 significant digits in a double
+ rngname = 'random', // rngname: name for Math.random and Math.seedrandom
+ startdenom = math.pow(width, chunks),
+ significance = math.pow(2, digits),
+ overflow = significance * 2,
+ mask = width - 1,
+ nodecrypto; // node.js crypto module, initialized at the bottom.
+
+//
+// seedrandom()
+// This is the seedrandom function described above.
+//
+function seedrandom(seed, options, callback) {
+ var key = [];
+ options = (options == true) ? { entropy: true } : (options || {});
+
+ // Flatten the seed string or build one from local entropy if needed.
+ var shortseed = mixkey(flatten(
+ options.entropy ? [seed, tostring(pool)] :
+ (seed == null) ? autoseed() : seed, 3), key);
+
+ // Use the seed to initialize an ARC4 generator.
+ var arc4 = new ARC4(key);
+
+ // This function returns a random double in [0, 1) that contains
+ // randomness in every bit of the mantissa of the IEEE 754 value.
+ var prng = function() {
+ var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48
+ d = startdenom, // and denominator d = 2 ^ 48.
+ x = 0; // and no 'extra last byte'.
+ while (n < significance) { // Fill up all significant digits by
+ n = (n + x) * width; // shifting numerator and
+ d *= width; // denominator and generating a
+ x = arc4.g(1); // new least-significant-byte.
+ }
+ while (n >= overflow) { // To avoid rounding up, before adding
+ n /= 2; // last byte, shift everything
+ d /= 2; // right using integer math until
+ x >>>= 1; // we have exactly the desired bits.
+ }
+ return (n + x) / d; // Form the number within [0, 1).
+ };
+
+ prng.int32 = function() { return arc4.g(4) | 0; }
+ prng.quick = function() { return arc4.g(4) / 0x100000000; }
+ prng.double = prng;
+
+ // Mix the randomness into accumulated entropy.
+ mixkey(tostring(arc4.S), pool);
+
+ // Calling convention: what to return as a function of prng, seed, is_math.
+ return (options.pass || callback ||
+ function(prng, seed, is_math_call, state) {
+ if (state) {
+ // Load the arc4 state from the given state if it has an S array.
+ if (state.S) { copy(state, arc4); }
+ // Only provide the .state method if requested via options.state.
+ prng.state = function() { return copy(arc4, {}); }
+ }
+
+ // If called as a method of Math (Math.seedrandom()), mutate
+ // Math.random because that is how seedrandom.js has worked since v1.0.
+ if (is_math_call) { math[rngname] = prng; return seed; }
+
+ // Otherwise, it is a newer calling convention, so return the
+ // prng directly.
+ else return prng;
+ })(
+ prng,
+ shortseed,
+ 'global' in options ? options.global : (this == math),
+ options.state);
+}
+math['seed' + rngname] = seedrandom;
+
+//
+// ARC4
+//
+// An ARC4 implementation. The constructor takes a key in the form of
+// an array of at most (width) integers that should be 0 <= x < (width).
+//
+// The g(count) method returns a pseudorandom integer that concatenates
+// the next (count) outputs from ARC4. Its return value is a number x
+// that is in the range 0 <= x < (width ^ count).
+//
+function ARC4(key) {
+ var t, keylen = key.length,
+ me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];
+
+ // The empty key [] is treated as [0].
+ if (!keylen) { key = [keylen++]; }
+
+ // Set up S using the standard key scheduling algorithm.
+ while (i < width) {
+ s[i] = i++;
+ }
+ for (i = 0; i < width; i++) {
+ s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];
+ s[j] = t;
+ }
+
+ // The "g" method returns the next (count) outputs as one number.
+ (me.g = function(count) {
+ // Using instance members instead of closure state nearly doubles speed.
+ var t, r = 0,
+ i = me.i, j = me.j, s = me.S;
+ while (count--) {
+ t = s[i = mask & (i + 1)];
+ r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];
+ }
+ me.i = i; me.j = j;
+ return r;
+ // For robust unpredictability, the function call below automatically
+ // discards an initial batch of values. This is called RC4-drop[256].
+ // See http://google.com/search?q=rsa+fluhrer+response&btnI
+ })(width);
+}
+
+//
+// copy()
+// Copies internal state of ARC4 to or from a plain object.
+//
+function copy(f, t) {
+ t.i = f.i;
+ t.j = f.j;
+ t.S = f.S.slice();
+ return t;
+};
+
+//
+// flatten()
+// Converts an object tree to nested arrays of strings.
+//
+function flatten(obj, depth) {
+ var result = [], typ = (typeof obj), prop;
+ if (depth && typ == 'object') {
+ for (prop in obj) {
+ try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
+ }
+ }
+ return (result.length ? result : typ == 'string' ? obj : obj + '\0');
+}
+
+//
+// mixkey()
+// Mixes a string seed into a key that is an array of integers, and
+// returns a shortened string seed that is equivalent to the result key.
+//
+function mixkey(seed, key) {
+ var stringseed = seed + '', smear, j = 0;
+ while (j < stringseed.length) {
+ key[mask & j] =
+ mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));
+ }
+ return tostring(key);
+}
+
+//
+// autoseed()
+// Returns an object for autoseeding, using window.crypto and Node crypto
+// module if available.
+//
+function autoseed() {
+ try {
+ var out;
+ if (nodecrypto && (out = nodecrypto.randomBytes)) {
+ // The use of 'out' to remember randomBytes makes tight minified code.
+ out = out(width);
+ } else {
+ out = new Uint8Array(width);
+ (global.crypto || global.msCrypto).getRandomValues(out);
+ }
+ return tostring(out);
+ } catch (e) {
+ var browser = global.navigator,
+ plugins = browser && browser.plugins;
+ return [+new Date, global, plugins, global.screen, tostring(pool)];
+ }
+}
+
+//
+// tostring()
+// Converts an array of charcodes to a string
+//
+function tostring(a) {
+ return String.fromCharCode.apply(0, a);
+}
+
+//
+// When seedrandom.js is loaded, we immediately mix a few bits
+// from the built-in RNG into the entropy pool. Because we do
+// not want to interfere with deterministic PRNG state later,
+// seedrandom will not call math.random on its own again after
+// initialization.
+//
+mixkey(math.random(), pool);
+
+//
+// Nodejs and AMD support: export the implementation as a module using
+// either convention.
+//
+if ( true && module.exports) {
+ module.exports = seedrandom;
+ // When in node.js, try using crypto package for autoseeding.
+ try {
+ nodecrypto = __webpack_require__(9011);
+ } catch (ex) {}
+} else if (true) {
+ !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return seedrandom; }).call(exports, __webpack_require__, exports, module),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+}
+
+// End anonymous scope, and pass initial values.
+})(
+ [], // pool: entropy pool starts empty
+ Math // math: package containing random, pow, and seedrandom
+);
+
+
+/***/ }),
+
+/***/ 5365:
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+var seedrandom = __webpack_require__(7986);
+var self = __webpack_require__(1020);
+
+module.exports = self;
+
+
+
+/***/ }),
+
+/***/ 1020:
+/***/ (function(module) {
+
+;(function() {
+ var self = {};
+
+ if(Math.seedrandom) seedrandom = Math.seedrandom;
+
+ var isArray = function($){
+ return Object.prototype.toString.call( $ ) === '[object Array]'
+ }
+
+ var extend = function(obj) {
+ for (var i = 1; i < arguments.length; i++) for (var key in arguments[i]) obj[key] = arguments[i][key];
+ return obj;
+ }
+
+ var seedify = function(seed){
+ if (/(number|string)/i.test(Object.prototype.toString.call(seed).match(/^\[object (.*)\]$/)[1])) return seed;
+ if (isNaN(seed)) return Number(String((this.strSeed = seed)).split('').map(function(x){return x.charCodeAt(0)}).join(''));
+ return seed;
+ }
+
+ var seedRand = function(func,min,max){
+ return Math.floor(func() * (max - min + 1)) + min;
+ }
+
+ self.shuffle = function(arr,seed){
+ if (!isArray(arr)) return null;
+ seed = seedify(seed) || 'none';
+
+ var size = arr.length;
+ var rng = seedrandom(seed);
+ var resp = [];
+ var keys = [];
+
+ for(var i=0;i {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.DispatchError = void 0;
+/**
+ * Indicates an error with dispatching.
+ *
+ * @export
+ * @class DispatchError
+ * @extends {Error}
+ */
+class DispatchError extends Error {
+ /**
+ * Creates an instance of DispatchError.
+ * @param {string} message The message.
+ *
+ * @memberOf DispatchError
+ */
+ constructor(message) {
+ super(message);
+ }
+}
+exports.DispatchError = DispatchError;
+
+
+/***/ }),
+
+/***/ 2464:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.DispatcherBase = void 0;
+const __1 = __webpack_require__(4327);
+/**
+ * Base class for implementation of the dispatcher. It facilitates the subscribe
+ * and unsubscribe methods based on generic handlers. The TEventType specifies
+ * the type of event that should be exposed. Use the asEvent to expose the
+ * dispatcher as event.
+ *
+ * @export
+ * @abstract
+ * @class DispatcherBase
+ * @implements {ISubscribable}
+ * @template TEventHandler The type of event handler.
+ */
+class DispatcherBase {
+ constructor() {
+ /**
+ * The subscriptions.
+ *
+ * @protected
+ *
+ * @memberOf DispatcherBase
+ */
+ this._subscriptions = new Array();
+ }
+ /**
+ * Returns the number of subscriptions.
+ *
+ * @readonly
+ * @type {number}
+ * @memberOf DispatcherBase
+ */
+ get count() {
+ return this._subscriptions.length;
+ }
+ /**
+ * Triggered when subscriptions are changed (added or removed).
+ *
+ * @readonly
+ * @type {ISubscribable}
+ * @memberOf DispatcherBase
+ */
+ get onSubscriptionChange() {
+ if (this._onSubscriptionChange == null) {
+ this._onSubscriptionChange = new __1.SubscriptionChangeEventDispatcher();
+ }
+ return this._onSubscriptionChange.asEvent();
+ }
+ /**
+ * Subscribe to the event dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ * @returns A function that unsubscribes the event handler from the event.
+ *
+ * @memberOf DispatcherBase
+ */
+ subscribe(fn) {
+ if (fn) {
+ this._subscriptions.push(this.createSubscription(fn, false));
+ this.triggerSubscriptionChange();
+ }
+ return () => {
+ this.unsubscribe(fn);
+ };
+ }
+ /**
+ * Subscribe to the event dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ * @returns A function that unsubscribes the event handler from the event.
+ *
+ * @memberOf DispatcherBase
+ */
+ sub(fn) {
+ return this.subscribe(fn);
+ }
+ /**
+ * Subscribe once to the event with the specified name.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ * @returns A function that unsubscribes the event handler from the event.
+ *
+ * @memberOf DispatcherBase
+ */
+ one(fn) {
+ if (fn) {
+ this._subscriptions.push(this.createSubscription(fn, true));
+ this.triggerSubscriptionChange();
+ }
+ return () => {
+ this.unsubscribe(fn);
+ };
+ }
+ /**
+ * Checks it the event has a subscription for the specified handler.
+ *
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf DispatcherBase
+ */
+ has(fn) {
+ if (!fn)
+ return false;
+ return this._subscriptions.some((sub) => sub.handler == fn);
+ }
+ /**
+ * Unsubscribes the handler from the dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf DispatcherBase
+ */
+ unsubscribe(fn) {
+ if (!fn)
+ return;
+ let changes = false;
+ for (let i = 0; i < this._subscriptions.length; i++) {
+ if (this._subscriptions[i].handler == fn) {
+ this._subscriptions.splice(i, 1);
+ changes = true;
+ break;
+ }
+ }
+ if (changes) {
+ this.triggerSubscriptionChange();
+ }
+ }
+ /**
+ * Unsubscribes the handler from the dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf DispatcherBase
+ */
+ unsub(fn) {
+ this.unsubscribe(fn);
+ }
+ /**
+ * Generic dispatch will dispatch the handlers with the given arguments.
+ *
+ * @protected
+ * @param {boolean} executeAsync `True` if the even should be executed async.
+ * @param {*} scope The scope of the event. The scope becomes the `this` for handler.
+ * @param {IArguments} args The arguments for the event.
+ * @returns {(IPropagationStatus | null)} The propagation status, or if an `executeAsync` is used `null`.
+ *
+ * @memberOf DispatcherBase
+ */
+ _dispatch(executeAsync, scope, args) {
+ //execute on a copy because of bug #9
+ for (let sub of [...this._subscriptions]) {
+ let ev = new __1.EventManagement(() => this.unsub(sub.handler));
+ let nargs = Array.prototype.slice.call(args);
+ nargs.push(ev);
+ let s = sub;
+ s.execute(executeAsync, scope, nargs);
+ //cleanup subs that are no longer needed
+ this.cleanup(sub);
+ if (!executeAsync && ev.propagationStopped) {
+ return { propagationStopped: true };
+ }
+ }
+ if (executeAsync) {
+ return null;
+ }
+ return { propagationStopped: false };
+ }
+ /**
+ * Creates a subscription.
+ *
+ * @protected
+ * @param {TEventHandler} handler The handler.
+ * @param {boolean} isOnce True if the handler should run only one.
+ * @returns {ISubscription} The subscription.
+ *
+ * @memberOf DispatcherBase
+ */
+ createSubscription(handler, isOnce) {
+ return new __1.Subscription(handler, isOnce);
+ }
+ /**
+ * Cleans up subs that ran and should run only once.
+ *
+ * @protected
+ * @param {ISubscription} sub The subscription.
+ *
+ * @memberOf DispatcherBase
+ */
+ cleanup(sub) {
+ let changes = false;
+ if (sub.isOnce && sub.isExecuted) {
+ let i = this._subscriptions.indexOf(sub);
+ if (i > -1) {
+ this._subscriptions.splice(i, 1);
+ changes = true;
+ }
+ }
+ if (changes) {
+ this.triggerSubscriptionChange();
+ }
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ *
+ * @returns {ISubscribable}
+ *
+ * @memberOf DispatcherBase
+ */
+ asEvent() {
+ if (this._wrap == null) {
+ this._wrap = new __1.DispatcherWrapper(this);
+ }
+ return this._wrap;
+ }
+ /**
+ * Clears the subscriptions.
+ *
+ * @memberOf DispatcherBase
+ */
+ clear() {
+ if (this._subscriptions.length != 0) {
+ this._subscriptions.splice(0, this._subscriptions.length);
+ this.triggerSubscriptionChange();
+ }
+ }
+ /**
+ * Triggers the subscription change event.
+ *
+ * @private
+ *
+ * @memberOf DispatcherBase
+ */
+ triggerSubscriptionChange() {
+ if (this._onSubscriptionChange != null) {
+ this._onSubscriptionChange.dispatch(this.count);
+ }
+ }
+}
+exports.DispatcherBase = DispatcherBase;
+
+
+/***/ }),
+
+/***/ 7210:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.DispatcherWrapper = void 0;
+/**
+ * Hides the implementation of the event dispatcher. Will expose methods that
+ * are relevent to the event.
+ *
+ * @export
+ * @class DispatcherWrapper
+ * @implements {ISubscribable}
+ * @template TEventHandler The type of event handler.
+ */
+class DispatcherWrapper {
+ /**
+ * Creates an instance of DispatcherWrapper.
+ * @param {ISubscribable} dispatcher
+ *
+ * @memberOf DispatcherWrapper
+ */
+ constructor(dispatcher) {
+ this._subscribe = (fn) => dispatcher.subscribe(fn);
+ this._unsubscribe = (fn) => dispatcher.unsubscribe(fn);
+ this._one = (fn) => dispatcher.one(fn);
+ this._has = (fn) => dispatcher.has(fn);
+ this._clear = () => dispatcher.clear();
+ this._count = () => dispatcher.count;
+ this._onSubscriptionChange = () => dispatcher.onSubscriptionChange;
+ }
+ /**
+ * Triggered when subscriptions are changed (added or removed).
+ *
+ * @readonly
+ * @type {ISubscribable}
+ * @memberOf DispatcherWrapper
+ */
+ get onSubscriptionChange() {
+ return this._onSubscriptionChange();
+ }
+ /**
+ * Returns the number of subscriptions.
+ *
+ * @readonly
+ * @type {number}
+ * @memberOf DispatcherWrapper
+ */
+ get count() {
+ return this._count();
+ }
+ /**
+ * Subscribe to the event dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ * @returns {() => void} A function that unsubscribes the event handler from the event.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ subscribe(fn) {
+ return this._subscribe(fn);
+ }
+ /**
+ * Subscribe to the event dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ * @returns {() => void} A function that unsubscribes the event handler from the event.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ sub(fn) {
+ return this.subscribe(fn);
+ }
+ /**
+ * Unsubscribe from the event dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ unsubscribe(fn) {
+ this._unsubscribe(fn);
+ }
+ /**
+ * Unsubscribe from the event dispatcher.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ unsub(fn) {
+ this.unsubscribe(fn);
+ }
+ /**
+ * Subscribe once to the event with the specified name.
+ *
+ * @returns {() => void} A function that unsubscribes the event handler from the event.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ one(fn) {
+ return this._one(fn);
+ }
+ /**
+ * Checks it the event has a subscription for the specified handler.
+ *
+ * @param {TEventHandler} fn The event handler that is called when the event is dispatched.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ has(fn) {
+ return this._has(fn);
+ }
+ /**
+ * Clears all the subscriptions.
+ *
+ * @memberOf DispatcherWrapper
+ */
+ clear() {
+ this._clear();
+ }
+}
+exports.DispatcherWrapper = DispatcherWrapper;
+
+
+/***/ }),
+
+/***/ 3699:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.EventListBase = void 0;
+/**
+ * Base class for event lists classes. Implements the get and remove.
+ *
+ * @export
+ * @abstract
+ * @class EventListBaset
+ * @template TEventDispatcher The type of event dispatcher.
+ */
+class EventListBase {
+ constructor() {
+ this._events = {};
+ }
+ /**
+ * Gets the dispatcher associated with the name.
+ *
+ * @param {string} name The name of the event.
+ * @returns {TEventDispatcher} The disptacher.
+ *
+ * @memberOf EventListBase
+ */
+ get(name) {
+ let event = this._events[name];
+ if (event) {
+ return event;
+ }
+ event = this.createDispatcher();
+ this._events[name] = event;
+ return event;
+ }
+ /**
+ * Removes the dispatcher associated with the name.
+ *
+ * @param {string} name
+ *
+ * @memberOf EventListBase
+ */
+ remove(name) {
+ delete this._events[name];
+ }
+}
+exports.EventListBase = EventListBase;
+
+
+/***/ }),
+
+/***/ 9787:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseDispatcherBase = void 0;
+const __1 = __webpack_require__(4327);
+/**
+ * Dispatcher base for dispatchers that use promises. Each promise
+ * is awaited before the next is dispatched, unless the event is
+ * dispatched with the executeAsync flag.
+ *
+ * @export
+ * @abstract
+ * @class PromiseDispatcherBase
+ * @extends {DispatcherBase}
+ * @template TEventHandler The type of event handler.
+ */
+class PromiseDispatcherBase extends __1.DispatcherBase {
+ /**
+ * The normal dispatch cannot be used in this class.
+ *
+ * @protected
+ * @param {boolean} executeAsync `True` if the even should be executed async.
+ * @param {*} scope The scope of the event. The scope becomes the `this` for handler.
+ * @param {IArguments} args The arguments for the event.
+ * @returns {(IPropagationStatus | null)} The propagation status, or if an `executeAsync` is used `null`.
+ *
+ * @memberOf DispatcherBase
+ */
+ _dispatch(executeAsync, scope, args) {
+ throw new __1.DispatchError("_dispatch not supported. Use _dispatchAsPromise.");
+ }
+ /**
+ * Crates a new subscription.
+ *
+ * @protected
+ * @param {TEventHandler} handler The handler.
+ * @param {boolean} isOnce Indicates if the handler should only run once.
+ * @returns {ISubscription} The subscription.
+ *
+ * @memberOf PromiseDispatcherBase
+ */
+ createSubscription(handler, isOnce) {
+ return new __1.PromiseSubscription(handler, isOnce);
+ }
+ /**
+ * Generic dispatch will dispatch the handlers with the given arguments.
+ *
+ * @protected
+ * @param {boolean} executeAsync `True` if the even should be executed async.
+ * @param {*} scope The scope of the event. The scope becomes the `this` for handler.
+ * @param {IArguments} args The arguments for the event.
+ * @returns {(IPropagationStatus | null)} The propagation status, or if an `executeAsync` is used `null`.
+ *
+ * @memberOf DispatcherBase
+ */
+ async _dispatchAsPromise(executeAsync, scope, args) {
+ //execute on a copy because of bug #9
+ for (let sub of [...this._subscriptions]) {
+ let ev = new __1.EventManagement(() => this.unsub(sub.handler));
+ let nargs = Array.prototype.slice.call(args);
+ nargs.push(ev);
+ let ps = sub;
+ await ps.execute(executeAsync, scope, nargs);
+ //cleanup subs that are no longer needed
+ this.cleanup(sub);
+ if (!executeAsync && ev.propagationStopped) {
+ return { propagationStopped: true };
+ }
+ }
+ if (executeAsync) {
+ return null;
+ }
+ return { propagationStopped: false };
+ }
+}
+exports.PromiseDispatcherBase = PromiseDispatcherBase;
+
+
+/***/ }),
+
+/***/ 3277:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SubscriptionChangeEventDispatcher = void 0;
+const __1 = __webpack_require__(4327);
+/**
+ * Dispatcher for subscription changes.
+ *
+ * @export
+ * @class SubscriptionChangeEventDispatcher
+ * @extends {DispatcherBase}
+ */
+class SubscriptionChangeEventDispatcher extends __1.DispatcherBase {
+ /**
+ * Dispatches the event.
+ *
+ * @param {number} count The currrent number of subscriptions.
+ *
+ * @memberOf SubscriptionChangeEventDispatcher
+ */
+ dispatch(count) {
+ this._dispatch(false, this, arguments);
+ }
+}
+exports.SubscriptionChangeEventDispatcher = SubscriptionChangeEventDispatcher;
+
+
+/***/ }),
+
+/***/ 8189:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSubscription = void 0;
+/**
+ * Subscription implementation for events with promises.
+ *
+ * @export
+ * @class PromiseSubscription
+ * @implements {ISubscription}
+ * @template TEventHandler The type of event handler.
+ */
+class PromiseSubscription {
+ /**
+ * Creates an instance of PromiseSubscription.
+ * @param {TEventHandler} handler The handler for the subscription.
+ * @param {boolean} isOnce Indicates if the handler should only be executed once.
+ *
+ * @memberOf PromiseSubscription
+ */
+ constructor(handler, isOnce) {
+ this.handler = handler;
+ this.isOnce = isOnce;
+ /**
+ * Indicates if the subscription has been executed before.
+ *
+ * @memberOf PromiseSubscription
+ */
+ this.isExecuted = false;
+ }
+ /**
+ * Executes the handler.
+ *
+ * @param {boolean} executeAsync True if the even should be executed async.
+ * @param {*} scope The scope the scope of the event.
+ * @param {IArguments} args The arguments for the event.
+ *
+ * @memberOf PromiseSubscription
+ */
+ async execute(executeAsync, scope, args) {
+ if (!this.isOnce || !this.isExecuted) {
+ this.isExecuted = true;
+ //TODO: do we need to cast to any -- seems yuck
+ var fn = this.handler;
+ if (executeAsync) {
+ setTimeout(() => {
+ fn.apply(scope, args);
+ }, 1);
+ return;
+ }
+ let result = fn.apply(scope, args);
+ await result;
+ }
+ }
+}
+exports.PromiseSubscription = PromiseSubscription;
+
+
+/***/ }),
+
+/***/ 7824:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.Subscription = void 0;
+/**
+ * Stores a handler. Manages execution meta data.
+ * @class Subscription
+ * @template TEventHandler
+ */
+class Subscription {
+ /**
+ * Creates an instance of Subscription.
+ *
+ * @param {TEventHandler} handler The handler for the subscription.
+ * @param {boolean} isOnce Indicates if the handler should only be executed once.
+ */
+ constructor(handler, isOnce) {
+ this.handler = handler;
+ this.isOnce = isOnce;
+ /**
+ * Indicates if the subscription has been executed before.
+ */
+ this.isExecuted = false;
+ }
+ /**
+ * Executes the handler.
+ *
+ * @param {boolean} executeAsync True if the even should be executed async.
+ * @param {*} scope The scope the scope of the event.
+ * @param {IArguments} args The arguments for the event.
+ */
+ execute(executeAsync, scope, args) {
+ if (!this.isOnce || !this.isExecuted) {
+ this.isExecuted = true;
+ var fn = this.handler;
+ if (executeAsync) {
+ setTimeout(() => {
+ fn.apply(scope, args);
+ }, 1);
+ }
+ else {
+ fn.apply(scope, args);
+ }
+ }
+ }
+}
+exports.Subscription = Subscription;
+
+
+/***/ }),
+
+/***/ 2881:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.HandlingBase = void 0;
+/**
+ * Base class that implements event handling. With a an
+ * event list this base class will expose events that can be
+ * subscribed to. This will give your class generic events.
+ *
+ * @export
+ * @abstract
+ * @class HandlingBase
+ * @template TEventHandler The type of event handler.
+ * @template TDispatcher The type of dispatcher.
+ * @template TList The type of event list.
+ */
+class HandlingBase {
+ /**
+ * Creates an instance of HandlingBase.
+ * @param {TList} events The event list. Used for event management.
+ *
+ * @memberOf HandlingBase
+ */
+ constructor(events) {
+ this.events = events;
+ }
+ /**
+ * Subscribes once to the event with the specified name.
+ * @param {string} name The name of the event.
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf HandlingBase
+ */
+ one(name, fn) {
+ this.events.get(name).one(fn);
+ }
+ /**
+ * Checks it the event has a subscription for the specified handler.
+ * @param {string} name The name of the event.
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf HandlingBase
+ */
+ has(name, fn) {
+ return this.events.get(name).has(fn);
+ }
+ /**
+ * Subscribes to the event with the specified name.
+ * @param {string} name The name of the event.
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf HandlingBase
+ */
+ subscribe(name, fn) {
+ this.events.get(name).subscribe(fn);
+ }
+ /**
+ * Subscribes to the event with the specified name.
+ * @param {string} name The name of the event.
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf HandlingBase
+ */
+ sub(name, fn) {
+ this.subscribe(name, fn);
+ }
+ /**
+ * Unsubscribes from the event with the specified name.
+ * @param {string} name The name of the event.
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf HandlingBase
+ */
+ unsubscribe(name, fn) {
+ this.events.get(name).unsubscribe(fn);
+ }
+ /**
+ * Unsubscribes from the event with the specified name.
+ * @param {string} name The name of the event.
+ * @param {TEventHandler} fn The event handler.
+ *
+ * @memberOf HandlingBase
+ */
+ unsub(name, fn) {
+ this.unsubscribe(name, fn);
+ }
+}
+exports.HandlingBase = HandlingBase;
+
+
+/***/ }),
+
+/***/ 4327:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+/*!
+ * Strongly Typed Events for TypeScript - Core
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SubscriptionChangeEventDispatcher = exports.HandlingBase = exports.PromiseDispatcherBase = exports.PromiseSubscription = exports.DispatchError = exports.EventManagement = exports.EventListBase = exports.DispatcherWrapper = exports.DispatcherBase = exports.Subscription = void 0;
+const DispatcherBase_1 = __webpack_require__(2464);
+Object.defineProperty(exports, "DispatcherBase", ({ enumerable: true, get: function () { return DispatcherBase_1.DispatcherBase; } }));
+const DispatchError_1 = __webpack_require__(9762);
+Object.defineProperty(exports, "DispatchError", ({ enumerable: true, get: function () { return DispatchError_1.DispatchError; } }));
+const DispatcherWrapper_1 = __webpack_require__(7210);
+Object.defineProperty(exports, "DispatcherWrapper", ({ enumerable: true, get: function () { return DispatcherWrapper_1.DispatcherWrapper; } }));
+const EventListBase_1 = __webpack_require__(3699);
+Object.defineProperty(exports, "EventListBase", ({ enumerable: true, get: function () { return EventListBase_1.EventListBase; } }));
+const EventManagement_1 = __webpack_require__(3712);
+Object.defineProperty(exports, "EventManagement", ({ enumerable: true, get: function () { return EventManagement_1.EventManagement; } }));
+const HandlingBase_1 = __webpack_require__(2881);
+Object.defineProperty(exports, "HandlingBase", ({ enumerable: true, get: function () { return HandlingBase_1.HandlingBase; } }));
+const PromiseDispatcherBase_1 = __webpack_require__(9787);
+Object.defineProperty(exports, "PromiseDispatcherBase", ({ enumerable: true, get: function () { return PromiseDispatcherBase_1.PromiseDispatcherBase; } }));
+const PromiseSubscription_1 = __webpack_require__(8189);
+Object.defineProperty(exports, "PromiseSubscription", ({ enumerable: true, get: function () { return PromiseSubscription_1.PromiseSubscription; } }));
+const Subscription_1 = __webpack_require__(7824);
+Object.defineProperty(exports, "Subscription", ({ enumerable: true, get: function () { return Subscription_1.Subscription; } }));
+const SubscriptionChangeEventHandler_1 = __webpack_require__(3277);
+Object.defineProperty(exports, "SubscriptionChangeEventDispatcher", ({ enumerable: true, get: function () { return SubscriptionChangeEventHandler_1.SubscriptionChangeEventDispatcher; } }));
+
+
+/***/ }),
+
+/***/ 3712:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.EventManagement = void 0;
+/**
+ * Allows the user to interact with the event.
+ *
+ * @export
+ * @class EventManagement
+ * @implements {IEventManagement}
+ */
+class EventManagement {
+ /**
+ * Creates an instance of EventManagement.
+ * @param {() => void} unsub An unsubscribe handler.
+ *
+ * @memberOf EventManagement
+ */
+ constructor(unsub) {
+ this.unsub = unsub;
+ this.propagationStopped = false;
+ }
+ /**
+ * Stops the propagation of the event.
+ * Cannot be used when async dispatch is done.
+ *
+ * @memberOf EventManagement
+ */
+ stopPropagation() {
+ this.propagationStopped = true;
+ }
+}
+exports.EventManagement = EventManagement;
+
+
+/***/ }),
+
+/***/ 7552:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.EventDispatcher = void 0;
+const ste_core_1 = __webpack_require__(4327);
+/**
+ * Dispatcher implementation for events. Can be used to subscribe, unsubscribe
+ * or dispatch events. Use the ToEvent() method to expose the event.
+ *
+ * @export
+ * @class EventDispatcher
+ * @extends {DispatcherBase>}
+ * @implements {IEvent}
+ * @template TSender The sender type.
+ * @template TArgs The event arguments type.
+ */
+class EventDispatcher extends ste_core_1.DispatcherBase {
+ /**
+ * Creates an instance of EventDispatcher.
+ *
+ * @memberOf EventDispatcher
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Dispatches the event.
+ *
+ * @param {TSender} sender The sender.
+ * @param {TArgs} args The arguments.
+ * @returns {IPropagationStatus} The propagation status to interact with the event
+ *
+ * @memberOf EventDispatcher
+ */
+ dispatch(sender, args) {
+ const result = this._dispatch(false, this, arguments);
+ if (result == null) {
+ throw new ste_core_1.DispatchError("Got `null` back from dispatch.");
+ }
+ return result;
+ }
+ /**
+ * Dispatches the event in an async way. Does not support event interaction.
+ *
+ * @param {TSender} sender The sender.
+ * @param {TArgs} args The arguments.
+ *
+ * @memberOf EventDispatcher
+ */
+ dispatchAsync(sender, args) {
+ this._dispatch(true, this, arguments);
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ *
+ * @returns {IEvent} The event.
+ *
+ * @memberOf EventDispatcher
+ */
+ asEvent() {
+ return super.asEvent();
+ }
+}
+exports.EventDispatcher = EventDispatcher;
+
+
+/***/ }),
+
+/***/ 3709:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.EventHandlingBase = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const EventList_1 = __webpack_require__(8513);
+/**
+ * Extends objects with signal event handling capabilities.
+ */
+class EventHandlingBase extends ste_core_1.HandlingBase {
+ constructor() {
+ super(new EventList_1.EventList());
+ }
+}
+exports.EventHandlingBase = EventHandlingBase;
+
+
+/***/ }),
+
+/***/ 8513:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.EventList = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const EventDispatcher_1 = __webpack_require__(7552);
+/**
+ * Storage class for multiple events that are accessible by name.
+ * Events dispatchers are automatically created.
+ */
+class EventList extends ste_core_1.EventListBase {
+ /**
+ * Creates a new EventList instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new EventDispatcher_1.EventDispatcher();
+ }
+}
+exports.EventList = EventList;
+
+
+/***/ }),
+
+/***/ 1674:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformEventList = void 0;
+const EventDispatcher_1 = __webpack_require__(7552);
+/**
+ * Similar to EventList, but instead of TArgs, a map of event names ang argument types is provided with TArgsMap.
+ */
+class NonUniformEventList {
+ constructor() {
+ this._events = {};
+ }
+ /**
+ * Gets the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ get(name) {
+ if (this._events[name]) {
+ // @TODO avoid typecasting. Not sure why TS thinks this._events[name] could still be undefined.
+ return this._events[name];
+ }
+ const event = this.createDispatcher();
+ this._events[name] = event;
+ return event;
+ }
+ /**
+ * Removes the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ remove(name) {
+ delete this._events[name];
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new EventDispatcher_1.EventDispatcher();
+ }
+}
+exports.NonUniformEventList = NonUniformEventList;
+
+
+/***/ }),
+
+/***/ 1717:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+/*!
+ * Strongly Typed Events for TypeScript - Core
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformEventList = exports.EventList = exports.EventHandlingBase = exports.EventDispatcher = void 0;
+const EventDispatcher_1 = __webpack_require__(7552);
+Object.defineProperty(exports, "EventDispatcher", ({ enumerable: true, get: function () { return EventDispatcher_1.EventDispatcher; } }));
+const EventHandlingBase_1 = __webpack_require__(3709);
+Object.defineProperty(exports, "EventHandlingBase", ({ enumerable: true, get: function () { return EventHandlingBase_1.EventHandlingBase; } }));
+const EventList_1 = __webpack_require__(8513);
+Object.defineProperty(exports, "EventList", ({ enumerable: true, get: function () { return EventList_1.EventList; } }));
+const NonUniformEventList_1 = __webpack_require__(1674);
+Object.defineProperty(exports, "NonUniformEventList", ({ enumerable: true, get: function () { return NonUniformEventList_1.NonUniformEventList; } }));
+
+
+/***/ }),
+
+/***/ 4675:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformPromiseEventList = void 0;
+const PromiseEventDispatcher_1 = __webpack_require__(6863);
+/**
+ * Similar to EventList, but instead of TArgs, a map of event names ang argument types is provided with TArgsMap.
+ */
+class NonUniformPromiseEventList {
+ constructor() {
+ this._events = {};
+ }
+ /**
+ * Gets the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ get(name) {
+ if (this._events[name]) {
+ // @TODO avoid typecasting. Not sure why TS thinks this._events[name] could still be undefined.
+ return this._events[name];
+ }
+ const event = this.createDispatcher();
+ this._events[name] = event;
+ return event;
+ }
+ /**
+ * Removes the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ remove(name) {
+ delete this._events[name];
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new PromiseEventDispatcher_1.PromiseEventDispatcher();
+ }
+}
+exports.NonUniformPromiseEventList = NonUniformPromiseEventList;
+
+
+/***/ }),
+
+/***/ 6863:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseEventDispatcher = void 0;
+const ste_core_1 = __webpack_require__(4327);
+/**
+ * Dispatcher implementation for events. Can be used to subscribe, unsubscribe
+ * or dispatch events. Use the ToEvent() method to expose the event.
+ *
+ * @export
+ * @class PromiseEventDispatcher
+ * @extends {PromiseDispatcherBase>}
+ * @implements {IPromiseEvent}
+ * @template TSender
+ * @template TArgs
+ */
+class PromiseEventDispatcher extends ste_core_1.PromiseDispatcherBase {
+ /**
+ * Creates a new EventDispatcher instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Dispatches the event.
+ *
+ * @param {TSender} sender The sender object.
+ * @param {TArgs} args The argument object.
+ * @returns {Promise} The status.
+ *
+ * @memberOf PromiseEventDispatcher
+ */
+ async dispatch(sender, args) {
+ const result = await this._dispatchAsPromise(false, this, arguments);
+ if (result == null) {
+ throw new ste_core_1.DispatchError("Got `null` back from dispatch.");
+ }
+ return result;
+ }
+ /**
+ * Dispatches the event without waiting for the result.
+ *
+ * @param {TSender} sender The sender object.
+ * @param {TArgs} args The argument object.
+ *
+ * @memberOf PromiseEventDispatcher
+ */
+ dispatchAsync(sender, args) {
+ this._dispatchAsPromise(true, this, arguments);
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ */
+ asEvent() {
+ return super.asEvent();
+ }
+}
+exports.PromiseEventDispatcher = PromiseEventDispatcher;
+
+
+/***/ }),
+
+/***/ 7226:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseEventHandlingBase = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const PromiseEventList_1 = __webpack_require__(2570);
+/**
+ * Extends objects with signal event handling capabilities.
+ */
+class PromiseEventHandlingBase extends ste_core_1.HandlingBase {
+ constructor() {
+ super(new PromiseEventList_1.PromiseEventList());
+ }
+}
+exports.PromiseEventHandlingBase = PromiseEventHandlingBase;
+
+
+/***/ }),
+
+/***/ 2570:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseEventList = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const PromiseEventDispatcher_1 = __webpack_require__(6863);
+/**
+ * Storage class for multiple events that are accessible by name.
+ * Events dispatchers are automatically created.
+ */
+class PromiseEventList extends ste_core_1.EventListBase {
+ /**
+ * Creates a new EventList instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new PromiseEventDispatcher_1.PromiseEventDispatcher();
+ }
+}
+exports.PromiseEventList = PromiseEventList;
+
+
+/***/ }),
+
+/***/ 8669:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+/*!
+ * Strongly Typed Events for TypeScript - Core
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformPromiseEventList = exports.PromiseEventList = exports.PromiseEventHandlingBase = exports.PromiseEventDispatcher = void 0;
+const PromiseEventDispatcher_1 = __webpack_require__(6863);
+Object.defineProperty(exports, "PromiseEventDispatcher", ({ enumerable: true, get: function () { return PromiseEventDispatcher_1.PromiseEventDispatcher; } }));
+const PromiseEventHandlingBase_1 = __webpack_require__(7226);
+Object.defineProperty(exports, "PromiseEventHandlingBase", ({ enumerable: true, get: function () { return PromiseEventHandlingBase_1.PromiseEventHandlingBase; } }));
+const PromiseEventList_1 = __webpack_require__(2570);
+Object.defineProperty(exports, "PromiseEventList", ({ enumerable: true, get: function () { return PromiseEventList_1.PromiseEventList; } }));
+const NonUniformPromiseEventList_1 = __webpack_require__(4675);
+Object.defineProperty(exports, "NonUniformPromiseEventList", ({ enumerable: true, get: function () { return NonUniformPromiseEventList_1.NonUniformPromiseEventList; } }));
+
+
+/***/ }),
+
+/***/ 8435:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSignalDispatcher = void 0;
+const ste_core_1 = __webpack_require__(4327);
+/**
+ * The dispatcher handles the storage of subsciptions and facilitates
+ * subscription, unsubscription and dispatching of a signal event.
+ */
+class PromiseSignalDispatcher extends ste_core_1.PromiseDispatcherBase {
+ /**
+ * Creates a new SignalDispatcher instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Dispatches the signal.
+ *
+ * @returns {IPropagationStatus} The status of the dispatch.
+ *
+ * @memberOf SignalDispatcher
+ */
+ async dispatch() {
+ const result = await this._dispatchAsPromise(false, this, arguments);
+ if (result == null) {
+ throw new ste_core_1.DispatchError("Got `null` back from dispatch.");
+ }
+ return result;
+ }
+ /**
+ * Dispatches the signal threaded.
+ */
+ dispatchAsync() {
+ this._dispatchAsPromise(true, this, arguments);
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ */
+ asEvent() {
+ return super.asEvent();
+ }
+}
+exports.PromiseSignalDispatcher = PromiseSignalDispatcher;
+
+
+/***/ }),
+
+/***/ 6070:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSignalHandlingBase = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const PromiseSignalList_1 = __webpack_require__(5974);
+/**
+ * Extends objects with signal event handling capabilities.
+ */
+class PromiseSignalHandlingBase extends ste_core_1.HandlingBase {
+ constructor() {
+ super(new PromiseSignalList_1.PromiseSignalList());
+ }
+}
+exports.PromiseSignalHandlingBase = PromiseSignalHandlingBase;
+
+
+/***/ }),
+
+/***/ 5974:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSignalList = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const _1 = __webpack_require__(8943);
+/**
+ * Storage class for multiple signal events that are accessible by name.
+ * Events dispatchers are automatically created.
+ */
+class PromiseSignalList extends ste_core_1.EventListBase {
+ /**
+ * Creates a new SignalList instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new _1.PromiseSignalDispatcher();
+ }
+}
+exports.PromiseSignalList = PromiseSignalList;
+
+
+/***/ }),
+
+/***/ 8943:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+/*!
+ * Strongly Typed Events for TypeScript - Promise Signals
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSignalList = exports.PromiseSignalHandlingBase = exports.PromiseSignalDispatcher = void 0;
+const PromiseSignalDispatcher_1 = __webpack_require__(8435);
+Object.defineProperty(exports, "PromiseSignalDispatcher", ({ enumerable: true, get: function () { return PromiseSignalDispatcher_1.PromiseSignalDispatcher; } }));
+const PromiseSignalHandlingBase_1 = __webpack_require__(6070);
+Object.defineProperty(exports, "PromiseSignalHandlingBase", ({ enumerable: true, get: function () { return PromiseSignalHandlingBase_1.PromiseSignalHandlingBase; } }));
+const PromiseSignalList_1 = __webpack_require__(5974);
+Object.defineProperty(exports, "PromiseSignalList", ({ enumerable: true, get: function () { return PromiseSignalList_1.PromiseSignalList; } }));
+
+
+/***/ }),
+
+/***/ 6862:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformPromiseSimpleEventList = void 0;
+const PromiseSimpleEventDispatcher_1 = __webpack_require__(9666);
+/**
+ * Similar to EventList, but instead of TArgs, a map of event names ang argument types is provided with TArgsMap.
+ */
+class NonUniformPromiseSimpleEventList {
+ constructor() {
+ this._events = {};
+ }
+ /**
+ * Gets the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ get(name) {
+ if (this._events[name]) {
+ // @TODO avoid typecasting. Not sure why TS thinks this._events[name] could still be undefined.
+ return this._events[name];
+ }
+ const event = this.createDispatcher();
+ this._events[name] = event;
+ return event;
+ }
+ /**
+ * Removes the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ remove(name) {
+ delete this._events[name];
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new PromiseSimpleEventDispatcher_1.PromiseSimpleEventDispatcher();
+ }
+}
+exports.NonUniformPromiseSimpleEventList = NonUniformPromiseSimpleEventList;
+
+
+/***/ }),
+
+/***/ 9666:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSimpleEventDispatcher = void 0;
+const ste_core_1 = __webpack_require__(4327);
+/**
+ * The dispatcher handles the storage of subsciptions and facilitates
+ * subscription, unsubscription and dispatching of a simple event
+ *
+ * @export
+ * @class PromiseSimpleEventDispatcher
+ * @extends {PromiseDispatcherBase>}
+ * @implements {IPromiseSimpleEvent}
+ * @template TArgs
+ */
+class PromiseSimpleEventDispatcher extends ste_core_1.PromiseDispatcherBase {
+ /**
+ * Creates a new SimpleEventDispatcher instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Dispatches the event.
+ * @param args The arguments object.
+ * @returns {IPropagationStatus} The status of the dispatch.
+ * @memberOf PromiseSimpleEventDispatcher
+ */
+ async dispatch(args) {
+ const result = await this._dispatchAsPromise(false, this, arguments);
+ if (result == null) {
+ throw new ste_core_1.DispatchError("Got `null` back from dispatch.");
+ }
+ return result;
+ }
+ /**
+ * Dispatches the event without waiting for it to complete.
+ * @param args The argument object.
+ * @memberOf PromiseSimpleEventDispatcher
+ */
+ dispatchAsync(args) {
+ this._dispatchAsPromise(true, this, arguments);
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ */
+ asEvent() {
+ return super.asEvent();
+ }
+}
+exports.PromiseSimpleEventDispatcher = PromiseSimpleEventDispatcher;
+
+
+/***/ }),
+
+/***/ 1743:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSimpleEventHandlingBase = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const PromiseSimpleEventList_1 = __webpack_require__(7747);
+/**
+ * Extends objects with signal event handling capabilities.
+ */
+class PromiseSimpleEventHandlingBase extends ste_core_1.HandlingBase {
+ constructor() {
+ super(new PromiseSimpleEventList_1.PromiseSimpleEventList());
+ }
+}
+exports.PromiseSimpleEventHandlingBase = PromiseSimpleEventHandlingBase;
+
+
+/***/ }),
+
+/***/ 7747:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PromiseSimpleEventList = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const PromiseSimpleEventDispatcher_1 = __webpack_require__(9666);
+/**
+ * Storage class for multiple simple events that are accessible by name.
+ * Events dispatchers are automatically created.
+ */
+class PromiseSimpleEventList extends ste_core_1.EventListBase {
+ /**
+ * Creates a new SimpleEventList instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new PromiseSimpleEventDispatcher_1.PromiseSimpleEventDispatcher();
+ }
+}
+exports.PromiseSimpleEventList = PromiseSimpleEventList;
+
+
+/***/ }),
+
+/***/ 1748:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+/*!
+ * Strongly Typed Events for TypeScript - Core
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformPromiseSimpleEventList = exports.PromiseSimpleEventList = exports.PromiseSimpleEventHandlingBase = exports.PromiseSimpleEventDispatcher = void 0;
+const NonUniformPromiseSimpleEventList_1 = __webpack_require__(6862);
+Object.defineProperty(exports, "NonUniformPromiseSimpleEventList", ({ enumerable: true, get: function () { return NonUniformPromiseSimpleEventList_1.NonUniformPromiseSimpleEventList; } }));
+const PromiseSimpleEventDispatcher_1 = __webpack_require__(9666);
+Object.defineProperty(exports, "PromiseSimpleEventDispatcher", ({ enumerable: true, get: function () { return PromiseSimpleEventDispatcher_1.PromiseSimpleEventDispatcher; } }));
+const PromiseSimpleEventHandlingBase_1 = __webpack_require__(1743);
+Object.defineProperty(exports, "PromiseSimpleEventHandlingBase", ({ enumerable: true, get: function () { return PromiseSimpleEventHandlingBase_1.PromiseSimpleEventHandlingBase; } }));
+const PromiseSimpleEventList_1 = __webpack_require__(7747);
+Object.defineProperty(exports, "PromiseSimpleEventList", ({ enumerable: true, get: function () { return PromiseSimpleEventList_1.PromiseSimpleEventList; } }));
+
+
+/***/ }),
+
+/***/ 7118:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SignalDispatcher = void 0;
+const ste_core_1 = __webpack_require__(4327);
+/**
+ * The dispatcher handles the storage of subsciptions and facilitates
+ * subscription, unsubscription and dispatching of a signal event.
+ *
+ * @export
+ * @class SignalDispatcher
+ * @extends {DispatcherBase}
+ * @implements {ISignal}
+ */
+class SignalDispatcher extends ste_core_1.DispatcherBase {
+ /**
+ * Dispatches the signal.
+ *
+ * @returns {IPropagationStatus} The status of the signal.
+ *
+ * @memberOf SignalDispatcher
+ */
+ dispatch() {
+ const result = this._dispatch(false, this, arguments);
+ if (result == null) {
+ throw new ste_core_1.DispatchError("Got `null` back from dispatch.");
+ }
+ return result;
+ }
+ /**
+ * Dispatches the signal without waiting for the result.
+ *
+ * @memberOf SignalDispatcher
+ */
+ dispatchAsync() {
+ this._dispatch(true, this, arguments);
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ *
+ * @returns {ISignal} The signal.
+ *
+ * @memberOf SignalDispatcher
+ */
+ asEvent() {
+ return super.asEvent();
+ }
+}
+exports.SignalDispatcher = SignalDispatcher;
+
+
+/***/ }),
+
+/***/ 8643:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SignalHandlingBase = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const _1 = __webpack_require__(4215);
+/**
+ * Extends objects with signal event handling capabilities.
+ *
+ * @export
+ * @abstract
+ * @class SignalHandlingBase
+ * @extends {HandlingBase}
+ * @implements {ISignalHandling}
+ */
+class SignalHandlingBase extends ste_core_1.HandlingBase {
+ /**
+ * Creates an instance of SignalHandlingBase.
+ *
+ * @memberOf SignalHandlingBase
+ */
+ constructor() {
+ super(new _1.SignalList());
+ }
+}
+exports.SignalHandlingBase = SignalHandlingBase;
+
+
+/***/ }),
+
+/***/ 2679:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SignalList = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const _1 = __webpack_require__(4215);
+/**
+ * Storage class for multiple signal events that are accessible by name.
+ * Events dispatchers are automatically created.
+ *
+ * @export
+ * @class SignalList
+ * @extends {EventListBase}
+ */
+class SignalList extends ste_core_1.EventListBase {
+ /**
+ * Creates an instance of SignalList.
+ *
+ * @memberOf SignalList
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Creates a new dispatcher instance.
+ *
+ * @protected
+ * @returns {SignalDispatcher}
+ *
+ * @memberOf SignalList
+ */
+ createDispatcher() {
+ return new _1.SignalDispatcher();
+ }
+}
+exports.SignalList = SignalList;
+
+
+/***/ }),
+
+/***/ 4215:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+/*!
+ * Strongly Typed Events for TypeScript - Promise Signals
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SignalList = exports.SignalHandlingBase = exports.SignalDispatcher = void 0;
+const SignalDispatcher_1 = __webpack_require__(7118);
+Object.defineProperty(exports, "SignalDispatcher", ({ enumerable: true, get: function () { return SignalDispatcher_1.SignalDispatcher; } }));
+const SignalHandlingBase_1 = __webpack_require__(8643);
+Object.defineProperty(exports, "SignalHandlingBase", ({ enumerable: true, get: function () { return SignalHandlingBase_1.SignalHandlingBase; } }));
+const SignalList_1 = __webpack_require__(2679);
+Object.defineProperty(exports, "SignalList", ({ enumerable: true, get: function () { return SignalList_1.SignalList; } }));
+
+
+/***/ }),
+
+/***/ 2821:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformSimpleEventList = void 0;
+const SimpleEventDispatcher_1 = __webpack_require__(9515);
+/**
+ * Similar to EventList, but instead of TArgs, a map of event names ang argument types is provided with TArgsMap.
+ */
+class NonUniformSimpleEventList {
+ constructor() {
+ this._events = {};
+ }
+ /**
+ * Gets the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ get(name) {
+ if (this._events[name]) {
+ // @TODO avoid typecasting. Not sure why TS thinks this._events[name] could still be undefined.
+ return this._events[name];
+ }
+ const event = this.createDispatcher();
+ this._events[name] = event;
+ return event;
+ }
+ /**
+ * Removes the dispatcher associated with the name.
+ * @param name The name of the event.
+ */
+ remove(name) {
+ delete this._events[name];
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new SimpleEventDispatcher_1.SimpleEventDispatcher();
+ }
+}
+exports.NonUniformSimpleEventList = NonUniformSimpleEventList;
+
+
+/***/ }),
+
+/***/ 9515:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SimpleEventDispatcher = void 0;
+const ste_core_1 = __webpack_require__(4327);
+/**
+ * The dispatcher handles the storage of subsciptions and facilitates
+ * subscription, unsubscription and dispatching of a simple event
+ *
+ * @export
+ * @class SimpleEventDispatcher
+ * @extends {DispatcherBase>}
+ * @implements {ISimpleEvent}
+ * @template TArgs
+ */
+class SimpleEventDispatcher extends ste_core_1.DispatcherBase {
+ /**
+ * Creates an instance of SimpleEventDispatcher.
+ *
+ * @memberOf SimpleEventDispatcher
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Dispatches the event.
+ *
+ * @param {TArgs} args The arguments object.
+ * @returns {IPropagationStatus} The status of the event.
+ *
+ * @memberOf SimpleEventDispatcher
+ */
+ dispatch(args) {
+ const result = this._dispatch(false, this, arguments);
+ if (result == null) {
+ throw new ste_core_1.DispatchError("Got `null` back from dispatch.");
+ }
+ return result;
+ }
+ /**
+ * Dispatches the event without waiting for the result.
+ *
+ * @param {TArgs} args The arguments object.
+ *
+ * @memberOf SimpleEventDispatcher
+ */
+ dispatchAsync(args) {
+ this._dispatch(true, this, arguments);
+ }
+ /**
+ * Creates an event from the dispatcher. Will return the dispatcher
+ * in a wrapper. This will prevent exposure of any dispatcher methods.
+ *
+ * @returns {ISimpleEvent} The event.
+ *
+ * @memberOf SimpleEventDispatcher
+ */
+ asEvent() {
+ return super.asEvent();
+ }
+}
+exports.SimpleEventDispatcher = SimpleEventDispatcher;
+
+
+/***/ }),
+
+/***/ 1454:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SimpleEventHandlingBase = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const SimpleEventList_1 = __webpack_require__(2542);
+/**
+ * Extends objects with signal event handling capabilities.
+ */
+class SimpleEventHandlingBase extends ste_core_1.HandlingBase {
+ constructor() {
+ super(new SimpleEventList_1.SimpleEventList());
+ }
+}
+exports.SimpleEventHandlingBase = SimpleEventHandlingBase;
+
+
+/***/ }),
+
+/***/ 2542:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.SimpleEventList = void 0;
+const ste_core_1 = __webpack_require__(4327);
+const SimpleEventDispatcher_1 = __webpack_require__(9515);
+/**
+ * Storage class for multiple simple events that are accessible by name.
+ * Events dispatchers are automatically created.
+ */
+class SimpleEventList extends ste_core_1.EventListBase {
+ /**
+ * Creates a new SimpleEventList instance.
+ */
+ constructor() {
+ super();
+ }
+ /**
+ * Creates a new dispatcher instance.
+ */
+ createDispatcher() {
+ return new SimpleEventDispatcher_1.SimpleEventDispatcher();
+ }
+}
+exports.SimpleEventList = SimpleEventList;
+
+
+/***/ }),
+
+/***/ 3852:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.NonUniformSimpleEventList = exports.SimpleEventList = exports.SimpleEventHandlingBase = exports.SimpleEventDispatcher = void 0;
+const SimpleEventDispatcher_1 = __webpack_require__(9515);
+Object.defineProperty(exports, "SimpleEventDispatcher", ({ enumerable: true, get: function () { return SimpleEventDispatcher_1.SimpleEventDispatcher; } }));
+const SimpleEventHandlingBase_1 = __webpack_require__(1454);
+Object.defineProperty(exports, "SimpleEventHandlingBase", ({ enumerable: true, get: function () { return SimpleEventHandlingBase_1.SimpleEventHandlingBase; } }));
+const NonUniformSimpleEventList_1 = __webpack_require__(2821);
+Object.defineProperty(exports, "NonUniformSimpleEventList", ({ enumerable: true, get: function () { return NonUniformSimpleEventList_1.NonUniformSimpleEventList; } }));
+const SimpleEventList_1 = __webpack_require__(2542);
+Object.defineProperty(exports, "SimpleEventList", ({ enumerable: true, get: function () { return SimpleEventList_1.SimpleEventList; } }));
+
+
+/***/ }),
+
+/***/ 4386:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+var __webpack_unused_export__;
+
+/*!
+ * Strongly Typed Events for TypeScript
+ * https://github.com/KeesCBakker/StronlyTypedEvents/
+ * http://keestalkstech.com
+ *
+ * Copyright Kees C. Bakker / KeesTalksTech
+ * Released under the MIT license
+ */
+__webpack_unused_export__ = ({ value: true });
+__webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = exports.UD = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = exports.IL = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = void 0;
+var ste_core_1 = __webpack_require__(4327);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.Subscription; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.DispatcherBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.DispatcherWrapper; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.EventListBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.EventManagement; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.DispatchError; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.PromiseSubscription; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.PromiseDispatcherBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_core_1.HandlingBase; } });
+var ste_events_1 = __webpack_require__(1717);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_events_1.EventDispatcher; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_events_1.EventHandlingBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_events_1.EventList; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_events_1.NonUniformEventList; } });
+var ste_simple_events_1 = __webpack_require__(3852);
+Object.defineProperty(exports, "IL", ({ enumerable: true, get: function () { return ste_simple_events_1.SimpleEventDispatcher; } }));
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_simple_events_1.SimpleEventHandlingBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_simple_events_1.SimpleEventList; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_simple_events_1.NonUniformSimpleEventList; } });
+var ste_signals_1 = __webpack_require__(4215);
+Object.defineProperty(exports, "UD", ({ enumerable: true, get: function () { return ste_signals_1.SignalDispatcher; } }));
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_signals_1.SignalHandlingBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_signals_1.SignalList; } });
+var ste_promise_events_1 = __webpack_require__(8669);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_events_1.PromiseEventDispatcher; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_events_1.PromiseEventHandlingBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_events_1.PromiseEventList; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_events_1.NonUniformPromiseEventList; } });
+var ste_promise_signals_1 = __webpack_require__(8943);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_signals_1.PromiseSignalDispatcher; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_signals_1.PromiseSignalHandlingBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_signals_1.PromiseSignalList; } });
+var ste_promise_simple_events_1 = __webpack_require__(1748);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_simple_events_1.PromiseSimpleEventDispatcher; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_simple_events_1.PromiseSimpleEventHandlingBase; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_simple_events_1.PromiseSimpleEventList; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return ste_promise_simple_events_1.NonUniformPromiseSimpleEventList; } });
+
+
+/***/ }),
+
+/***/ 1234:
+/***/ (() => {
+
+/* (ignored) */
+
+/***/ }),
+
+/***/ 9011:
+/***/ (() => {
+
+/* (ignored) */
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ id: moduleId,
+/******/ loaded: false,
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/amd define */
+/******/ (() => {
+/******/ __webpack_require__.amdD = function () {
+/******/ throw new Error('define cannot be used indirect');
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/amd options */
+/******/ (() => {
+/******/ __webpack_require__.amdO = {};
+/******/ })();
+/******/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/node module decorator */
+/******/ (() => {
+/******/ __webpack_require__.nmd = (module) => {
+/******/ module.paths = [];
+/******/ if (!module.children) module.children = [];
+/******/ return module;
+/******/ };
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be in strict mode.
+(() => {
+"use strict";
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/deprecated.js
+// A way to gracefully handle deprecation.
+// Find and replace HTML Elements, Classes, and more after the DOM is loaded but before any other Javascript fires.
+
+class Deprecated {
+ constructor() {
+ let deprecated;
+ let replacement;
+ // Checks for body-side class
+ deprecated = document.querySelector(".body-side");
+ if (deprecated) {
+ this.warning(deprecated);
+ }
+ // Checks for backgroundImage class
+ deprecated = document.querySelector(".backgroundImage");
+ if (deprecated) {
+ replacement = "background-image";
+ this.replace(deprecated, replacement);
+ }
+ // Checks for backgroundImageOverlay class
+ deprecated = document.querySelector(".backgroundImageOverlay");
+ if (deprecated) {
+ replacement = "background-image-overlay";
+ this.replace(deprecated, replacement);
+ }
+ }
+ warning(deprecated) {
+ if (ENGrid.debug)
+ console.log("Deprecated: '" + deprecated + "' was detected and nothing was done.");
+ }
+ replace(deprecated, replacement) {
+ if (ENGrid.debug)
+ console.log("Deprecated: '" +
+ deprecated +
+ "' was detected and replaced with '" +
+ replacement +
+ "'.");
+ deprecated.classList.add(replacement);
+ deprecated.classList.remove(deprecated);
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/options.js
+const OptionsDefaults = {
+ backgroundImage: "",
+ MediaAttribution: true,
+ applePay: false,
+ CapitalizeFields: false,
+ ClickToExpand: true,
+ CurrencySymbol: "$",
+ CurrencyCode: "USD",
+ AddCurrencySymbol: true,
+ ThousandsSeparator: "",
+ DecimalSeparator: ".",
+ DecimalPlaces: 2,
+ MinAmount: 1,
+ MaxAmount: 100000,
+ MinAmountMessage: "Amount must be at least $1",
+ MaxAmountMessage: "Amount must be less than $100,000",
+ UseAmountValidatorFromEN: false,
+ SkipToMainContentLink: true,
+ SrcDefer: true,
+ SuppressPurchaseEcard: false,
+ NeverBounceAPI: null,
+ NeverBounceDateField: null,
+ NeverBounceStatusField: null,
+ NeverBounceDateFormat: "MM/DD/YYYY",
+ NeverBounceTimeout: 10000,
+ FreshAddress: false,
+ ProgressBar: false,
+ AutoYear: false,
+ TranslateFields: true,
+ Debug: false,
+ RememberMe: false,
+ TidyContact: false,
+ RegionLongFormat: "",
+ CountryDisable: [],
+ Placeholders: false,
+ ENValidators: false,
+ MobileCTA: false,
+ CustomCurrency: false,
+ CustomPremium: false,
+ VGS: false,
+ PostalCodeValidator: false,
+ CountryRedirect: false,
+ WelcomeBack: false,
+ OptInLadder: false,
+ StickyNSG: false,
+ StickyPrepopulation: false,
+ PreferredPaymentMethod: false,
+ PageLayouts: [
+ "leftleft1col",
+ "centerleft1col",
+ "centercenter1col",
+ "centercenter2col",
+ "centerright1col",
+ "rightright1col",
+ "none",
+ ],
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/upsell-options.js
+const UpsellOptionsDefaults = {
+ image: "https://picsum.photos/480/650",
+ imagePosition: "left",
+ title: "Will you change your gift to just {new-amount} a month to boost your impact?",
+ paragraph: "Make a monthly pledge today to support us with consistent, reliable resources during emergency moments.",
+ yesLabel: "Yes! Process My {new-amount} monthly gift",
+ noLabel: "No, thanks. Continue with my {old-amount} one-time gift",
+ otherAmount: true,
+ otherLabel: "Or enter a different monthly amount:",
+ upsellOriginalGiftAmountFieldName: "",
+ amountRange: [
+ { max: 10, suggestion: 5 },
+ { max: 15, suggestion: 7 },
+ { max: 20, suggestion: 8 },
+ { max: 25, suggestion: 9 },
+ { max: 30, suggestion: 10 },
+ { max: 35, suggestion: 11 },
+ { max: 40, suggestion: 12 },
+ { max: 50, suggestion: 14 },
+ { max: 100, suggestion: 15 },
+ { max: 200, suggestion: 19 },
+ { max: 300, suggestion: 29 },
+ { max: 500, suggestion: "Math.ceil((amount / 12)/5)*5" },
+ ],
+ minAmount: 0,
+ canClose: true,
+ submitOnClose: false,
+ oneTime: true,
+ annual: false,
+ disablePaymentMethods: [],
+ skipUpsell: false,
+ conversionField: "",
+ upsellCheckbox: false,
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/translate-options.js
+const ptbrTranslation = [
+ { field: "supporter.firstName", translation: "Nome" },
+ { field: "supporter.lastName", translation: "Sobrenome" },
+ { field: "supporter.phoneNumber", translation: "Celular" },
+ { field: "supporter.address1", translation: "EndereΓ§o" },
+ { field: "supporter.address2", translation: "Complemento" },
+ { field: "supporter.postcode", translation: "CEP" },
+ { field: "supporter.city", translation: "Cidade" },
+ { field: "supporter.region", translation: "Estado" },
+ { field: "supporter.country", translation: "PaΓs" },
+];
+const deTranslation = [
+ { field: "supporter.address1", translation: "StraΓe, Hausnummer" },
+ { field: "supporter.postcode", translation: "Postleitzahl" },
+ { field: "supporter.city", translation: "Ort" },
+ { field: "supporter.region", translation: "Bundesland" },
+ { field: "supporter.country", translation: "Land" },
+];
+const frTranslation = [
+ { field: "supporter.address1", translation: "Adresse" },
+ { field: "supporter.postcode", translation: "Code Postal" },
+ { field: "supporter.city", translation: "Ville" },
+ { field: "supporter.region", translation: "RΓ©gion" },
+ { field: "supporter.country", translation: "Country" },
+];
+const nlTranslation = [
+ { field: "supporter.address1", translation: "Adres" },
+ { field: "supporter.postcode", translation: "Postcode" },
+ { field: "supporter.city", translation: "Woonplaats" },
+ { field: "supporter.region", translation: "Provincie" },
+ { field: "supporter.country", translation: "Country" },
+];
+const TranslateOptionsDefaults = {
+ BR: ptbrTranslation,
+ BRA: ptbrTranslation,
+ DE: deTranslation,
+ DEU: deTranslation,
+ FR: frTranslation,
+ FRA: frTranslation,
+ NL: nlTranslation,
+ NLD: nlTranslation,
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/exit-intent-options.js
+const ExitIntentOptionsDefaults = {
+ enabled: false,
+ title: "We are sad that you are leaving",
+ text: "Would you mind telling us why you are leaving this page?",
+ buttonText: "Send us your comments",
+ buttonLink: "https://www.4sitestudios.com/",
+ cookieName: "engrid-exit-intent-lightbox",
+ cookieDuration: 30,
+ triggers: {
+ visibilityState: true,
+ mousePosition: true,
+ },
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/frequency-upsell-options.js
+const FrequencyUpsellOptionsDefaults = {
+ title: "Before we process your donation...",
+ paragraph: "Would you like to make it an annual gift?",
+ yesButton: "YES! Process my gift as an annual gift of ${upsell_amount}",
+ noButton: "NO! Process my gift as a one-time gift of ${current_amount}",
+ upsellFrequency: "annual",
+ upsellFromFrequency: ["onetime"],
+ customClass: "",
+ upsellAmount: (currentAmount) => currentAmount,
+ onOpen: () => { },
+ onAccept: () => { },
+ onDecline: () => { },
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/iframe-queue-options.js
+/**
+ * Configuration interfaces for the Iframe Queue component.
+ *
+ * The Iframe Queue loads a sequence of embedded Engaging Networks pages
+ * one at a time, passes field values into them via `postMessage`, and
+ * exposes a global `IframeQueueEvents` instance so external code can
+ * subscribe to chain-completion. See iframe-queue.ts for the component.
+ *
+ * Configuration may be supplied either programmatically (via
+ * `IframeQueue.getInstance().enqueue(...).process()`) or declaratively
+ * by setting `window.EngridIframeQueue` on the host EN page before
+ * the ENgrid bundle loads.
+ */
+const iframe_queue_options_IframeQueueOptionsDefaults = {
+ items: [],
+ autoStart: true,
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/loader.js
+// Ref: https://app.getguru.com/card/iMgx968T/ENgrid-Loader
+
+class Loader {
+ constructor() {
+ this.logger = new logger_EngridLogger("Loader", "gold", "black", "π");
+ this.cssElement = document.querySelector('link[href*="engrid."][rel="stylesheet"]');
+ this.jsElement = document.querySelector('script[src*="engrid."]');
+ }
+ // Returns true if ENgrid should reload (that means the current ENgrid is not the right one)
+ // Returns false if ENgrid should not reload (that means the current ENgrid is the right one)
+ reload() {
+ var _a, _b, _c;
+ const assets = this.getOption("assets");
+ const isLoaded = engrid_ENGrid.getBodyData("loaded");
+ let shouldSkipCss = this.getOption("engridcss") === "false";
+ let shouldSkipJs = this.getOption("engridjs") === "false";
+ if (isLoaded || !assets) {
+ if (shouldSkipCss && this.cssElement) {
+ this.logger.log("engridcss=false | Removing original stylesheet:", this.cssElement);
+ this.cssElement.remove();
+ }
+ if (shouldSkipJs && this.jsElement) {
+ this.logger.log("engridjs=false | Removing original script:", this.jsElement);
+ this.jsElement.remove();
+ }
+ if (shouldSkipCss) {
+ this.logger.log("engridcss=false | adding top banner CSS");
+ this.addENgridCSSUnloadedCSS();
+ }
+ if (shouldSkipJs) {
+ this.logger.log("engridjs=false | Skipping JS load.");
+ this.logger.success("LOADED");
+ return true;
+ }
+ this.logger.success("LOADED");
+ return false;
+ }
+ // Load the right ENgrid
+ this.logger.log("RELOADING");
+ engrid_ENGrid.setBodyData("loaded", "true"); // Set the loaded flag, so the next time we don't reload
+ // Fetch the desired repo, assets location, and override JS/CSS
+ const theme = engrid_ENGrid.getBodyData("theme");
+ const engrid_repo = (_a = this.getOption("repo-name")) !== null && _a !== void 0 ? _a : `engrid-${theme}`;
+ let engrid_js_url = "";
+ let engrid_css_url = "";
+ switch (assets) {
+ case "local":
+ this.logger.log("LOADING LOCAL");
+ engrid_ENGrid.setBodyData("assets", "local");
+ engrid_js_url = `https://${engrid_repo}.test/dist/engrid.js`;
+ engrid_css_url = `https://${engrid_repo}.test/dist/engrid.css`;
+ break;
+ case "flush":
+ this.logger.log("FLUSHING CACHE");
+ const timestamp = Date.now();
+ const jsCurrentURL = new URL(((_b = this.jsElement) === null || _b === void 0 ? void 0 : _b.getAttribute("src")) || "");
+ jsCurrentURL.searchParams.set("v", timestamp.toString());
+ engrid_js_url = jsCurrentURL.toString();
+ const cssCurrentURL = new URL(((_c = this.cssElement) === null || _c === void 0 ? void 0 : _c.getAttribute("href")) || "");
+ cssCurrentURL.searchParams.set("v", timestamp.toString());
+ engrid_css_url = cssCurrentURL.toString();
+ break;
+ default:
+ this.logger.log("LOADING EXTERNAL");
+ engrid_js_url = `https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${engrid_repo}/${assets}/engrid.js`;
+ engrid_css_url = `https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${engrid_repo}/${assets}/engrid.css`;
+ }
+ if (shouldSkipCss && this.cssElement) {
+ this.logger.log("engridcss=false | Removing original stylesheet:", this.cssElement);
+ this.cssElement.remove();
+ }
+ if (shouldSkipCss && engrid_css_url && engrid_css_url !== "") {
+ this.logger.log("engridcss=false | Skipping injection of stylesheet:", engrid_css_url);
+ }
+ if (shouldSkipCss) {
+ this.logger.log("engridcss=false | adding top banner CSS");
+ this.addENgridCSSUnloadedCSS();
+ }
+ else {
+ this.setCssFile(engrid_css_url);
+ }
+ if (shouldSkipJs && this.jsElement) {
+ this.logger.log("engridjs=false | Removing original script:", this.jsElement);
+ this.jsElement.remove();
+ }
+ if (shouldSkipJs && engrid_js_url && engrid_js_url !== "") {
+ this.logger.log("engridjs=false | Skipping injection of script:", engrid_js_url);
+ }
+ if (!shouldSkipJs) {
+ this.setJsFile(engrid_js_url);
+ }
+ // If custom assets aren't defined, we don't need to reload.
+ if (!assets) {
+ return false;
+ }
+ return true;
+ }
+ getOption(key) {
+ const urlParam = engrid_ENGrid.getUrlParameter(key);
+ if (urlParam && ["assets", "engridcss", "engridjs"].includes(key)) {
+ return urlParam;
+ }
+ else if (window.EngridLoader && window.EngridLoader.hasOwnProperty(key)) {
+ return window.EngridLoader[key];
+ }
+ else if (this.jsElement && this.jsElement.hasAttribute("data-" + key)) {
+ return this.jsElement.getAttribute("data-" + key);
+ }
+ return null;
+ }
+ setCssFile(url) {
+ if (url === "") {
+ return;
+ }
+ if (this.cssElement) {
+ this.logger.log("Replacing stylesheet:", url);
+ this.cssElement.setAttribute("href", url);
+ }
+ else {
+ this.logger.log("Injecting stylesheet:", url);
+ const link = document.createElement("link");
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("type", "text/css");
+ link.setAttribute("media", "all");
+ link.setAttribute("href", url);
+ document.head.appendChild(link);
+ }
+ }
+ setJsFile(url) {
+ if (url === "") {
+ return;
+ }
+ this.logger.log("Injecting script:", url);
+ const script = document.createElement("script");
+ script.setAttribute("src", url);
+ document.head.appendChild(script);
+ }
+ addENgridCSSUnloadedCSS() {
+ document.body.insertAdjacentHTML("beforeend", ``);
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/@4site/engrid-scripts/node_modules/strongly-typed-events/dist/index.js
+var dist = __webpack_require__(3199);
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/en-form.js
+
+
+class en_form_EnForm {
+ constructor() {
+ this.logger = new logger_EngridLogger("EnForm");
+ this._onIntentSubmit = new dist/* SignalDispatcher */.UD();
+ this._onSubmit = new dist/* SignalDispatcher */.UD();
+ this._onValidate = new dist/* SignalDispatcher */.UD();
+ this._onError = new dist/* SignalDispatcher */.UD();
+ this.submit = true;
+ this.submitPromise = false;
+ this.validate = true;
+ this.validatePromise = false;
+ }
+ static getInstance() {
+ if (!en_form_EnForm.instance) {
+ en_form_EnForm.instance = new en_form_EnForm();
+ }
+ return en_form_EnForm.instance;
+ }
+ dispatchIntentSubmit() {
+ this._onIntentSubmit.dispatch();
+ this.logger.log("dispatchIntentSubmit");
+ }
+ dispatchSubmit() {
+ this._onSubmit.dispatch();
+ this.logger.log("dispatchSubmit");
+ }
+ dispatchValidate() {
+ this._onValidate.dispatch();
+ this.logger.log("dispatchValidate");
+ }
+ dispatchError() {
+ this._onError.dispatch();
+ this.logger.log("dispatchError");
+ }
+ submitForm() {
+ const enForm = document.querySelector("form .en__submit button");
+ if (enForm) {
+ // Add submitting class to modal
+ const enModal = document.getElementById("enModal");
+ if (enModal)
+ enModal.classList.add("is-submitting");
+ enForm.click();
+ this.logger.log("submitForm");
+ }
+ }
+ /**
+ * onIntentSubmit is dispatched when a submit button is clicked,
+ * or a digital wallet submission is initiated,
+ * but before server-side validation or the actual submit event.
+ * This allows you to run code at the moment the user intends to submit,
+ * such as triggering data formatting, analytics events, or other pre-submit actions.
+ * Actions that rely on fully processed form data or validation results should use the onSubmit event instead.
+ * Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
+ */
+ get onIntentSubmit() {
+ return this._onIntentSubmit.asEvent();
+ }
+ /**
+ * onSubmit is dispatched when the form is submitted, after validation has passed.
+ * This is the main event to listen to for form submissions, as it indicates that the user has successfully submitted the form and all validation checks have been passed.
+ * This event uses window.enOnSubmit, which is called by Engaging Networks' JavaScript when the form is submitted.
+ * At the time of writing, enOnSubmit does not trigger when a user submits via a digital wallet, use onIntentSubmit to listen for those submission attempts.
+ * Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
+ */
+ get onSubmit() {
+ return this._onSubmit.asEvent();
+ }
+ /**
+ * onValidate is dispatched using window.enOnValidate, which is called by Engaging Networks' JavaScript
+ * when the form is being validated, before submission. This only occurs after ENgrid's client-side validation has passed, but before server-side validation.
+ */
+ get onValidate() {
+ return this._onValidate.asEvent();
+ }
+ /**
+ * onError is dispatched using window.enOnError, which is called by Engaging Networks' JavaScript when a server-side validation error occurs on form submission.
+ * This allows you to listen for validation errors and respond accordingly, such as displaying custom error messages or triggering analytics events.
+ */
+ get onError() {
+ return this._onError.asEvent();
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/donation-amount.js
+
+
+class DonationAmount {
+ constructor(radios = "transaction.donationAmt", other = "transaction.donationAmt.other") {
+ this._onAmountChange = new dist/* SimpleEventDispatcher */.IL();
+ this._amount = 0;
+ this._radios = "";
+ this._other = "";
+ this._dispatch = true;
+ this._other = other;
+ this._radios = radios;
+ // Watch Radios Inputs for Changes
+ document.addEventListener("change", (e) => {
+ const element = e.target;
+ if (element) {
+ if (element.name == radios) {
+ this.amount = parseFloat(element.value);
+ }
+ else if (element.name == other) {
+ const cleanedAmount = engrid_ENGrid.cleanAmount(element.value);
+ element.value =
+ cleanedAmount % 1 != 0
+ ? cleanedAmount.toFixed(2)
+ : cleanedAmount.toString();
+ this.amount = cleanedAmount;
+ }
+ }
+ });
+ // Watch Other Amount Field
+ const otherField = document.querySelector(`[name='${this._other}']`);
+ if (otherField) {
+ otherField.addEventListener("keyup", (e) => {
+ this.amount = engrid_ENGrid.cleanAmount(otherField.value);
+ });
+ }
+ // Load the current amount
+ this.load();
+ }
+ static getInstance(radios = "transaction.donationAmt", other = "transaction.donationAmt.other") {
+ if (!DonationAmount.instance) {
+ DonationAmount.instance = new DonationAmount(radios, other);
+ }
+ return DonationAmount.instance;
+ }
+ get amount() {
+ return this._amount;
+ }
+ // Every time we set an amount, trigger the onAmountChange event
+ set amount(value) {
+ this._amount = value || 0;
+ if (this._dispatch)
+ this._onAmountChange.dispatch(this._amount);
+ }
+ get onAmountChange() {
+ return this._onAmountChange.asEvent();
+ }
+ // Set amount var with currently selected amount
+ load() {
+ const currentAmountField = document.querySelector('input[name="' + this._radios + '"]:checked');
+ if (currentAmountField) {
+ let currentAmountValue = parseFloat(currentAmountField.value || "");
+ if (currentAmountValue > 0) {
+ this.amount = parseFloat(currentAmountField.value);
+ }
+ else {
+ const otherField = document.querySelector('input[name="' + this._other + '"]');
+ currentAmountValue = engrid_ENGrid.cleanAmount(otherField.value);
+ this.amount = currentAmountValue;
+ }
+ }
+ else if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationTotal") &&
+ engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationFee")) {
+ const total = window.EngagingNetworks.require._defined.enjs.getDonationTotal() -
+ window.EngagingNetworks.require._defined.enjs.getDonationFee();
+ if (total) {
+ this.amount = total;
+ }
+ }
+ }
+ // Force a new amount
+ setAmount(amount, dispatch = true) {
+ // Run only if it is a Donation Page with a Donation Amount field
+ if (!document.getElementsByName(this._radios).length) {
+ return;
+ }
+ // Set dispatch to be checked by the SET method
+ this._dispatch = dispatch;
+ // Search for the current amount on radio boxes
+ let found = Array.from(document.querySelectorAll('input[name="' + this._radios + '"]')).filter((el) => el instanceof HTMLInputElement && parseInt(el.value) == amount);
+ // We found the amount on the radio boxes, so check it
+ if (found.length) {
+ const amountField = found[0];
+ amountField.checked = true;
+ // Change Event
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true,
+ });
+ amountField.dispatchEvent(event);
+ // Clear OTHER text field
+ this.clearOther();
+ }
+ else {
+ const otherField = document.querySelector('input[name="' + this._other + '"]');
+ if (otherField) {
+ const enFieldOtherAmountRadio = document.querySelector(`.en__field--donationAmt.en__field--withOther .en__field__item:nth-last-child(2) input[name="${this._radios}"]`);
+ if (enFieldOtherAmountRadio) {
+ enFieldOtherAmountRadio.checked = true;
+ }
+ otherField.value = parseFloat(amount.toString()).toFixed(2);
+ // Change Event
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true,
+ });
+ otherField.dispatchEvent(event);
+ const otherWrapper = otherField.parentNode;
+ otherWrapper.classList.remove("en__field__item--hidden");
+ }
+ }
+ // Set the new amount and trigger all live variables
+ this.amount = amount;
+ // Revert dispatch to default value (true)
+ this._dispatch = true;
+ }
+ // Clear Other Field
+ clearOther() {
+ const otherField = document.querySelector('input[name="' + this._other + '"]');
+ otherField.value = "";
+ const otherWrapper = otherField.parentNode;
+ otherWrapper.classList.add("en__field__item--hidden");
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/engrid.js
+class engrid_ENGrid {
+ constructor() {
+ if (!engrid_ENGrid.enForm) {
+ throw new Error("Engaging Networks Form Not Found!");
+ }
+ }
+ static get enForm() {
+ return document.querySelector("form.en__component");
+ }
+ static get debug() {
+ return !!this.getOption("Debug");
+ }
+ static get demo() {
+ return this.getUrlParameter("mode") === "DEMO";
+ }
+ // Return any parameter from the URL
+ static getUrlParameter(name) {
+ const searchParams = new URLSearchParams(window.location.search);
+ // Add support for array on the name ending with []
+ if (name.endsWith("[]")) {
+ let values = [];
+ searchParams.forEach((value, key) => {
+ if (key.startsWith(name.replace("[]", ""))) {
+ values.push(new Object({ [key]: value }));
+ }
+ });
+ return values.length > 0 ? values : null;
+ }
+ if (searchParams.has(name)) {
+ return searchParams.get(name) || true;
+ }
+ return null;
+ }
+ static getField(name) {
+ // Get the field by name
+ return document.querySelector(`[name="${name}"]`);
+ }
+ // Return the field value from its name. It works on any field type.
+ // Multiple values (from checkboxes or multi-select) are returned as single string
+ // Separated by ,
+ static getFieldValue(name) {
+ return new FormData(this.enForm).getAll(name).join(",");
+ }
+ // Set a value to any field. If it's a dropdown, radio or checkbox, it selects the proper option matching the value
+ static setFieldValue(name, value, parseENDependencies = true, dispatchEvents = false) {
+ if (value === engrid_ENGrid.getFieldValue(name))
+ return;
+ document.getElementsByName(name).forEach((field) => {
+ if ("type" in field) {
+ switch (field.type) {
+ case "select-one":
+ case "select-multiple":
+ for (const option of field.options) {
+ if (option.value == value) {
+ option.selected = true;
+ if (dispatchEvents) {
+ field.dispatchEvent(new Event("change", { bubbles: true }));
+ }
+ }
+ }
+ break;
+ case "checkbox":
+ case "radio":
+ if (field.value == value) {
+ field.checked = true;
+ if (dispatchEvents) {
+ field.dispatchEvent(new Event("change", { bubbles: true }));
+ }
+ }
+ break;
+ case "textarea":
+ case "text":
+ default:
+ field.value = value;
+ if (dispatchEvents) {
+ field.dispatchEvent(new Event("change", { bubbles: true }));
+ field.dispatchEvent(new Event("blur", { bubbles: true }));
+ }
+ }
+ field.setAttribute("engrid-value-changed", "");
+ }
+ });
+ if (parseENDependencies)
+ this.enParseDependencies();
+ return;
+ }
+ // Create a hidden input field
+ static createHiddenInput(name, value = "") {
+ var _a;
+ const formBlock = document.createElement("div");
+ formBlock.classList.add("en__component", "en__component--formblock", "hide");
+ const textField = document.createElement("div");
+ textField.classList.add("en__field", "en__field--text");
+ const textElement = document.createElement("div");
+ textElement.classList.add("en__field__element", "en__field__element--text");
+ const inputField = document.createElement("input");
+ inputField.classList.add("en__field__input", "en__field__input--text", "engrid-added-input");
+ inputField.setAttribute("name", name);
+ inputField.setAttribute("type", "hidden");
+ inputField.setAttribute("value", value);
+ textElement.appendChild(inputField);
+ textField.appendChild(textElement);
+ formBlock.appendChild(textField);
+ const submitElement = document.querySelector(".en__submit");
+ if (submitElement) {
+ const lastFormComponent = submitElement.closest(".en__component");
+ if (lastFormComponent) {
+ // Insert the new field after the submit button
+ (_a = lastFormComponent.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(formBlock, lastFormComponent.nextSibling);
+ }
+ }
+ else {
+ engrid_ENGrid.enForm.appendChild(formBlock);
+ }
+ return inputField;
+ }
+ // Trigger EN Dependencies
+ static enParseDependencies() {
+ var _a, _b, _c, _d, _e, _f;
+ if (window.EngagingNetworks &&
+ typeof ((_e = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enDependencies) === null || _d === void 0 ? void 0 : _d.dependencies) === null || _e === void 0 ? void 0 : _e.parseDependencies) === "function") {
+ const customDependencies = [];
+ if ("dependencies" in window.EngagingNetworks) {
+ const amountContainer = document.querySelector(".en__field--donationAmt");
+ if (amountContainer) {
+ let amountID = ((_f = [...amountContainer.classList.values()]
+ .filter((v) => v.startsWith("en__field--") && Number(v.substring(11)) > 0)
+ .toString()
+ .match(/\d/g)) === null || _f === void 0 ? void 0 : _f.join("")) || "";
+ if (amountID) {
+ window.EngagingNetworks.dependencies.forEach((dependency) => {
+ if ("actions" in dependency && dependency.actions.length > 0) {
+ let amountIdFound = false;
+ dependency.actions.forEach((action) => {
+ if ("target" in action && action.target == amountID) {
+ amountIdFound = true;
+ }
+ });
+ if (!amountIdFound) {
+ customDependencies.push(dependency);
+ }
+ }
+ });
+ if (customDependencies.length > 0) {
+ window.EngagingNetworks.require._defined.enDependencies.dependencies.parseDependencies(customDependencies);
+ if (engrid_ENGrid.getOption("Debug"))
+ console.log("EN Dependencies Triggered", customDependencies);
+ }
+ }
+ }
+ }
+ }
+ }
+ // Return the status of the gift process (true if a donation has been made, otherwise false)
+ static getGiftProcess() {
+ if ("pageJson" in window)
+ return window.pageJson.giftProcess;
+ return null;
+ }
+ // Return the page count
+ static getPageCount() {
+ if ("pageJson" in window)
+ return window.pageJson.pageCount;
+ return null;
+ }
+ // Return the current page number
+ static getPageNumber() {
+ if ("pageJson" in window)
+ return window.pageJson.pageNumber;
+ return null;
+ }
+ static isThankYouPage() {
+ return this.getPageNumber() === this.getPageCount();
+ }
+ // Return the current page ID
+ static getPageID() {
+ if ("pageJson" in window)
return window.pageJson.campaignPageId;
return 0;
}
/**
- * Parse the numeric Page ID out of a Engaging Networks URL.
- * EN page URLs follow the pattern `https:///page///...`.
- * Used by the Iframe Queue component to match Thank-You-page pings from
- * embedded iframes against the queued URL that was submitted.
+ * Parse the numeric Page ID out of a Engaging Networks URL.
+ * EN page URLs follow the pattern `https:///page///...`.
+ * Used by the Iframe Queue component to match Thank-You-page pings from
+ * embedded iframes against the queued URL that was submitted.
+ *
+ * @param url Full URL string to parse.
+ * @returns The numeric Page ID, or 0 if it could not be parsed.
+ */
+ static getPageIdFromUrl(url) {
+ if (!url)
+ return 0;
+ const match = url.match(/\/page\/(\d+)(?:\/|$|\?|#)/);
+ if (!match)
+ return 0;
+ const id = parseInt(match[1], 10);
+ return Number.isFinite(id) ? id : 0;
+ }
+ // Return the client ID
+ static getClientID() {
+ if ("pageJson" in window)
+ return window.pageJson.clientId;
+ return 0;
+ }
+ //returns 'us or 'ca' based on the client ID
+ static getDataCenter() {
+ return engrid_ENGrid.getClientID() >= 10000 ? "us" : "ca";
+ }
+ // Return the current page type
+ static getPageType() {
+ if ("pageJson" in window && "pageType" in window.pageJson) {
+ switch (window.pageJson.pageType) {
+ case "p2pcheckout":
+ case "p2pdonation":
+ case "donation":
+ case "premiumgift":
+ return "DONATION";
+ break;
+ case "e-card":
+ return "ECARD";
+ break;
+ case "otherdatacapture":
+ case "survey":
+ return "SURVEY";
+ break;
+ case "emailtotarget":
+ return "EMAILTOTARGET";
+ break;
+ case "advocacypetition":
+ return "ADVOCACY";
+ break;
+ case "emailsubscribeform":
+ return "SUBSCRIBEFORM";
+ break;
+ case "event":
+ return "EVENT";
+ break;
+ case "supporterhub":
+ return "SUPPORTERHUB";
+ break;
+ case "unsubscribe":
+ return "UNSUBSCRIBE";
+ break;
+ case "tweetpage":
+ return "TWEETPAGE";
+ break;
+ default:
+ return "UNKNOWN";
+ }
+ }
+ else {
+ return "UNKNOWN";
+ }
+ }
+ // Set body engrid data attributes
+ static setBodyData(dataName, value) {
+ const body = document.querySelector("body");
+ // If value is boolean
+ if (typeof value === "boolean" && value === false) {
+ body.removeAttribute(`data-engrid-${dataName}`);
+ return;
+ }
+ body.setAttribute(`data-engrid-${dataName}`, value.toString());
+ }
+ // Get body engrid data attributes
+ static getBodyData(dataName) {
+ const body = document.querySelector("body");
+ return body.getAttribute(`data-engrid-${dataName}`);
+ }
+ // Check if body has engrid data attributes
+ static hasBodyData(dataName) {
+ const body = document.querySelector("body");
+ return body.hasAttribute(`data-engrid-${dataName}`);
+ }
+ // Return the option value
+ static getOption(key) {
+ return window.EngridOptions[key] || null;
+ }
+ // Load an external script
+ static loadJS(url, onload = null, head = true) {
+ const scriptTag = document.createElement("script");
+ scriptTag.src = url;
+ scriptTag.onload = onload;
+ if (head) {
+ document.head.appendChild(scriptTag);
+ return;
+ }
+ document.body.appendChild(scriptTag);
+ return;
+ }
+ // Format a number
+ static formatNumber(number, decimals = 2, dec_point = ".", thousands_sep = ",") {
+ // Strip all characters but numerical ones.
+ number = (number + "").replace(/[^0-9+\-Ee.]/g, "");
+ const n = !isFinite(+number) ? 0 : +number;
+ const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
+ const sep = typeof thousands_sep === "undefined" ? "," : thousands_sep;
+ const dec = typeof dec_point === "undefined" ? "." : dec_point;
+ let s = [];
+ const toFixedFix = function (n, prec) {
+ const k = Math.pow(10, prec);
+ return "" + Math.round(n * k) / k;
+ };
+ // Fix for IE parseFloat(0.55).toFixed(0) = 0;
+ s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split(".");
+ if (s[0].length > 3) {
+ s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
+ }
+ if ((s[1] || "").length < prec) {
+ s[1] = s[1] || "";
+ s[1] += new Array(prec - s[1].length + 1).join("0");
+ }
+ return s.join(dec);
+ }
+ // Clean an Amount
+ static cleanAmount(amount) {
+ // Split the number
+ const valueArray = amount.replace(/[^0-9,\.]/g, "").split(/[,.]+/);
+ const delimArray = amount.replace(/[^.,]/g, "").split("");
+ // Handle values with no decimal places and non-numeric values
+ if (valueArray.length === 1) {
+ return parseInt(valueArray[0]) || 0;
+ }
+ // Ignore invalid numbers
+ if (valueArray
+ .map((x, index) => {
+ return index > 0 && index + 1 !== valueArray.length && x.length !== 3
+ ? true
+ : false;
+ })
+ .includes(true)) {
+ return 0;
+ }
+ // Multiple commas is a bad thing? So edgy.
+ if (delimArray.length > 1 && !delimArray.includes(".")) {
+ return 0;
+ }
+ // Handle invalid decimal and comma formatting
+ if ([...new Set(delimArray.slice(0, -1))].length > 1) {
+ return 0;
+ }
+ // If there are cents
+ if (valueArray[valueArray.length - 1].length <= 2) {
+ const cents = valueArray.pop() || "00";
+ return parseInt(cents) > 0
+ ? parseFloat(Number(parseInt(valueArray.join("")) + "." + cents).toFixed(2))
+ : parseInt(valueArray.join(""));
+ }
+ return parseInt(valueArray.join(""));
+ }
+ static disableSubmit(label = "") {
+ const submit = document.querySelector(".en__submit button");
+ if (!submit)
+ return false;
+ let submitButtonProcessingHTML = `${label} `;
+ if (submit.innerHTML.includes("loader-wrapper")) {
+ // If we are already processing, don't override the originalText again
+ return false;
+ }
+ submit.dataset.originalText = submit.innerHTML;
+ submit.disabled = true;
+ submit.innerHTML = submitButtonProcessingHTML;
+ return true;
+ }
+ static enableSubmit() {
+ const submit = document.querySelector(".en__submit button");
+ if (!submit)
+ return false;
+ if (submit.dataset.originalText) {
+ submit.disabled = false;
+ submit.innerHTML = submit.dataset.originalText;
+ delete submit.dataset.originalText;
+ return true;
+ }
+ return false;
+ }
+ static formatDate(date, format = "MM/DD/YYYY") {
+ const dateAray = date
+ .toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ })
+ .split("/");
+ const dateString = format
+ .replace(/YYYY/g, dateAray[2])
+ .replace(/MM/g, dateAray[0])
+ .replace(/DD/g, dateAray[1])
+ .replace(/YY/g, dateAray[2].substr(2, 2));
+ return dateString;
+ }
+ /**
+ * Check if the provided object has ALL the provided properties
+ * Example: checkNested(EngagingNetworks, 'require', '_defined', 'enjs', 'checkSubmissionFailed')
+ * will return true if EngagingNetworks.require._defined.enjs.checkSubmissionFailed is defined
+ */
+ static checkNested(obj, ...args) {
+ for (let i = 0; i < args.length; i++) {
+ if (!obj || !obj.hasOwnProperty(args[i])) {
+ return false;
+ }
+ obj = obj[args[i]];
+ }
+ return true;
+ }
+ // Deep merge two objects
+ static deepMerge(target, source) {
+ for (const key in source) {
+ if (source[key] instanceof Object)
+ Object.assign(source[key], engrid_ENGrid.deepMerge(target[key], source[key]));
+ }
+ Object.assign(target || {}, source);
+ return target;
+ }
+ static setError(element, errorMessage) {
+ const errorElement = typeof element === "string" ? document.querySelector(element) : element;
+ if (errorElement) {
+ errorElement.classList.add("en__field--validationFailed");
+ let errorMessageElement = errorElement.querySelector(".en__field__error");
+ if (!errorMessageElement) {
+ errorMessageElement = document.createElement("div");
+ errorMessageElement.classList.add("en__field__error");
+ errorMessageElement.innerHTML = errorMessage;
+ errorElement.insertBefore(errorMessageElement, errorElement.firstChild);
+ }
+ else {
+ errorMessageElement.innerHTML = errorMessage;
+ }
+ }
+ }
+ static removeError(element) {
+ const errorElement = typeof element === "string" ? document.querySelector(element) : element;
+ if (errorElement) {
+ errorElement.classList.remove("en__field--validationFailed");
+ const errorMessageElement = errorElement.querySelector(".en__field__error");
+ if (errorMessageElement) {
+ errorElement.removeChild(errorMessageElement);
+ }
+ }
+ }
+ static isVisible(element) {
+ if (!element) {
+ return false;
+ }
+ return !!(element.offsetWidth ||
+ element.offsetHeight ||
+ element.getClientRects().length);
+ }
+ static getCurrencySymbol() {
+ const currencyField = engrid_ENGrid.getField("transaction.paycurrency");
+ if (currencyField) {
+ // Check if the selected currency field option have a data-currency-symbol attribute
+ const selectedOption = currencyField.tagName === "SELECT"
+ ? currencyField.options[currencyField.selectedIndex]
+ : currencyField;
+ if (selectedOption.dataset.currencySymbol) {
+ return selectedOption.dataset.currencySymbol;
+ }
+ const currencyArray = {
+ USD: "$",
+ EUR: "β¬",
+ GBP: "Β£",
+ AUD: "$",
+ CAD: "$",
+ JPY: "Β₯",
+ };
+ return currencyArray[currencyField.value] || "$";
+ }
+ return engrid_ENGrid.getOption("CurrencySymbol") || "$";
+ }
+ static getCurrencyCode() {
+ const currencyField = engrid_ENGrid.getField("transaction.paycurrency");
+ if (currencyField) {
+ return currencyField.value || "USD";
+ }
+ return engrid_ENGrid.getOption("CurrencyCode") || "USD";
+ }
+ static addHtml(html, target = "body", position = "before") {
+ var _a, _b;
+ const targetElement = document.querySelector(target);
+ if (typeof html === "object") {
+ html = html.outerHTML;
+ }
+ if (targetElement) {
+ const htmlElement = document.createRange().createContextualFragment(html);
+ if (position === "before") {
+ (_a = targetElement.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(htmlElement, targetElement);
+ }
+ else {
+ (_b = targetElement.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(htmlElement, targetElement.nextSibling);
+ }
+ }
+ }
+ static removeHtml(target) {
+ const targetElement = document.querySelector(target);
+ if (targetElement) {
+ targetElement.remove();
+ }
+ }
+ static slugify(text) {
+ return text
+ .toString()
+ .toLowerCase()
+ .replace(/\s+/g, "-") // Replace spaces with -
+ .replace(/[^\w\-]+/g, "") // Remove all non-word chars
+ .replace(/\-\-+/g, "-") // Replace multiple - with single -
+ .replace(/^-+/, "") // Trim - from start of text
+ .replace(/-+$/, ""); // Trim - from end of text
+ }
+ // This function is used to run a callback function when an error is displayed on the page
+ static watchForError(callback) {
+ const errorElement = document.querySelector(".en__errorList");
+ const capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
+ // Avoid duplicate callbacks
+ let callbackType = callback.toString();
+ if (callbackType.indexOf("function") === 0) {
+ callbackType = callbackType.replace("function ", "");
+ }
+ if (callbackType.indexOf("(") > 0) {
+ callbackType = callbackType.substring(0, callbackType.indexOf("("));
+ }
+ // Remove invalid characters
+ callbackType = callbackType.replace(/[^a-zA-Z0-9]/g, "");
+ // Limit to 20 characters and add prefix
+ callbackType = callbackType.substring(0, 20);
+ callbackType = "engrid" + capitalize(callbackType);
+ if (errorElement && !errorElement.dataset[callbackType]) {
+ errorElement.dataset[callbackType] = "true";
+ const observer = new MutationObserver(function (mutations) {
+ mutations.forEach(function (mutation) {
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+ callback();
+ }
+ });
+ });
+ observer.observe(errorElement, { childList: true });
+ }
+ }
+ // Get the Payment Type
+ static getPaymentType() {
+ return engrid_ENGrid.getFieldValue("transaction.paymenttype");
+ }
+ // Set the Payment Type
+ static setPaymentType(paymentType) {
+ const enFieldPaymentType = engrid_ENGrid.getField("transaction.paymenttype");
+ if (enFieldPaymentType) {
+ const paymentTypeOption = Array.from(enFieldPaymentType.options).find((option) => paymentType.toLowerCase() === "card"
+ ? ["card", "visa", "vi"].includes(option.value.toLowerCase())
+ : paymentType.toLowerCase() === option.value.toLowerCase());
+ if (paymentTypeOption) {
+ paymentTypeOption.selected = true;
+ enFieldPaymentType.value = paymentTypeOption.value;
+ }
+ else {
+ enFieldPaymentType.value = paymentType;
+ }
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true,
+ });
+ enFieldPaymentType.dispatchEvent(event);
+ }
+ }
+ static isInViewport(element) {
+ const rect = element.getBoundingClientRect();
+ return (rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <=
+ (window.innerHeight ||
+ document.documentElement.clientHeight) /* or $(window).height() */ &&
+ rect.right <=
+ (window.innerWidth ||
+ document.documentElement.clientWidth) /* or $(window).width() */);
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/donation-frequency.js
+
+
+class DonationFrequency {
+ constructor() {
+ this._onFrequencyChange = new dist/* SimpleEventDispatcher */.IL();
+ this._frequency = "onetime";
+ this._recurring = "n";
+ this._dispatch = true;
+ // Watch the Radios for Changes
+ document.addEventListener("change", (e) => {
+ const element = e.target;
+ if (element && element.name == "transaction.recurrpay") {
+ this.recurring = element.value;
+ // When this element is a radio, that means you're between onetime and monthly only
+ if (element.type == "radio") {
+ this.frequency =
+ element.value.toLowerCase() == "n" ? "onetime" : "monthly";
+ // This field is hidden when transaction.recurrpay is radio
+ engrid_ENGrid.setFieldValue("transaction.recurrfreq", this.frequency.toUpperCase());
+ }
+ }
+ if (element && element.name == "transaction.recurrfreq") {
+ this.frequency = element.value;
+ }
+ });
+ //Thank you page handling for utility classes
+ if (engrid_ENGrid.getGiftProcess()) {
+ engrid_ENGrid.setBodyData("transaction-recurring-frequency", sessionStorage.getItem("engrid-transaction-recurring-frequency") ||
+ "onetime");
+ engrid_ENGrid.setBodyData("transaction-recurring", window.pageJson.recurring ? "y" : "n");
+ }
+ }
+ static getInstance() {
+ if (!DonationFrequency.instance) {
+ DonationFrequency.instance = new DonationFrequency();
+ }
+ return DonationFrequency.instance;
+ }
+ get frequency() {
+ return this._frequency;
+ }
+ // Every time we set a frequency, trigger the onFrequencyChange event
+ set frequency(value) {
+ this._frequency = value.toLowerCase() || "onetime";
+ if (this._dispatch)
+ this._onFrequencyChange.dispatch(this._frequency);
+ engrid_ENGrid.setBodyData("transaction-recurring-frequency", this._frequency);
+ sessionStorage.setItem("engrid-transaction-recurring-frequency", this._frequency);
+ }
+ get recurring() {
+ return this._recurring;
+ }
+ set recurring(value) {
+ this._recurring = value.toLowerCase() || "n";
+ engrid_ENGrid.setBodyData("transaction-recurring", this._recurring);
+ }
+ get onFrequencyChange() {
+ return this._onFrequencyChange.asEvent();
+ }
+ // Set amount var with currently selected amount
+ load() {
+ var _a;
+ this.frequency =
+ engrid_ENGrid.getFieldValue("transaction.recurrfreq") ||
+ sessionStorage.getItem("engrid-transaction-recurring-frequency") ||
+ "onetime";
+ const recurrField = engrid_ENGrid.getField("transaction.recurrpay");
+ if (recurrField) {
+ this.recurring = engrid_ENGrid.getFieldValue("transaction.recurrpay");
+ }
+ else if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getSupporterData")) {
+ this.recurring =
+ ((_a = window.EngagingNetworks.require._defined.enjs
+ .getSupporterData("recurrpay")) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "n";
+ }
+ // ENGrid.enParseDependencies();
+ }
+ // Force a new recurrency
+ setRecurrency(recurr, dispatch = true) {
+ // Run only if it is a Donation Page with a Recurrency
+ if (!document.getElementsByName("transaction.recurrpay").length) {
+ return;
+ }
+ // Set dispatch to be checked by the SET method
+ this._dispatch = dispatch;
+ engrid_ENGrid.setFieldValue("transaction.recurrpay", recurr.toUpperCase());
+ // Revert dispatch to default value (true)
+ this._dispatch = true;
+ }
+ // Force a new frequency
+ setFrequency(freq, dispatch = true) {
+ // Run only if it is a Donation Page with a Frequency
+ if (!document.getElementsByName("transaction.recurrfreq").length) {
+ return;
+ }
+ // Set dispatch to be checked by the SET method
+ this._dispatch = dispatch;
+ // Search for the current amount on radio boxes
+ let found = Array.from(document.querySelectorAll('input[name="transaction.recurrfreq"]')).filter((el) => el instanceof HTMLInputElement && el.value == freq.toUpperCase());
+ // We found the amount on the radio boxes, so check it
+ if (found.length) {
+ const freqField = found[0];
+ freqField.checked = true;
+ this.frequency = freq.toLowerCase();
+ if (this.frequency === "onetime") {
+ this.setRecurrency("N", dispatch);
+ }
+ else {
+ this.setRecurrency("Y", dispatch);
+ }
+ }
+ // Revert dispatch to default value (true)
+ this._dispatch = true;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/processing-fees.js
+
+
+
+class ProcessingFees {
+ constructor() {
+ this._onFeeChange = new dist/* SimpleEventDispatcher */.IL();
+ this._amount = DonationAmount.getInstance();
+ this._form = en_form_EnForm.getInstance();
+ this._fee = 0;
+ this._field = null;
+ // console.log('%c Processing Fees Constructor', 'font-size: 30px; background-color: #000; color: #FF0');
+ // Run only if it is a Donation Page with a Donation Amount field
+ if (!document.getElementsByName("transaction.donationAmt").length) {
+ return;
+ }
+ this._field = this.isENfeeCover()
+ ? document.querySelector("#en__field_transaction_feeCover")
+ : document.querySelector('input[name="supporter.processing_fees"]');
+ // Watch the Radios for Changes
+ if (this._field instanceof HTMLInputElement) {
+ // console.log('%c Processing Fees Start', 'font-size: 30px; background-color: #000; color: #FF0');
+ this._field.addEventListener("change", (e) => {
+ if (this._field instanceof HTMLInputElement &&
+ this._field.checked &&
+ !this._subscribe) {
+ this._subscribe = this._form.onSubmit.subscribe(() => this.addFees());
+ }
+ this._onFeeChange.dispatch(this.fee);
+ // // console.log('%c Processing Fees Script Applied', 'font-size: 30px; background-color: #000; color: #FF0');
+ });
+ }
+ // this._amount = amount;
+ }
+ static getInstance() {
+ if (!ProcessingFees.instance) {
+ ProcessingFees.instance = new ProcessingFees();
+ }
+ return ProcessingFees.instance;
+ }
+ get onFeeChange() {
+ return this._onFeeChange.asEvent();
+ }
+ get fee() {
+ return this.calculateFees();
+ }
+ // Every time we set a frequency, trigger the onFrequencyChange event
+ set fee(value) {
+ this._fee = value;
+ this._onFeeChange.dispatch(this._fee);
+ }
+ calculateFees(amount = 0) {
+ var _a;
+ if (this._field instanceof HTMLInputElement && this._field.checked) {
+ if (this.isENfeeCover()) {
+ return amount > 0
+ ? window.EngagingNetworks.require._defined.enjs.feeCover.fee(amount)
+ : window.EngagingNetworks.require._defined.enjs.getDonationFee();
+ }
+ const fees = Object.assign({
+ processingfeepercentadded: "0",
+ processingfeefixedamountadded: "0",
+ }, (_a = this._field) === null || _a === void 0 ? void 0 : _a.dataset);
+ const amountToFee = amount > 0 ? amount : this._amount.amount;
+ const processing_fee = (parseFloat(fees.processingfeepercentadded) / 100) * amountToFee +
+ parseFloat(fees.processingfeefixedamountadded);
+ return Math.round(processing_fee * 100) / 100;
+ }
+ return 0;
+ }
+ // Add Fees to Amount
+ addFees() {
+ if (this._form.submit && !this.isENfeeCover()) {
+ this._amount.setAmount(this._amount.amount + this.fee, false);
+ }
+ }
+ // Remove Fees From Amount
+ removeFees() {
+ if (!this.isENfeeCover())
+ this._amount.setAmount(this._amount.amount - this.fee);
+ }
+ // Check if this is a Processing Fee from EN
+ isENfeeCover() {
+ if ("feeCover" in window.EngagingNetworks) {
+ for (const key in window.EngagingNetworks.feeCover) {
+ if (window.EngagingNetworks.feeCover.hasOwnProperty(key)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/remember-me-events.js
+/**
+ * This class is responsible for managing events related to the "Remember Me" functionality.
+ * It uses the Singleton design pattern to ensure only one instance of this class exists.
+ * It provides methods for dispatching load and clear events, and getters for accessing these events.
+ */
+
+
+class RememberMeEvents {
+ constructor() {
+ this.logger = new logger_EngridLogger("RememberMeEvents");
+ this._onLoad = new dist/* SimpleEventDispatcher */.IL();
+ this._onClear = new dist/* SignalDispatcher */.UD();
+ this.hasData = false;
+ }
+ static getInstance() {
+ if (!RememberMeEvents.instance) {
+ RememberMeEvents.instance = new RememberMeEvents();
+ }
+ return RememberMeEvents.instance;
+ }
+ dispatchLoad(hasData) {
+ this.hasData = hasData;
+ this._onLoad.dispatch(hasData);
+ this.logger.log(`dispatchLoad: ${hasData}`);
+ }
+ dispatchClear() {
+ this._onClear.dispatch();
+ this.logger.log("dispatchClear");
+ }
+ get onLoad() {
+ return this._onLoad.asEvent();
+ }
+ get onClear() {
+ return this._onClear.asEvent();
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/iframe-queue-events.js
+/**
+ * Singleton event hub for the Iframe Queue component.
+ *
+ * Mirrors the structure of RememberMeEvents: private constructor,
+ * static `getInstance()`, internal dispatchers exposed via `.asEvent()`
+ * getters, and `dispatch*` methods called by the IframeQueue class.
+ *
+ * External code subscribes to these events to react to queue
+ * lifecycle without holding a reference to the IframeQueue itself.
+ * The TNC Bequest Lightbox, for example, will subscribe to
+ * `onChainComplete` so it only opens after the QCB opt-in chain has
+ * finished submitting.
+ *
+ * @example
+ * IframeQueueEvents.getInstance().onChainComplete.subscribe(() => {
+ * openBequestLightbox();
+ * });
+ */
+
+
+class iframe_queue_events_IframeQueueEvents {
+ constructor() {
+ this.logger = new logger_EngridLogger("IframeQueueEvents");
+ this._onChainComplete = new dist/* SignalDispatcher */.UD();
+ this._onChainError = new dist/* SimpleEventDispatcher */.IL();
+ this._onItemStart = new dist/* SimpleEventDispatcher */.IL();
+ this._onItemComplete = new dist/* SimpleEventDispatcher */.IL();
+ this._onItemError = new dist/* SimpleEventDispatcher */.IL();
+ }
+ /** Returns the shared IframeQueueEvents singleton. */
+ static getInstance() {
+ if (!iframe_queue_events_IframeQueueEvents.instance) {
+ iframe_queue_events_IframeQueueEvents.instance = new iframe_queue_events_IframeQueueEvents();
+ }
+ return iframe_queue_events_IframeQueueEvents.instance;
+ }
+ /**
+ * Fires once when the entire queue completes successfully.
+ * Use to trigger work that must wait for all chained iframe submits
+ * (e.g. opening a bequest lightbox after QCB opt-ins are recorded).
+ */
+ get onChainComplete() {
+ return this._onChainComplete.asEvent();
+ }
+ /**
+ * Fires when the queue aborts due to an error (timeout, iframe load
+ * error, or error message from an embedded page). Carries the failed
+ * item (if known) and the underlying error.
+ */
+ get onChainError() {
+ return this._onChainError.asEvent();
+ }
+ /** Fires immediately before an item begins processing. */
+ get onItemStart() {
+ return this._onItemStart.asEvent();
+ }
+ /** Fires when an item completes (its iframe reached its Thank You page). */
+ get onItemComplete() {
+ return this._onItemComplete.asEvent();
+ }
+ /** Fires when an item fails. The queue aborts after this event. */
+ get onItemError() {
+ return this._onItemError.asEvent();
+ }
+ /** Internal β called by IframeQueue when the queue drains successfully. */
+ dispatchChainComplete() {
+ this.logger.log("dispatchChainComplete");
+ this._onChainComplete.dispatch();
+ }
+ /** Internal β called by IframeQueue when the queue aborts on error. */
+ dispatchChainError(payload) {
+ this.logger.log(`dispatchChainError: ${payload.message}`);
+ this._onChainError.dispatch(payload);
+ }
+ /** Internal β called by IframeQueue immediately before an item starts. */
+ dispatchItemStart(item) {
+ this.logger.log(`dispatchItemStart: ${item.url}`);
+ this._onItemStart.dispatch(item);
+ }
+ /** Internal β called by IframeQueue when an item finishes successfully. */
+ dispatchItemComplete(item) {
+ this.logger.log(`dispatchItemComplete: ${item.url}`);
+ this._onItemComplete.dispatch(item);
+ }
+ /** Internal β called by IframeQueue when an item errors. */
+ dispatchItemError(item, error) {
+ this.logger.log(`dispatchItemError: ${item.url} - ${error.message}`);
+ this._onItemError.dispatch({ item, error });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/country.js
+
+
+class Country {
+ constructor() {
+ this._onCountryChange = new dist/* SimpleEventDispatcher */.IL();
+ this._country = "";
+ this._field = null;
+ // Run only if it is a Page with a Country field
+ this._field = document.getElementById("en__field_supporter_country");
+ if (!this._field) {
+ return;
+ }
+ document.addEventListener("change", (e) => {
+ const element = e.target;
+ if (element && element.name == "supporter.country") {
+ this.country = element.value;
+ }
+ });
+ // Set the country to the current value on the field
+ this.country = engrid_ENGrid.getFieldValue("supporter.country");
+ }
+ static getInstance() {
+ if (!Country.instance) {
+ Country.instance = new Country();
+ }
+ return Country.instance;
+ }
+ get countryField() {
+ return this._field;
+ }
+ get onCountryChange() {
+ return this._onCountryChange.asEvent();
+ }
+ get country() {
+ return this._country;
+ }
+ // Every time we set a country, trigger the onCountryChange event
+ set country(value) {
+ this._country = value;
+ this._onCountryChange.dispatch(this._country);
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/index.js
+
+
+
+
+
+
+
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/app.js
+
+
+class App extends engrid_ENGrid {
+ constructor(options) {
+ super();
+ // Events
+ this._form = en_form_EnForm.getInstance();
+ this._fees = ProcessingFees.getInstance();
+ this._amount = DonationAmount.getInstance("transaction.donationAmt", "transaction.donationAmt.other");
+ this._frequency = DonationFrequency.getInstance();
+ this._country = Country.getInstance();
+ this.logger = new logger_EngridLogger("App", "black", "white", "π");
+ const loader = new Loader();
+ this.options = Object.assign(Object.assign({}, OptionsDefaults), options);
+ // Add Options to window
+ window.EngridOptions = this.options;
+ this._dataLayer = DataLayer.getInstance();
+ // If there's a ?pbedit query string, redirect to the page builder to edit on EN
+ if (engrid_ENGrid.getUrlParameter("pbedit") === true ||
+ engrid_ENGrid.getUrlParameter("pbedit") === "true") {
+ window.location.href = `https://${engrid_ENGrid.getDataCenter()}.engagingnetworks.app/index.html#pages/${engrid_ENGrid.getPageID()}/edit`;
+ return;
+ }
+ if (loader.reload())
+ return;
+ // Turn Debug ON if you use local assets
+ if (engrid_ENGrid.getBodyData("assets") === "local" &&
+ engrid_ENGrid.getUrlParameter("debug") !== "false" &&
+ engrid_ENGrid.getUrlParameter("debug") !== "log") {
+ window.EngridOptions.Debug = true;
+ }
+ // Document Load
+ if (document.readyState !== "loading") {
+ this.run();
+ }
+ else {
+ document.addEventListener("DOMContentLoaded", () => {
+ this.run();
+ });
+ }
+ // Window Resize
+ window.onresize = () => {
+ this.onResize();
+ };
+ }
+ run() {
+ if (!engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs")) {
+ this.logger.danger("Engaging Networks JS Framework NOT FOUND");
+ setTimeout(() => {
+ this.run();
+ }, 100);
+ return;
+ }
+ // If there's an option object on the page, override the defaults
+ if (window.hasOwnProperty("EngridPageOptions")) {
+ this.options = Object.assign(Object.assign({}, this.options), window.EngridPageOptions);
+ // Add Options to window
+ window.EngridOptions = this.options;
+ }
+ // If there's no pageJson.pageType, add a big red warning to the console
+ if (!engrid_ENGrid.checkNested(window, "pageJson", "pageType")) {
+ window.setTimeout(() => {
+ console.log("%c βοΈ pageJson.pageType NOT FOUND - Go to the Account Settings and Expose the Transaction Details %s", "background-color: red; color: white; font-size: 22px; font-weight: bold;", "https://knowledge.engagingnetworks.net/datareports/expose-transaction-details-pagejson");
+ }, 2000);
+ }
+ if (this.options.Debug || App.getUrlParameter("debug") == "true")
+ // Enable debug if available is the first thing
+ App.setBodyData("debug", "");
+ new Advocacy();
+ new InputPlaceholders();
+ new InputHasValueAndFocus();
+ // Give By Select
+ new GiveBySelect();
+ new ShowHideRadioCheckboxes("transaction.giveBySelect", "giveBySelect-");
+ new ShowHideRadioCheckboxes("transaction.inmem", "inmem-");
+ new ShowHideRadioCheckboxes("transaction.recurrpay", "recurrpay-");
+ new ShowHideRadioCheckboxes("transaction.shipenabled", "shipenabled-");
+ // Automatically show/hide all radios
+ let radioFields = [];
+ const allRadios = document.querySelectorAll("input[type=radio]");
+ allRadios.forEach((radio) => {
+ if ("name" in radio && radioFields.includes(radio.name) === false) {
+ radioFields.push(radio.name);
+ }
+ });
+ radioFields.forEach((field) => {
+ new ShowHideRadioCheckboxes(field, "engrid__" + field.replace(/\./g, "") + "-");
+ });
+ // Automatically show/hide all checkboxes
+ const allCheckboxes = document.querySelectorAll("input[type=checkbox]");
+ allCheckboxes.forEach((checkbox) => {
+ if ("name" in checkbox) {
+ new ShowHideRadioCheckboxes(checkbox.name, "engrid__" + checkbox.name.replace(/\./g, "") + "-");
+ }
+ });
+ // Client onSubmit and onError functions
+ this._form.onIntentSubmit.subscribe(() => this.onIntentSubmit());
+ this._form.onSubmit.subscribe(() => this.onSubmit());
+ this._form.onError.subscribe(() => this.onError());
+ this._form.onValidate.subscribe(() => this.onValidate());
+ // Event Listener Examples
+ this._amount.onAmountChange.subscribe((s) => this.logger.success(`Live Amount: ${s}`));
+ this._frequency.onFrequencyChange.subscribe((s) => {
+ this.logger.success(`Live Frequency: ${s}`);
+ setTimeout(() => {
+ this._amount.load();
+ }, 150);
+ });
+ this._form.onSubmit.subscribe((s) => this.logger.success("Submit: " + JSON.stringify(s)));
+ this._form.onError.subscribe((s) => this.logger.danger("Error: " + JSON.stringify(s)));
+ this._country.onCountryChange.subscribe((s) => this.logger.success(`Country: ${s}`));
+ window.enOnSubmit = () => {
+ this._form.submit = true;
+ this._form.submitPromise = false;
+ this._form.dispatchIntentSubmit();
+ this._form.dispatchSubmit();
+ engrid_ENGrid.watchForError(engrid_ENGrid.enableSubmit);
+ if (!this._form.submit)
+ return false;
+ if (this._form.submitPromise)
+ return this._form.submitPromise;
+ this.logger.success("enOnSubmit Success");
+ // If all validation passes, we'll watch for Digital Wallets Errors, which
+ // will not reload the page (thanks EN), so we will enable the submit button if
+ // an error is programmatically thrown by the Digital Wallets
+ return true;
+ };
+ window.enOnError = () => {
+ this._form.dispatchError();
+ };
+ window.enOnValidate = () => {
+ this._form.validate = true;
+ this._form.validatePromise = false;
+ this._form.dispatchValidate();
+ if (!this._form.validate)
+ return false;
+ if (this._form.validatePromise)
+ return this._form.validatePromise;
+ this.logger.success("Validation Passed");
+ return true;
+ };
+ new DataAttributes();
+ // Country Redirect
+ new CountryRedirect();
+ // iFrame Logic
+ new iFrame();
+ // Live Variables
+ new LiveVariables(this.options);
+ // Dynamically set Recurrency Frequency
+ new setRecurrFreq();
+ // Upsell Checkbox
+ new UpsellCheckbox();
+ // Upsell Lightbox
+ new UpsellLightbox();
+ // Amount Labels
+ new AmountLabel();
+ // Engrid Data Replacement
+ new DataReplace();
+ // ENgrid Hide Script
+ new DataHide();
+ // Autosubmit script
+ new Autosubmit();
+ // Adjust display of event tickets.
+ new EventTickets();
+ // StickyNSG - Must load before SwapAmounts
+ new StickyNSG();
+ // Swap Amounts
+ new SwapAmounts();
+ // On the end of the script, after all subscribers defined, let's load the current frequency
+ // The amount will be loaded by the frequency change event
+ // This timeout is needed because when you have alternative amounts, EN is slower than Engrid
+ // about 20% of the time and we get a race condition if the client is also using the SwapAmounts feature
+ window.setTimeout(() => {
+ this._frequency.load();
+ }, 1000);
+ // Fast Form Fill
+ new FastFormFill();
+ // Currency Related Components
+ new LiveCurrency();
+ new CustomCurrency();
+ // Auto Country Select
+ new AutoCountrySelect();
+ // Add Image Attribution
+ if (this.options.MediaAttribution)
+ new MediaAttribution();
+ // Apple Pay
+ if (this.options.applePay)
+ new ApplePay();
+ // Capitalize Fields
+ if (this.options.CapitalizeFields)
+ new CapitalizeFields();
+ // Auto Year Class
+ if (this.options.AutoYear)
+ new AutoYear();
+ // Autocomplete Class
+ new Autocomplete();
+ // Ecard Class
+ new Ecard();
+ // Click To Expand
+ if (this.options.ClickToExpand)
+ new ClickToExpand();
+ if (this.options.SkipToMainContentLink)
+ new SkipToMainContentLink();
+ if (this.options.SrcDefer)
+ new SrcDefer();
+ // Progress Bar
+ if (this.options.ProgressBar)
+ new ProgressBar();
+ // RememberMe
+ try {
+ // Accessing window.localStorage will throw an exception if it isn't permitted due to security reasons
+ // For example, this happens in Firefox when cookies are disabled. If it isn't available, we shouldn't
+ // bother with enabling RememberMe
+ if (this.options.RememberMe &&
+ typeof this.options.RememberMe === "object" &&
+ window.localStorage) {
+ new RememberMe(this.options.RememberMe);
+ }
+ }
+ catch (e) { }
+ if (this.options.NeverBounceAPI)
+ new NeverBounce(this.options.NeverBounceAPI, this.options.NeverBounceDateField, this.options.NeverBounceStatusField, this.options.NeverBounceDateFormat);
+ // FreshAddress
+ if (this.options.FreshAddress)
+ new FreshAddress();
+ new ShowIfAmount();
+ new OtherAmount();
+ new MinMaxAmount();
+ new Ticker();
+ new A11y();
+ new AddNameToMessage();
+ new ExpandRegionName();
+ // Page Background
+ new PageBackground();
+ // Url Params to Form Fields
+ new UrlToForm();
+ // Required if Visible Fields
+ new RequiredIfVisible();
+ // EN Custom Validators (behind a feature flag, off by default)
+ new ENValidators();
+ //Debug hidden fields
+ if (this.options.Debug)
+ new DebugHiddenFields();
+ // TidyContact
+ if (this.options.TidyContact)
+ new TidyContact();
+ // Translate Fields
+ if (this.options.TranslateFields)
+ new TranslateFields();
+ // Country Disable
+ new CountryDisable();
+ // Premium Gift Features
+ new PremiumGift();
+ // Custom Premium filtering (frequency/amount-based visibility)
+ new CustomPremium();
+ // Supporter Hub Features
+ new SupporterHub();
+ // Digital Wallets Features
+ if (engrid_ENGrid.getPageType() === "DONATION") {
+ new DigitalWallets();
+ new PreferredPaymentMethod();
+ }
+ // Mobile CTA
+ new MobileCTA();
+ // Live Frequency
+ new LiveFrequency();
+ // Universal Opt In
+ new UniversalOptIn();
+ new StripeFinancialConnections();
+ //Exit Intent Lightbox
+ new ExitIntentLightbox();
+ new UrlParamsToBodyAttrs();
+ new SetAttr();
+ new ShowIfPresent();
+ new PostalCodeValidator();
+ // Very Good Security
+ new VGS();
+ new WelcomeBack();
+ new EcardToTarget();
+ new UsOnlyForm();
+ new ThankYouPageConditionalContent();
+ new EmbeddedEcard();
+ new CheckboxLabel();
+ new PostDonationEmbed();
+ new FrequencyUpsell();
+ new StickyPrepopulation();
+ //Debug panel
+ let showDebugPanel = this.options.Debug;
+ try {
+ // accessing storage can throw an exception if it isn't available in Firefox
+ if (!showDebugPanel &&
+ window.sessionStorage.hasOwnProperty(DebugPanel.debugSessionStorageKey)) {
+ showDebugPanel = true;
+ }
+ }
+ catch (e) { }
+ if (showDebugPanel) {
+ new DebugPanel(this.options.PageLayouts);
+ }
+ if (engrid_ENGrid.getUrlParameter("development") === "branding") {
+ new BrandingHtml().show();
+ }
+ engrid_ENGrid.setBodyData("js-loading", "finished");
+ window.EngridVersion = AppVersion;
+ this.logger.success(`VERSION: ${AppVersion}`);
+ // Window Load
+ let onLoad = typeof window.onload === "function" ? window.onload : null;
+ if (document.readyState !== "loading") {
+ this.onLoad();
+ }
+ else {
+ window.onload = (e) => {
+ this.onLoad();
+ if (onLoad) {
+ onLoad.bind(window, e);
+ }
+ };
+ }
+ }
+ onLoad() {
+ if (this.options.onLoad) {
+ this.options.onLoad();
+ }
+ }
+ onResize() {
+ if (this.options.onResize) {
+ this.options.onResize();
+ }
+ }
+ onValidate() {
+ if (this.options.onValidate) {
+ this.logger.log("Client onValidate Triggered");
+ this.options.onValidate();
+ }
+ }
+ onIntentSubmit() {
+ if (this.options.onIntentSubmit) {
+ this.logger.log("Client onIntentSubmit Triggered");
+ this.options.onIntentSubmit();
+ }
+ }
+ onSubmit() {
+ if (this.options.onSubmit) {
+ this.logger.log("Client onSubmit Triggered");
+ this.options.onSubmit();
+ }
+ }
+ onError() {
+ if (this.options.onError) {
+ this.logger.danger("Client onError Triggered");
+ this.options.onError();
+ }
+ }
+ static log(message) {
+ const logger = new logger_EngridLogger("Client", "brown", "aliceblue", "πͺ");
+ logger.log(message);
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/amount-label.js
+// This script checks if the donations amounts are numbers and if they are, appends the correct currency symbol
+
+class AmountLabel {
+ constructor() {
+ this._frequency = DonationFrequency.getInstance();
+ if (!this.shouldRun()) {
+ // If we're not on a Donation Page, get out
+ return;
+ }
+ this._frequency.onFrequencyChange.subscribe((s) => window.setTimeout(this.fixAmountLabels.bind(this), 100));
+ // Run the main function on page load so we can analyze the amounts of the current frequency
+ window.setTimeout(this.fixAmountLabels.bind(this), 300);
+ }
+ // Should we run the script?
+ shouldRun() {
+ return !!(engrid_ENGrid.getPageType() === "DONATION" &&
+ engrid_ENGrid.getOption("AddCurrencySymbol"));
+ }
+ // Fix Amount Labels
+ fixAmountLabels() {
+ let amounts = document.querySelectorAll(".en__field--donationAmt label");
+ const currencySymbol = engrid_ENGrid.getCurrencySymbol() || "";
+ amounts.forEach((element) => {
+ const amountText = element.innerText.replace(/,/g, "").replace(/\./g, "");
+ if (!isNaN(amountText)) {
+ element.innerText = currencySymbol + element.innerText;
+ }
+ });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/apple-pay.js
+var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+/*global window */
+const ApplePaySession = window.ApplePaySession;
+const merchantIdentifier = window.merchantIdentifier;
+const merchantDomainName = window.merchantDomainName;
+const merchantDisplayName = window.merchantDisplayName;
+const merchantSessionIdentifier = window.merchantSessionIdentifier;
+const merchantNonce = window.merchantNonce;
+const merchantEpochTimestamp = window.merchantEpochTimestamp;
+const merchantSignature = window.merchantSignature;
+const merchantCountryCode = window.merchantCountryCode;
+const merchantCurrencyCode = window.merchantCurrencyCode;
+const merchantSupportedNetworks = window.merchantSupportedNetworks;
+const merchantCapabilities = window.merchantCapabilities;
+const merchantTotalLabel = window.merchantTotalLabel;
+class ApplePay {
+ constructor() {
+ this.applePay = document.querySelector('.en__field__input.en__field__input--radio[value="applepay"]');
+ this._amount = DonationAmount.getInstance();
+ this._fees = ProcessingFees.getInstance();
+ this._form = en_form_EnForm.getInstance();
+ this.checkApplePay();
+ }
+ checkApplePay() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const pageform = document.querySelector("form.en__component--page");
+ if (!this.applePay || !window.hasOwnProperty("ApplePaySession")) {
+ const applePayContainer = document.querySelector(".en__field__item.applepay");
+ if (applePayContainer)
+ applePayContainer.remove();
+ if (engrid_ENGrid.debug)
+ console.log("Apple Pay DISABLED");
+ return false;
+ }
+ const promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantIdentifier);
+ let applePayEnabled = false;
+ yield promise.then((canMakePayments) => {
+ applePayEnabled = canMakePayments;
+ if (canMakePayments) {
+ let input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("name", "PkPaymentToken");
+ input.setAttribute("id", "applePayToken");
+ pageform.appendChild(input);
+ this._form.onSubmit.subscribe(() => this.onPayClicked());
+ }
+ });
+ if (engrid_ENGrid.debug)
+ console.log("applePayEnabled", applePayEnabled);
+ let applePayWrapper = this.applePay.closest(".en__field__item");
+ if (applePayEnabled) {
+ // Set Apple Pay Class
+ applePayWrapper === null || applePayWrapper === void 0 ? void 0 : applePayWrapper.classList.add("applePayWrapper");
+ }
+ else {
+ // Hide Apple Pay Wrapper
+ if (applePayWrapper)
+ applePayWrapper.style.display = "none";
+ }
+ return applePayEnabled;
+ });
+ }
+ performValidation(url) {
+ return new Promise(function (resolve, reject) {
+ var merchantSession = {};
+ merchantSession.merchantIdentifier = merchantIdentifier;
+ merchantSession.merchantSessionIdentifier = merchantSessionIdentifier;
+ merchantSession.nonce = merchantNonce;
+ merchantSession.domainName = merchantDomainName;
+ merchantSession.epochTimestamp = merchantEpochTimestamp;
+ merchantSession.signature = merchantSignature;
+ var validationData = "&merchantIdentifier=" +
+ merchantIdentifier +
+ "&merchantDomain=" +
+ merchantDomainName +
+ "&displayName=" +
+ merchantDisplayName;
+ var validationUrl = "/ea-dataservice/rest/applepay/validateurl?url=" + url + validationData;
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function () {
+ var data = JSON.parse(this.responseText);
+ if (engrid_ENGrid.debug)
+ console.log("Apple Pay Validation", data);
+ resolve(data);
+ };
+ xhr.onerror = reject;
+ xhr.open("GET", validationUrl);
+ xhr.send();
+ });
+ }
+ log(name, msg) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "/ea-dataservice/rest/applepay/log?name=" + name + "&msg=" + msg);
+ xhr.send();
+ }
+ sendPaymentToken(token) {
+ return new Promise(function (resolve, reject) {
+ resolve(true);
+ });
+ }
+ onPayClicked() {
+ if (!this._form.submit)
+ return;
+ const enFieldPaymentType = document.querySelector("#en__field_transaction_paymenttype");
+ const applePayToken = document.getElementById("applePayToken");
+ const formClass = this._form;
+ // Only work if Payment Type is Apple Pay
+ if (enFieldPaymentType.value == "applepay" && applePayToken.value == "") {
+ try {
+ let donationAmount = this._amount.amount + this._fees.fee;
+ var request = {
+ supportedNetworks: merchantSupportedNetworks,
+ merchantCapabilities: merchantCapabilities,
+ countryCode: merchantCountryCode,
+ currencyCode: merchantCurrencyCode,
+ total: {
+ label: merchantTotalLabel,
+ amount: donationAmount,
+ },
+ };
+ var session = new ApplePaySession(1, request);
+ var thisClass = this;
+ session.onvalidatemerchant = function (event) {
+ thisClass
+ .performValidation(event.validationURL)
+ .then(function (merchantSession) {
+ if (engrid_ENGrid.debug)
+ console.log("Apple Pay merchantSession", merchantSession);
+ session.completeMerchantValidation(merchantSession);
+ });
+ };
+ session.onpaymentauthorized = function (event) {
+ thisClass
+ .sendPaymentToken(event.payment.token)
+ .then(function (success) {
+ if (engrid_ENGrid.debug)
+ console.log("Apple Pay Token", event.payment.token);
+ document.getElementById("applePayToken").value = JSON.stringify(event.payment.token);
+ formClass.submitForm();
+ });
+ };
+ session.oncancel = function (event) {
+ if (engrid_ENGrid.debug)
+ console.log("Cancelled", event);
+ alert("You cancelled. Sorry it didn't work out.");
+ formClass.dispatchError();
+ };
+ session.begin();
+ this._form.submit = false;
+ return false;
+ }
+ catch (e) {
+ alert("Developer mistake: '" + e.message + "'");
+ formClass.dispatchError();
+ }
+ }
+ this._form.submit = true;
+ return true;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/a11y.js
+// a11y means accessibility
+// This Component is supposed to be used as a helper for Aria Attributes & Other Accessibility Features
+class A11y {
+ constructor() {
+ this.addRequired();
+ this.addLabel();
+ this.addGroupRole();
+ this.updateFrequencyLabel();
+ const ecardImages = document.querySelectorAll('.en__ecarditems__list img');
+ this.setAutoGeneratedAltTags(ecardImages);
+ this.manageErrorListAlertRole();
+ }
+ addGroupRole() {
+ // Add role="group" to all EN Radio fields
+ const radioFields = document.querySelectorAll(".en__field--radio");
+ radioFields.forEach((field) => {
+ field.setAttribute("role", "group");
+ // Add random ID to the label
+ const label = field.querySelector("label");
+ if (label) {
+ label.setAttribute("id", `en__field__label--${Math.random().toString(36).slice(2, 7)}`);
+ field.setAttribute("aria-labelledby", label.id);
+ }
+ });
+ }
+ addRequired() {
+ const mandatoryFields = document.querySelectorAll(".en__mandatory .en__field__input");
+ mandatoryFields.forEach((field) => {
+ field.setAttribute("aria-required", "true");
+ });
+ }
+ addLabel() {
+ const otherAmount = document.querySelector(".en__field__input--otheramount");
+ if (otherAmount) {
+ otherAmount.setAttribute("aria-label", "Enter your custom donation amount");
+ }
+ // Split selects usually don't have a label, so let's make the first option the label
+ const splitSelects = document.querySelectorAll(".en__field__input--splitselect");
+ splitSelects.forEach((select) => {
+ var _a, _b, _c, _d;
+ const firstOption = select.querySelector("option");
+ if (firstOption &&
+ firstOption.value === "" &&
+ !((_b = (_a = firstOption.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.includes("select")) &&
+ !((_d = (_c = firstOption.textContent) === null || _c === void 0 ? void 0 : _c.toLowerCase()) === null || _d === void 0 ? void 0 : _d.includes("choose"))) {
+ select.setAttribute("aria-label", firstOption.textContent || "");
+ }
+ });
+ }
+ // Update the label for the frequency field based on the selected radio button
+ updateFrequencyLabel() {
+ const frequencyLabels = document.querySelectorAll('div.en__field__item input[id^="en__field_transaction_recurrfreq"]');
+ const frequencyMainLabel = document.querySelector('label[for="en__field_transaction_recurrfreq"]');
+ frequencyLabels.forEach((item) => {
+ if (item) {
+ // Set the label for the checked item on load
+ if (item.checked) {
+ frequencyMainLabel === null || frequencyMainLabel === void 0 ? void 0 : frequencyMainLabel.setAttribute('for', item.id);
+ }
+ // Then, detect if it changes with the click event
+ item.addEventListener('click', () => {
+ let frequencyId = item.id;
+ frequencyMainLabel === null || frequencyMainLabel === void 0 ? void 0 : frequencyMainLabel.setAttribute('for', frequencyId);
+ });
+ }
+ });
+ }
+ setAutoGeneratedAltTags(images) {
+ images.forEach((img) => {
+ var _a;
+ // Skip if the alt tag is already set
+ if (img.alt)
+ return;
+ try {
+ // Extract the filename from the `src` attribute
+ const src = img.src;
+ if (!src)
+ throw new Error("Image src is null or undefined");
+ const url = new URL(src);
+ const fileNameWithExtension = url.pathname.split('/').pop();
+ if (!fileNameWithExtension)
+ throw new Error("No filename found in src");
+ // Remove the file extension and replace `-` and `_` with spaces
+ let altText = ((_a = fileNameWithExtension.split('.').shift()) === null || _a === void 0 ? void 0 : _a.replace(/[-_]/g, ' ')) || '';
+ // Remove dimensions (#x#) and anything that follows
+ altText = altText.replace(/\d+x\d+.*$/, '').trim();
+ // Wrap in the disclaimer
+ altText = `This is an auto-generated alt tag from the filename: ${altText}`;
+ // Set the generated alt text on the image
+ img.alt = altText;
+ }
+ catch (error) {
+ console.error(`Error processing image: ${img.src}`, error);
+ }
+ });
+ }
+ manageErrorListAlertRole() {
+ const errorList = document.querySelector('ul.en__errorList');
+ if (!errorList)
+ return;
+ const hasErrorItems = () => Boolean(errorList.querySelector('li'));
+ const enableAlert = () => {
+ if (!errorList.hasAttribute('role')) {
+ errorList.setAttribute('role', 'alert');
+ }
+ };
+ const disableAlert = () => {
+ if (errorList.hasAttribute('role')) {
+ errorList.removeAttribute('role');
+ }
+ };
+ hasErrorItems() ? enableAlert() : disableAlert();
+ new MutationObserver(records => {
+ for (const record of records) {
+ if (record.type === 'childList') {
+ hasErrorItems() ? enableAlert() : disableAlert();
+ break;
+ }
+ }
+ }).observe(errorList, { childList: true });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/capitalize-fields.js
+// CapitalizeFields is a class that capitalizes the first letter of the fields passed to it.
+// It subscribes to the onSubmit event of the EnForm class and capitalizes the fields on submit.
+
+
+class CapitalizeFields {
+ constructor() {
+ this._form = en_form_EnForm.getInstance();
+ this._form.onSubmit.subscribe(() => this.capitalizeFields("en__field_supporter_firstName", "en__field_supporter_lastName", "en__field_supporter_address1", "en__field_supporter_city"));
+ }
+ capitalizeFields(...fields) {
+ fields.forEach((f) => this.capitalize(f));
+ }
+ capitalize(f) {
+ let field = document.getElementById(f);
+ if (field) {
+ field.value = field.value.replace(/\w\S*/g, (w) => w.replace(/^\w/, (c) => c.toUpperCase()));
+ if (engrid_ENGrid.debug)
+ console.log("Capitalized", field.value);
+ }
+ return true;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/auto-year.js
+// This class changes the Credit Card Expiration Year Field Options to
+// include the current year and the next 19 years.
+class AutoYear {
+ constructor() {
+ this.yearField = document.querySelector("select[name='transaction.ccexpire']:not(#en__field_transaction_ccexpire)");
+ this.years = 20;
+ this.yearLength = 2;
+ if (this.yearField) {
+ this.clearFieldOptions();
+ for (let i = 0; i < this.years; i++) {
+ const year = new Date().getFullYear() + i;
+ const newOption = document.createElement("option");
+ const optionText = document.createTextNode(year.toString());
+ newOption.appendChild(optionText);
+ newOption.value =
+ this.yearLength == 2 ? year.toString().substr(-2) : year.toString();
+ this.yearField.appendChild(newOption);
+ }
+ }
+ }
+ clearFieldOptions() {
+ if (this.yearField) {
+ this.yearLength =
+ this.yearField.options[this.yearField.options.length - 1].value.length;
+ [...this.yearField.options].forEach((option) => {
+ var _a;
+ if (option.value !== "" && !isNaN(Number(option.value))) {
+ // @ts-ignore
+ const index = [...this.yearField.options].findIndex((i) => i.value === option.value);
+ (_a = this.yearField) === null || _a === void 0 ? void 0 : _a.remove(index);
+ }
+ });
+ }
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/autocomplete.js
+// This class adds the autocomplete attribute to
+// the most common input elements
+
+class Autocomplete {
+ constructor() {
+ this.logger = new logger_EngridLogger("Autocomplete", "#330033", "#f0f0f0", "π");
+ this.autoCompleteField('[name="supporter.firstName"]', "given-name");
+ this.autoCompleteField('[name="supporter.lastName"]', "family-name");
+ this.autoCompleteField("#en__field_transaction_ccexpire", "cc-exp-month");
+ this.autoCompleteField('[name="transaction.ccexpire"]:not(#en__field_transaction_ccexpire)', "cc-exp-year");
+ this.autoCompleteField('[name="supporter.emailAddress"]', "email");
+ this.autoCompleteField('[name="supporter.phoneNumber"]', "tel");
+ this.autoCompleteField('[name="supporter.country"]', "country");
+ this.autoCompleteField('[name="supporter.address1"]', "address-line1");
+ this.autoCompleteField('[name="supporter.address2"]', "address-line2");
+ this.autoCompleteField('[name="supporter.city"]', "address-level2");
+ this.autoCompleteField('[name="supporter.region"]', "address-level1");
+ this.autoCompleteField('[name="supporter.postcode"]', "postal-code");
+ // Ignore Autocomplete on the Recipient Email Field & Address ("none" is intentional because "off" doesn't work)
+ this.autoCompleteField('[name="transaction.honname"]', "none");
+ this.autoCompleteField('[name="transaction.infemail"]', "none");
+ this.autoCompleteField('[name="transaction.infname"]', "none");
+ this.autoCompleteField('[name="transaction.infadd1"]', "none");
+ this.autoCompleteField('[name="transaction.infadd2"]', "none");
+ this.autoCompleteField('[name="transaction.infcity"]', "none");
+ this.autoCompleteField('[name="transaction.infpostcd"]', "none");
+ }
+ autoCompleteField(querySelector, autoCompleteValue) {
+ let field = document.querySelector(querySelector);
+ if (field) {
+ field.autocomplete = autoCompleteValue;
+ return true;
+ }
+ if (autoCompleteValue !== "none")
+ this.logger.log("Field Not Found", querySelector);
+ return false;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/ecard.js
+
+class Ecard {
+ constructor() {
+ this._form = en_form_EnForm.getInstance();
+ this.logger = new logger_EngridLogger("Ecard", "red", "#f5f5f5", "πͺͺ");
+ if (!this.shouldRun())
+ return;
+ this._form.onValidate.subscribe(() => this.checkRecipientFields());
+ const schedule = engrid_ENGrid.getUrlParameter("engrid_ecard.schedule");
+ const scheduleField = engrid_ENGrid.getField("ecard.schedule");
+ const name = engrid_ENGrid.getUrlParameter("engrid_ecard.name");
+ const nameField = document.querySelector(".en__ecardrecipients__name input");
+ const email = engrid_ENGrid.getUrlParameter("engrid_ecard.email");
+ const emailField = document.querySelector(".en__ecardrecipients__email input");
+ if (schedule && scheduleField) {
+ // Check if chedule date is in the past
+ const scheduleDate = new Date(schedule.toString());
+ const today = new Date();
+ if (scheduleDate.setHours(0, 0, 0, 0) < today.setHours(0, 0, 0, 0)) {
+ // If it is, set the schedule to today
+ scheduleField.value = engrid_ENGrid.formatDate(today, "YYYY-MM-DD");
+ }
+ else {
+ // Otherwise, set the schedule to the date provided
+ scheduleField.value = schedule.toString();
+ }
+ this.logger.log("Schedule set to " + scheduleField.value);
+ }
+ if (name && nameField) {
+ nameField.value = name.toString();
+ this.logger.log("Name set to " + nameField.value);
+ }
+ if (email && emailField) {
+ emailField.value = email.toString();
+ this.logger.log("Email set to " + emailField.value);
+ }
+ // Replace the Future Delivery Label with a H2
+ const futureDeliveryLabel = document.querySelector(".en__ecardrecipients__futureDelivery label");
+ if (futureDeliveryLabel) {
+ const futureDeliveryH2 = document.createElement("h2");
+ futureDeliveryH2.innerText = futureDeliveryLabel.innerText;
+ futureDeliveryLabel.replaceWith(futureDeliveryH2);
+ }
+ if (emailField) {
+ emailField.setAttribute("type", "email");
+ emailField.setAttribute("autocomplete", "off");
+ }
+ }
+ shouldRun() {
+ return engrid_ENGrid.getPageType() === "ECARD";
+ }
+ checkRecipientFields() {
+ const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
+ // If we find the "+" button and there's no hidden recipient field, click on the button
+ if (addRecipientButton &&
+ !document.querySelector(".ecardrecipient__email")) {
+ addRecipientButton.click();
+ }
+ return true;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/click-to-expand.js
+// This class is used to expand content when a user clicks on a div with the class "click-to-expand".
+// The content is shortened by default and will expand when clicked.
+
+// Works when the user has adds ".click-to-expand" as a class to any field
+class ClickToExpand {
+ constructor() {
+ this.clickToExpandWrapper = document.querySelectorAll("div.click-to-expand");
+ if (this.clickToExpandWrapper.length) {
+ this.clickToExpandWrapper.forEach((element) => {
+ const content = element.innerHTML;
+ const wrapper_html = '
' +
+ content +
+ "
";
+ element.innerHTML = wrapper_html;
+ element.addEventListener("click", (event) => {
+ if (event) {
+ if (engrid_ENGrid.debug)
+ console.log("A click-to-expand div was clicked");
+ element.classList.add("expanded");
+ }
+ });
+ element.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
+ if (engrid_ENGrid.debug)
+ console.log("A click-to-expand div had the 'Enter' key pressed on it");
+ element.classList.add("expanded");
+ }
+ else if (event.key === " ") {
+ if (engrid_ENGrid.debug)
+ console.log("A click-to-expand div had the 'Spacebar' key pressed on it");
+ element.classList.add("expanded");
+ event.preventDefault(); // Prevents the page from scrolling
+ event.stopPropagation(); // Prevent a console error generated by LastPass https://github.com/KillerCodeMonkey/ngx-quill/issues/351#issuecomment-476017960
+ }
+ });
+ });
+ }
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/advocacy.js
+// Component to handle advocacy features
+// 1 - Adds EN Polyfill to support "label" clicking on Advocacy Recipient "labels"
+
+class Advocacy {
+ constructor() {
+ this.logger = new logger_EngridLogger("Advocacy", "#232323", "#f7b500", "π¨ββοΈ");
+ if (!this.shoudRun())
+ return;
+ this.setClickableLabels();
+ }
+ shoudRun() {
+ return ["ADVOCACY", "EMAILTOTARGET"].includes(engrid_ENGrid.getPageType());
+ }
+ setClickableLabels() {
+ const contactItems = document.querySelectorAll(".en__contactDetails__rows");
+ if (!contactItems)
+ return;
+ contactItems.forEach((contact) => {
+ contact.addEventListener("click", (e) => {
+ this.toggleCheckbox(contact);
+ });
+ });
+ }
+ toggleCheckbox(contact) {
+ const wrapper = contact.closest(".en__contactDetails");
+ if (!wrapper)
+ return;
+ const checkbox = wrapper.querySelector("input[type='checkbox']");
+ if (!checkbox)
+ return;
+ this.logger.log("toggleCheckbox", checkbox.checked);
+ checkbox.checked = !checkbox.checked;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-attributes.js
+// Component that adds data attributes to the Body
+
+class DataAttributes {
+ constructor() {
+ this.logger = new logger_EngridLogger("Data Attribute Changed", "#FFFFFF", "#4d9068", "π οΈ");
+ this._country = Country.getInstance();
+ this._frequency = DonationFrequency.getInstance();
+ this.setDataAttributes();
+ }
+ setDataAttributes() {
+ // Apple Pay Availability
+ if (window.hasOwnProperty("ApplePaySession")) {
+ engrid_ENGrid.setBodyData("apple-pay-available", "true");
+ }
+ else {
+ engrid_ENGrid.setBodyData("apple-pay-available", "false");
+ }
+ // Add the Page Type as a Data Attribute on the Body Tag
+ if (engrid_ENGrid.checkNested(window, "pageJson", "pageType")) {
+ engrid_ENGrid.setBodyData("page-type", window.pageJson.pageType);
+ }
+ // Add the currency code as a Data Attribute on the Body Tag
+ engrid_ENGrid.setBodyData("currency-code", engrid_ENGrid.getCurrencyCode());
+ // Add a body banner data attribute if the banner contains no image or video
+ if (!document.querySelector(".body-banner img, .body-banner video")) {
+ engrid_ENGrid.setBodyData("body-banner", "empty");
+ }
+ // Add a page-alert data attribute if it is empty
+ if (!document.querySelector(".page-alert *")) {
+ engrid_ENGrid.setBodyData("no-page-alert", "");
+ }
+ // Add a content-header data attribute if it is empty
+ if (!document.querySelector(".content-header *")) {
+ engrid_ENGrid.setBodyData("no-content-header", "");
+ }
+ // Add a body-headerOutside data attribute if it is empty
+ if (!document.querySelector(".body-headerOutside *")) {
+ engrid_ENGrid.setBodyData("no-body-headerOutside", "");
+ }
+ // Add a body-header data attribute if it is empty
+ if (!document.querySelector(".body-header *")) {
+ engrid_ENGrid.setBodyData("no-body-header", "");
+ }
+ // Add a body-title data attribute if it is empty
+ if (!document.querySelector(".body-title *")) {
+ engrid_ENGrid.setBodyData("no-body-title", "");
+ }
+ // Add a body-banner data attribute if it is empty
+ if (!document.querySelector(".body-banner *")) {
+ engrid_ENGrid.setBodyData("no-body-banner", "");
+ }
+ // Add a body-bannerOverlay data attribute if it is empty
+ if (!document.querySelector(".body-bannerOverlay *")) {
+ engrid_ENGrid.setBodyData("no-body-bannerOverlay", "");
+ }
+ // Add a body-top data attribute if it is empty
+ if (!document.querySelector(".body-top *")) {
+ engrid_ENGrid.setBodyData("no-body-top", "");
+ }
+ // Add a body-main data attribute if it is empty
+ if (!document.querySelector(".body-main *")) {
+ engrid_ENGrid.setBodyData("no-body-main", "");
+ }
+ // Add a body-bottom data attribute if it is empty
+ if (!document.querySelector(".body-bottom *")) {
+ engrid_ENGrid.setBodyData("no-body-bottom", "");
+ }
+ // Add a body-footer data attribute if it is empty
+ if (!document.querySelector(".body-footer *")) {
+ engrid_ENGrid.setBodyData("no-body-footer", "");
+ }
+ // Add a body-footerOutside data attribute if it is empty
+ if (!document.querySelector(".body-footerOutside *")) {
+ engrid_ENGrid.setBodyData("no-body-footerOutside", "");
+ }
+ // Add a content-footerSpacer data attribute if it is empty
+ if (!document.querySelector(".content-footerSpacer *")) {
+ engrid_ENGrid.setBodyData("no-content-footerSpacer", "");
+ }
+ // Add a content-preFooter data attribute if it is empty
+ if (!document.querySelector(".content-preFooter *")) {
+ engrid_ENGrid.setBodyData("no-content-preFooter", "");
+ }
+ // Add a content-footer data attribute if it is empty
+ if (!document.querySelector(".content-footer *")) {
+ engrid_ENGrid.setBodyData("no-content-footer", "");
+ }
+ // Add a page-backgroundImage banner data attribute if the page background image contains no image or video
+ if (!document.querySelector(".page-backgroundImage img, .page-backgroundImage video")) {
+ engrid_ENGrid.setBodyData("no-page-backgroundImage", "");
+ }
+ // Add a page-backgroundImageOverlay data attribute if it is empty
+ if (!document.querySelector(".page-backgroundImageOverlay *")) {
+ engrid_ENGrid.setBodyData("no-page-backgroundImageOverlay", "");
+ }
+ // Add a page-customCode data attribute if it is empty
+ if (!document.querySelector(".page-customCode *")) {
+ engrid_ENGrid.setBodyData("no-page-customCode", "");
+ }
+ // Add a country data attribute
+ if (this._country.country) {
+ engrid_ENGrid.setBodyData("country", this._country.country);
+ this._country.onCountryChange.subscribe((country) => {
+ engrid_ENGrid.setBodyData("country", country);
+ });
+ }
+ const otherAmountDiv = document.querySelector(".en__field--donationAmt .en__field__item--other");
+ if (otherAmountDiv) {
+ otherAmountDiv.setAttribute("data-currency-symbol", engrid_ENGrid.getCurrencySymbol());
+ }
+ // Add a payment type data attribute
+ const paymentTypeSelect = engrid_ENGrid.getField("transaction.paymenttype");
+ if (paymentTypeSelect) {
+ engrid_ENGrid.setBodyData("payment-type", paymentTypeSelect.value);
+ paymentTypeSelect.addEventListener("change", () => {
+ engrid_ENGrid.setBodyData("payment-type", paymentTypeSelect.value);
+ });
+ }
+ // Footer in Viewport Check
+ const contentFooter = document.querySelector(".content-footer");
+ if (contentFooter && engrid_ENGrid.isInViewport(contentFooter)) {
+ engrid_ENGrid.setBodyData("footer-above-fold", "");
+ }
+ else {
+ engrid_ENGrid.setBodyData("footer-below-fold", "");
+ }
+ // Add demo data attribute
+ if (engrid_ENGrid.demo)
+ engrid_ENGrid.setBodyData("demo", "");
+ // Add data-first-page and data-last-page
+ if (engrid_ENGrid.getPageNumber() === 1) {
+ engrid_ENGrid.setBodyData("first-page", "");
+ }
+ if (engrid_ENGrid.getPageNumber() === engrid_ENGrid.getPageCount()) {
+ engrid_ENGrid.setBodyData("last-page", "");
+ }
+ // "Temporary solutions are forever, you know..."
+ // - Fernando Santos
+ // "I know, but what if we just..."
+ // - Bryan Casler
+ // Add data attribute if browser does not support :has selector
+ if (!CSS.supports("selector(:has(*))")) {
+ engrid_ENGrid.setBodyData("css-has-selector", "false");
+ }
+ if (engrid_ENGrid.getPageType() === "DONATION") {
+ this.addFrequencyDataAttribute();
+ this.addGiftAmountDataAttribute();
+ }
+ }
+ // Add a data attribute to the body tag with how many visible frequency options there are
+ addFrequencyDataAttribute() {
+ const frequencyOptions = document.querySelectorAll(".en__field--recurrfreq .en__field__item label.en__field__label");
+ let visibleFrequencyOptions = 0;
+ frequencyOptions.forEach((option) => {
+ if (engrid_ENGrid.isVisible(option)) {
+ visibleFrequencyOptions++;
+ }
+ });
+ engrid_ENGrid.setBodyData("visible-frequency", visibleFrequencyOptions.toString());
+ }
+ // Add a data attribute to the body tag with how many visible gift amount options there are
+ addGiftAmountDataAttribute() {
+ const updateGiftAmountData = () => {
+ const giftAmountOptions = document.querySelectorAll(".en__field--donationAmt .en__field__element .en__field__item");
+ let visibleGiftAmountOptions = 0;
+ giftAmountOptions.forEach((option) => {
+ if (engrid_ENGrid.isVisible(option)) {
+ visibleGiftAmountOptions++;
+ }
+ });
+ engrid_ENGrid.setBodyData("visible-gift-amount", visibleGiftAmountOptions.toString());
+ this.logger.log("Visible Gift Amount Changed to: " + visibleGiftAmountOptions.toString());
+ };
+ // Initial update
+ updateGiftAmountData();
+ // Observe changes in the donation amount section
+ const observer = new MutationObserver(updateGiftAmountData);
+ const targetNode = document.querySelector(".en__field--donationAmt");
+ if (targetNode) {
+ observer.observe(targetNode, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ });
+ }
+ // Run update updateGiftAmountData when frequency changes
+ this._frequency.onFrequencyChange.subscribe(() => {
+ setTimeout(() => {
+ updateGiftAmountData();
+ }, 10);
+ });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/iframe.js
+
+
+class iFrame {
+ constructor() {
+ this._form = en_form_EnForm.getInstance();
+ this.logger = new logger_EngridLogger("iFrame", "brown", "gray", "π‘");
+ if (this.inIframe()) {
+ // Add the data-engrid-embedded attribute when inside an iFrame if it wasn't already added by a script in the Page Template
+ engrid_ENGrid.setBodyData("embedded", "");
+ // Check if the parent page URL matches the criteria for a thank you page donation
+ const getParentUrl = () => {
+ try {
+ return window.parent.location.href;
+ }
+ catch (e) {
+ // If we can't access parent location due to same-origin policy, fall back to referrer
+ return document.referrer;
+ }
+ };
+ const parentUrl = getParentUrl();
+ const thankYouPageRegex = /\/page\/\d+\/[^\/]+\/(\d+)(\?|$)/;
+ const match = parentUrl.match(thankYouPageRegex);
+ if (match) {
+ const pageNumber = parseInt(match[1], 10);
+ if (pageNumber > 1) {
+ engrid_ENGrid.setBodyData("embedded", "thank-you-page-donation");
+ this.hideFormComponents();
+ this.logger.log("iFrame Event - Set embedded attribute to thank-you-page-donation");
+ }
+ }
+ // Fire the resize event
+ this.logger.log("iFrame Event - Begin Resizing");
+ // Run onLoaded function
+ console.log("document.readyState", document.readyState);
+ // Document Load
+ if (document.readyState !== "loading") {
+ this.onLoaded();
+ }
+ else {
+ document.addEventListener("DOMContentLoaded", () => {
+ this.onLoaded();
+ });
+ }
+ window.setTimeout(() => {
+ this.sendIframeHeight();
+ }, 300);
+ window.addEventListener("resize", this.debounceWithImmediate(() => {
+ this.logger.log("iFrame Event - window resized");
+ this.sendIframeHeight();
+ }));
+ // Listen for the form submit event
+ this._form.onSubmit.subscribe((e) => {
+ this.logger.log("iFrame Event - onSubmit");
+ this.sendIframeFormStatus("submit");
+ });
+ // If the iFrame is Chained, check if the form has data
+ if (this.isChained() && engrid_ENGrid.getPaymentType()) {
+ this.logger.log("iFrame Event - Chained iFrame");
+ this.sendIframeFormStatus("chained");
+ // this.addChainedBanner();
+ }
+ // Remove the skip link markup when inside an iFrame
+ const skipLink = document.querySelector(".skip-link");
+ if (skipLink) {
+ skipLink.remove();
+ }
+ this._form.onError.subscribe(() => {
+ // Get the first .en__field--validationFailed element
+ const firstError = document.querySelector(".en__field--validationFailed");
+ // Send scrollTo message
+ // Parent pages listens for this message and scrolls to the correct position
+ const scrollTo = firstError
+ ? firstError.getBoundingClientRect().top
+ : 0;
+ this.logger.log(`iFrame Event 'scrollTo' - Position of top of first error ${scrollTo} px`); // check the message is being sent correctly
+ window.parent.postMessage({ scrollTo }, "*");
+ // Send the height of the iFrame
+ window.setTimeout(() => {
+ this.sendIframeHeight();
+ }, 100);
+ });
+ }
+ else {
+ // When not in iframe, default behaviour, smooth scroll to first error
+ this._form.onError.subscribe(() => {
+ // Smooth Scroll to the first .en__field--validationFailed element
+ const firstError = document.querySelector(".en__field--validationFailed");
+ if (firstError) {
+ firstError.scrollIntoView({ behavior: "smooth" });
+ }
+ });
+ // Parent Page Logic (when an ENgrid form is embedded in an ENgrid page)
+ window.addEventListener("message", (event) => {
+ const iframe = this.getIFrameByEvent(event);
+ if (iframe) {
+ if (event.data.hasOwnProperty("frameHeight")) {
+ iframe.style.height = event.data.frameHeight + "px";
+ if (event.data.frameHeight > 0) {
+ iframe.classList.add("loaded");
+ }
+ else {
+ iframe.classList.remove("loaded");
+ }
+ }
+ // Old scroll event logic "scroll", scrolls to correct iframe?
+ else if (event.data.hasOwnProperty("scroll") &&
+ event.data.scroll > 0) {
+ const elDistanceToTop = window.pageYOffset + iframe.getBoundingClientRect().top;
+ let scrollTo = elDistanceToTop + event.data.scroll;
+ window.scrollTo({
+ top: scrollTo,
+ left: 0,
+ behavior: "smooth",
+ });
+ this.logger.log("iFrame Event - Scrolling Window to " + scrollTo);
+ }
+ // New scroll event logic "scrollTo", scrolls to the first error
+ else if (event.data.hasOwnProperty("scrollTo")) {
+ const scrollToPosition = event.data.scrollTo +
+ window.scrollY +
+ iframe.getBoundingClientRect().top;
+ window.scrollTo({
+ top: scrollToPosition,
+ left: 0,
+ behavior: "smooth",
+ });
+ this.logger.log("iFrame Event - Scrolling Window to " + scrollToPosition);
+ }
+ }
+ });
+ }
+ }
+ onLoaded() {
+ // Scroll to top of iFrame
+ this.logger.log("iFrame Event - window.onload");
+ this.sendIframeHeight();
+ window.parent.postMessage({
+ scroll: this.shouldScroll(),
+ }, "*");
+ // Iframe Queue: signal Thank-You-page completion to the parent window.
+ // The IframeQueue component (in parent mode) listens for this ping and
+ // matches it by Page ID to advance to the next queued iframe. Fires
+ // exactly once per Thank-You-page load. See iframe-queue.ts.
+ this.sendIframeQueueThankYouPing();
+ // On click fire the resize event
+ document.addEventListener("click", (e) => {
+ this.logger.log("iFrame Event - click");
+ setTimeout(() => {
+ this.sendIframeHeight();
+ }, 100);
+ });
+ // Watch for errors and send the height
+ engrid_ENGrid.watchForError(this.sendIframeHeight.bind(this));
+ }
+ /**
+ * Posts a `engrid-iframe-queue:thank-you` message to the parent window
+ * when the embedded EN page reaches its Thank You page (the last page
+ * in the page sequence). Carries the Page ID of the submitting form so
+ * the IframeQueue parent can match the ping against the queued item it
+ * is waiting on, ignoring pings from unrelated EN iframes that may exist
+ * on the same parent page (e.g. an Embedded Ecard iframe).
*
- * @param url Full URL string to parse.
- * @returns The numeric Page ID, or 0 if it could not be parsed.
+ * Only fires when:
+ * - the script is running inside an iframe (already guaranteed by the
+ * code path that calls onLoaded()), AND
+ * - the embedded page is a Thank You page (ENGrid.isThankYouPage()).
+ *
+ * Consumed by: IframeQueue (engrid/packages/scripts/src/iframe-queue.ts).
*/
- static getPageIdFromUrl(url) {
- if (!url)
- return 0;
- const match = url.match(/\/page\/(\d+)(?:\/|$|\?|#)/);
- if (!match)
- return 0;
- const id = parseInt(match[1], 10);
- return Number.isFinite(id) ? id : 0;
+ sendIframeQueueThankYouPing() {
+ if (!engrid_ENGrid.isThankYouPage())
+ return;
+ const pageId = engrid_ENGrid.getPageID();
+ const message = {
+ type: "engrid-iframe-queue:thank-you",
+ pageId,
+ pageNumber: engrid_ENGrid.getPageNumber(),
+ pageCount: engrid_ENGrid.getPageCount(),
+ url: window.location.href,
+ };
+ this.logger.log(`iFrame Event - Iframe Queue thank-you ping (pageId=${pageId})`);
+ window.parent.postMessage(message, "*");
}
- // Return the client ID
- static getClientID() {
- if ("pageJson" in window)
- return window.pageJson.clientId;
- return 0;
+ sendIframeHeight() {
+ let height = document.body.offsetHeight;
+ this.logger.log("iFrame Event - Sending iFrame height of: " + height + "px"); // check the message is being sent correctly
+ window.parent.postMessage({
+ frameHeight: height,
+ pageNumber: engrid_ENGrid.getPageNumber(),
+ pageCount: engrid_ENGrid.getPageCount(),
+ giftProcess: engrid_ENGrid.getGiftProcess(),
+ }, "*");
}
- //returns 'us or 'ca' based on the client ID
- static getDataCenter() {
- return engrid_ENGrid.getClientID() >= 10000 ? "us" : "ca";
+ sendIframeFormStatus(status) {
+ window.parent.postMessage({
+ status: status,
+ pageNumber: engrid_ENGrid.getPageNumber(),
+ pageCount: engrid_ENGrid.getPageCount(),
+ giftProcess: engrid_ENGrid.getGiftProcess(),
+ }, "*");
}
- // Return the current page type
- static getPageType() {
- if ("pageJson" in window && "pageType" in window.pageJson) {
- switch (window.pageJson.pageType) {
- case "p2pcheckout":
- case "p2pdonation":
- case "donation":
- case "premiumgift":
- return "DONATION";
- break;
- case "e-card":
- return "ECARD";
- break;
- case "otherdatacapture":
- case "survey":
- return "SURVEY";
- break;
- case "emailtotarget":
- return "EMAILTOTARGET";
- break;
- case "advocacypetition":
- return "ADVOCACY";
- break;
- case "emailsubscribeform":
- return "SUBSCRIBEFORM";
- break;
- case "event":
- return "EVENT";
- break;
- case "supporterhub":
- return "SUPPORTERHUB";
- break;
- case "unsubscribe":
- return "UNSUBSCRIBE";
- break;
- case "tweetpage":
- return "TWEETPAGE";
- break;
- default:
- return "UNKNOWN";
+ getIFrameByEvent(event) {
+ return [].slice
+ .call(document.getElementsByTagName("iframe"))
+ .filter((iframe) => {
+ return iframe.contentWindow === event.source;
+ })[0];
+ }
+ shouldScroll() {
+ // If you find a error, scroll
+ if (document.querySelector(".en__errorHeader")) {
+ return true;
+ }
+ // If it's a chained iFrame, don't scroll
+ if (this.isChained()) {
+ return false;
+ }
+ // Try to match the iframe referrer URL by testing valid EN Page URLs
+ let referrer = document.referrer;
+ let enURLPattern = new RegExp(/^(.*)\/(page)\/(\d+.*)/);
+ // Scroll if the Regex matches, don't scroll otherwise
+ return enURLPattern.test(referrer);
+ }
+ inIframe() {
+ try {
+ return window.self !== window.top;
+ }
+ catch (e) {
+ return true;
+ }
+ }
+ // This method checks if the URL has a parameter named "chain" and returns true if it exists, otherwise false.
+ isChained() {
+ return !!engrid_ENGrid.getUrlParameter("chain");
+ }
+ hideFormComponents() {
+ this.logger.log("iFrame Event - Hiding Form Components");
+ const excludeClasses = [
+ "giveBySelect-Card",
+ "en__field--ccnumber",
+ "en__field--survey",
+ "en__component--ecardblock",
+ "give-by-select",
+ "give-by-select-header",
+ "en__submit",
+ "en__captcha",
+ "force-visibility",
+ "hide",
+ "hide-iframe",
+ "radio-to-buttons_donationAmt",
+ ];
+ const excludeIds = ["en__digitalWallet"];
+ const components = Array.from(document.querySelectorAll(".body-main:not(.force-visibility) > div:not(:last-child)"));
+ components.forEach((component) => {
+ const shouldExclude = excludeClasses.some((cls) => component.classList.contains(cls) ||
+ component.querySelector(`:scope > .${cls}`)) || excludeIds.some((id) => component.querySelector(`#${id}`));
+ if (!shouldExclude) {
+ component.classList.add("hide-iframe", "hide-chained");
+ }
+ });
+ this.sendIframeHeight();
+ }
+ showFormComponents() {
+ this.logger.log("iFrame Event - Showing Form Components");
+ const en__component = document.querySelectorAll(".body-main > div.hide-chained");
+ en__component.forEach((component) => {
+ component.classList.remove("hide-iframe");
+ component.classList.remove("hide-chained");
+ });
+ this.sendIframeHeight();
+ }
+ // private addChainedBanner() {
+ // this.logger.log("iFrame Event - Adding Chained Banner");
+ // const banner = document.createElement("div");
+ // const lastComponent = document.querySelector(
+ // ".body-main > div:last-of-type"
+ // ) as HTMLDivElement;
+ // banner.classList.add("en__component");
+ // banner.classList.add("en__component--banner");
+ // banner.classList.add("en__component--banner--chained");
+ // banner.innerHTML = `
+ // ${ENGrid.getFieldValue("supporter.firstName") ? `Giving as ${ENGrid.getFieldValue("supporter.firstName")} ${ENGrid.getFieldValue("supporter.lastName")} ` : "Testing as "}
+ // with ${ENGrid.getFieldValue(
+ // "transaction.paymenttype"
+ // ).toUpperCase()}
+ // (change )
`;
+ // lastComponent?.parentNode?.insertBefore(banner, lastComponent);
+ // banner
+ // .querySelector(".en__component__content__link")
+ // ?.addEventListener("click", (e) => {
+ // e.preventDefault();
+ // this.showFormComponents();
+ // banner.remove();
+ // });
+ // }
+ debounceWithImmediate(func, timeout = 1000) {
+ let timer;
+ let firstEvent = true;
+ return (...args) => {
+ clearTimeout(timer);
+ if (firstEvent) {
+ func.apply(this, args);
+ firstEvent = false;
}
+ timer = setTimeout(() => {
+ func.apply(this, args);
+ firstEvent = true;
+ }, timeout);
+ };
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/iframe-queue.js
+/**
+ * Iframe Queue β load embedded EN pages sequentially.
+ *
+ * **This component is opt-in.** Like `OptInLadder`, it is exported from
+ * `@4site/engrid-scripts` but is **not** auto-constructed by ENgrid's
+ * core bootstrap (`app.ts`). To use it, instantiate it once in your
+ * theme's bootstrap:
+ *
+ * ```ts
+ * import { IframeQueue } from "@4site/engrid-scripts";
+ * new IframeQueue();
+ * ```
+ *
+ * On client themes that don't use this component, **nothing in this
+ * file runs**: no `message` listener is registered, no singleton is
+ * allocated, no bundle code beyond the unused class definition.
+ *
+ * **Why this exists.** Engaging Networks' platform handles concurrent
+ * iframe submissions inconsistently β when several embedded EN forms
+ * are submitted in parallel (e.g. QCB opt-ins for postal mail, mobile
+ * phone, and double opt-in email), roughly 40% of records are lost.
+ * Loading the iframes sequentially (without `?chain`) resolves the
+ * issue. This component generalises that pattern.
+ *
+ * **What it does.** In _parent_ mode (top-level page) it holds an
+ * ordered queue of {@link IframeQueueItem} configs and processes them
+ * one at a time: create iframe β wait for `load` β post a populate
+ * message with field values β wait for the embedded page to reach a
+ * Thank You page β advance. In _embedded_ mode (running inside an
+ * iframe owned by an IframeQueue parent) it listens for the populate
+ * message, fills the form fields via {@link ENGrid.setFieldValue}, and
+ * submits via {@link EnForm.submitForm} when `autoSubmit` is true.
+ *
+ * **Why not `?chain`?** Engaging Networks' `?chain` URL parameter is
+ * unreliable for sequential iframe submission; the agreed solution is
+ * to pass field data via `postMessage` instead. The queue defensively
+ * strips any `chain` query parameter from queued URLs.
+ *
+ * **Page ID matching.** The Thank-You-page ping (sent by the iFrame
+ * component, see iframe.ts) carries the Page ID of the submitting
+ * form. The queue compares it against the Page ID parsed from the
+ * queued URL so that pings from unrelated EN iframes on the same
+ * parent page (such as an Embedded Ecard iframe) are ignored.
+ *
+ * **Events.** Lifecycle events are dispatched via the
+ * {@link IframeQueueEvents} singleton. External code subscribes there
+ * rather than holding a reference to the queue itself.
+ *
+ * @example Programmatic API
+ * const queue = IframeQueue.getInstance();
+ * queue.enqueue({
+ * url: "https://example.org/page/123/data/1",
+ * fields: { "supporter.emailAddress": "donor@example.org" },
+ * autoSubmit: true,
+ * });
+ * queue.process().then(() => console.log("done"));
+ *
+ * @example Declarative API (set on the EN page before the bundle loads)
+ * window.EngridIframeQueue = {
+ * items: [
+ * { url: "https://example.org/page/123/data/1",
+ * fields: { "supporter.emailAddress": "donor@example.org" } },
+ * ],
+ * autoStart: true,
+ * };
+ */
+var iframe_queue_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+
+
+/** Wire-format type for the populate message sent parent β iframe. */
+const MSG_POPULATE = "engrid-iframe-queue:populate";
+/** Wire-format type for the Thank-You-page ping sent iframe β parent. */
+const MSG_THANK_YOU = "engrid-iframe-queue:thank-you";
+/** Wire-format type for an error message sent iframe β parent. */
+const MSG_ERROR = "engrid-iframe-queue:error";
+/** Default per-item timeout in milliseconds. */
+const DEFAULT_TIMEOUT_MS = 30000;
+/**
+ * Parameters that are automatically inherited from the parent page
+ * onto each queued iframe URL. These are all ENgrid loader / dev-mode
+ * flags β adding them to the parent is meant to affect "the ENgrid
+ * bundle running on this browser tab," which conceptually includes
+ * the embedded forms loaded by the queue.
+ *
+ * For each key, the value is resolved with the same precedence used by
+ * `loader.ts#getOption`:
+ * 1. The item's own URL β if the consumer hard-coded the param on
+ * the iframe URL, that wins.
+ * 2. The parent page's URL parameter (`?assets=local`).
+ * 3. `window.EngridLoader[key]` on the parent page β useful when EN
+ * strips URL params on the Thank You page, so themes set
+ * ``
+ * to pin the bundle source.
+ *
+ * Notable use case: any of the three works for forcing local-asset
+ * loading on every queued QCB iframe during testing.
+ */
+const PROPAGATED_PARENT_PARAMS = [
+ "assets",
+ "engridjs",
+ "engridcss",
+ "repo-name",
+ "repo-owner",
+ "debug",
+ "mode",
+];
+/** Default visually-hidden style for queue iframes. */
+const DEFAULT_HIDDEN_STYLE = {
+ position: "absolute",
+ width: "1px",
+ height: "1px",
+ left: "-9999px",
+ top: "0",
+ opacity: "0",
+ border: "0",
+};
+class IframeQueue {
+ /**
+ * Returns the shared IframeQueue singleton. The bootstrap in app.ts
+ * instantiates this once via `new IframeQueue()`, but consumers that
+ * need to enqueue items programmatically should always go through
+ * `getInstance()` so they share the same queue state.
+ */
+ static getInstance() {
+ if (!IframeQueue.instance) {
+ IframeQueue.instance = new IframeQueue();
+ }
+ return IframeQueue.instance;
+ }
+ constructor() {
+ this.logger = new logger_EngridLogger("IframeQueue", "white", "#1f6feb", "π");
+ this.events = iframe_queue_events_IframeQueueEvents.getInstance();
+ this._form = en_form_EnForm.getInstance();
+ this.queue = [];
+ this._isProcessing = false;
+ this._aborted = false;
+ this.inFlightPromise = null;
+ // Singleton guard: if called via `new IframeQueue()` after an
+ // instance already exists (e.g. by app.ts), return the existing
+ // instance so behaviour stays consistent with `getInstance()`.
+ if (IframeQueue.instance) {
+ return IframeQueue.instance;
}
- else {
- return "UNKNOWN";
+ IframeQueue.instance = this;
+ if (this.inIframe()) {
+ this.setupEmbeddedMode();
}
- }
- // Set body engrid data attributes
- static setBodyData(dataName, value) {
- const body = document.querySelector("body");
- // If value is boolean
- if (typeof value === "boolean" && value === false) {
- body.removeAttribute(`data-engrid-${dataName}`);
- return;
+ else {
+ this.setupParentMode();
}
- body.setAttribute(`data-engrid-${dataName}`, value.toString());
}
- // Get body engrid data attributes
- static getBodyData(dataName) {
- const body = document.querySelector("body");
- return body.getAttribute(`data-engrid-${dataName}`);
- }
- // Check if body has engrid data attributes
- static hasBodyData(dataName) {
- const body = document.querySelector("body");
- return body.hasAttribute(`data-engrid-${dataName}`);
+ // ---------------------------------------------------------------------------
+ // Public API (parent mode)
+ // ---------------------------------------------------------------------------
+ /** Whether the queue is currently processing. */
+ get isProcessing() {
+ return this._isProcessing;
}
- // Return the option value
- static getOption(key) {
- return window.EngridOptions[key] || null;
+ /** Number of items currently in the queue (not counting the in-flight item). */
+ get size() {
+ return this.queue.length;
}
- // Load an external script
- static loadJS(url, onload = null, head = true) {
- const scriptTag = document.createElement("script");
- scriptTag.src = url;
- scriptTag.onload = onload;
- if (head) {
- document.head.appendChild(scriptTag);
+ /**
+ * Add an item to the back of the queue. Items are processed in
+ * insertion order. Calling `enqueue` while the queue is processing is
+ * supported β the new item joins the chain and will be picked up
+ * after the current item completes.
+ */
+ enqueue(item) {
+ if (!item || typeof item.url !== "string" || !item.url) {
+ this.logger.danger("enqueue() called with invalid item; ignoring");
return;
}
- document.body.appendChild(scriptTag);
- return;
- }
- // Format a number
- static formatNumber(number, decimals = 2, dec_point = ".", thousands_sep = ",") {
- // Strip all characters but numerical ones.
- number = (number + "").replace(/[^0-9+\-Ee.]/g, "");
- const n = !isFinite(+number) ? 0 : +number;
- const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
- const sep = typeof thousands_sep === "undefined" ? "," : thousands_sep;
- const dec = typeof dec_point === "undefined" ? "." : dec_point;
- let s = [];
- const toFixedFix = function (n, prec) {
- const k = Math.pow(10, prec);
- return "" + Math.round(n * k) / k;
- };
- // Fix for IE parseFloat(0.55).toFixed(0) = 0;
- s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split(".");
- if (s[0].length > 3) {
- s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
- }
- if ((s[1] || "").length < prec) {
- s[1] = s[1] || "";
- s[1] += new Array(prec - s[1].length + 1).join("0");
- }
- return s.join(dec);
+ this.queue.push(item);
+ this.logger.log(`enqueue: ${item.url} (queue size = ${this.queue.length})`);
}
- // Clean an Amount
- static cleanAmount(amount) {
- // Split the number
- const valueArray = amount.replace(/[^0-9,\.]/g, "").split(/[,.]+/);
- const delimArray = amount.replace(/[^.,]/g, "").split("");
- // Handle values with no decimal places and non-numeric values
- if (valueArray.length === 1) {
- return parseInt(valueArray[0]) || 0;
- }
- // Ignore invalid numbers
- if (valueArray
- .map((x, index) => {
- return index > 0 && index + 1 !== valueArray.length && x.length !== 3
- ? true
- : false;
- })
- .includes(true)) {
- return 0;
- }
- // Multiple commas is a bad thing? So edgy.
- if (delimArray.length > 1 && !delimArray.includes(".")) {
- return 0;
- }
- // Handle invalid decimal and comma formatting
- if ([...new Set(delimArray.slice(0, -1))].length > 1) {
- return 0;
- }
- // If there are cents
- if (valueArray[valueArray.length - 1].length <= 2) {
- const cents = valueArray.pop() || "00";
- return parseInt(cents) > 0
- ? parseFloat(Number(parseInt(valueArray.join("")) + "." + cents).toFixed(2))
- : parseInt(valueArray.join(""));
- }
- return parseInt(valueArray.join(""));
+ /**
+ * Add many items at once, preserving order. Equivalent to calling
+ * {@link enqueue} repeatedly.
+ */
+ enqueueAll(items) {
+ if (!Array.isArray(items))
+ return;
+ for (const item of items)
+ this.enqueue(item);
}
- static disableSubmit(label = "") {
- const submit = document.querySelector(".en__submit button");
- if (!submit)
- return false;
- let submitButtonProcessingHTML = `${label} `;
- if (submit.innerHTML.includes("loader-wrapper")) {
- // If we are already processing, don't override the originalText again
- return false;
+ /**
+ * Begin processing the queue. Resolves when the queue drains
+ * successfully and rejects on the first error. If already processing,
+ * returns the in-flight promise so callers don't start a second drain.
+ */
+ process() {
+ if (this._isProcessing && this.inFlightPromise) {
+ this.logger.log("process: already processing; returning in-flight promise");
+ return this.inFlightPromise;
}
- submit.dataset.originalText = submit.innerHTML;
- submit.disabled = true;
- submit.innerHTML = submitButtonProcessingHTML;
- return true;
- }
- static enableSubmit() {
- const submit = document.querySelector(".en__submit button");
- if (!submit)
- return false;
- if (submit.dataset.originalText) {
- submit.disabled = false;
- submit.innerHTML = submit.dataset.originalText;
- delete submit.dataset.originalText;
- return true;
+ if (this.queue.length === 0) {
+ this.logger.log("process: queue empty; nothing to do");
+ return Promise.resolve();
}
- return false;
- }
- static formatDate(date, format = "MM/DD/YYYY") {
- const dateAray = date
- .toLocaleDateString("en-US", {
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
+ this._aborted = false;
+ this._isProcessing = true;
+ this.inFlightPromise = this.drain()
+ .then(() => {
+ this.events.dispatchChainComplete();
})
- .split("/");
- const dateString = format
- .replace(/YYYY/g, dateAray[2])
- .replace(/MM/g, dateAray[0])
- .replace(/DD/g, dateAray[1])
- .replace(/YY/g, dateAray[2].substr(2, 2));
- return dateString;
+ .finally(() => {
+ this._isProcessing = false;
+ this.inFlightPromise = null;
+ });
+ return this.inFlightPromise;
}
/**
- * Check if the provided object has ALL the provided properties
- * Example: checkNested(EngagingNetworks, 'require', '_defined', 'enjs', 'checkSubmissionFailed')
- * will return true if EngagingNetworks.require._defined.enjs.checkSubmissionFailed is defined
+ * Empty the queue without processing. Stops the in-flight item if
+ * any (the in-flight item rejects with an abort error which is
+ * surfaced via `onChainError`).
*/
- static checkNested(obj, ...args) {
- for (let i = 0; i < args.length; i++) {
- if (!obj || !obj.hasOwnProperty(args[i])) {
- return false;
- }
- obj = obj[args[i]];
- }
- return true;
+ clear() {
+ this.logger.log(`clear: dropping ${this.queue.length} queued item(s)`);
+ this.queue = [];
+ this._aborted = true;
}
- // Deep merge two objects
- static deepMerge(target, source) {
- for (const key in source) {
- if (source[key] instanceof Object)
- Object.assign(source[key], engrid_ENGrid.deepMerge(target[key], source[key]));
+ // ---------------------------------------------------------------------------
+ // Parent-mode internals
+ // ---------------------------------------------------------------------------
+ /**
+ * In parent mode the constructor checks `window.EngridIframeQueue`
+ * for declarative startup config, enqueues those items, and (if
+ * `autoStart` is true) calls `process()` after DOMContentLoaded.
+ */
+ setupParentMode() {
+ this.logger.log("setupParentMode");
+ const config = this.readWindowConfig();
+ if (!config)
+ return;
+ if (Array.isArray(config.items) && config.items.length > 0) {
+ this.enqueueAll(config.items);
}
- Object.assign(target || {}, source);
- return target;
- }
- static setError(element, errorMessage) {
- const errorElement = typeof element === "string" ? document.querySelector(element) : element;
- if (errorElement) {
- errorElement.classList.add("en__field--validationFailed");
- let errorMessageElement = errorElement.querySelector(".en__field__error");
- if (!errorMessageElement) {
- errorMessageElement = document.createElement("div");
- errorMessageElement.classList.add("en__field__error");
- errorMessageElement.innerHTML = errorMessage;
- errorElement.insertBefore(errorMessageElement, errorElement.firstChild);
- }
- else {
- errorMessageElement.innerHTML = errorMessage;
- }
+ const shouldAutoStart = typeof config.autoStart === "boolean"
+ ? config.autoStart
+ : this.queue.length > 0;
+ if (!shouldAutoStart || this.queue.length === 0)
+ return;
+ const start = () => {
+ this.process().catch((err) => {
+ this.logger.danger(`Auto-started queue rejected: ${err}`);
+ });
+ };
+ if (document.readyState !== "loading") {
+ start();
}
- }
- static removeError(element) {
- const errorElement = typeof element === "string" ? document.querySelector(element) : element;
- if (errorElement) {
- errorElement.classList.remove("en__field--validationFailed");
- const errorMessageElement = errorElement.querySelector(".en__field__error");
- if (errorMessageElement) {
- errorElement.removeChild(errorMessageElement);
- }
+ else {
+ document.addEventListener("DOMContentLoaded", start);
}
}
- static isVisible(element) {
- if (!element) {
- return false;
- }
- return !!(element.offsetWidth ||
- element.offsetHeight ||
- element.getClientRects().length);
+ /**
+ * Reads `window.EngridIframeQueue` and returns merged options, or
+ * null if no valid config is present.
+ */
+ readWindowConfig() {
+ const raw = window
+ .EngridIframeQueue;
+ if (!raw || typeof raw !== "object")
+ return null;
+ return Object.assign(Object.assign({}, iframe_queue_options_IframeQueueOptionsDefaults), raw);
}
- static getCurrencySymbol() {
- const currencyField = engrid_ENGrid.getField("transaction.paycurrency");
- if (currencyField) {
- // Check if the selected currency field option have a data-currency-symbol attribute
- const selectedOption = currencyField.tagName === "SELECT"
- ? currencyField.options[currencyField.selectedIndex]
- : currencyField;
- if (selectedOption.dataset.currencySymbol) {
- return selectedOption.dataset.currencySymbol;
+ /** Process queued items strictly one at a time. */
+ drain() {
+ var _a;
+ return iframe_queue_awaiter(this, void 0, void 0, function* () {
+ while (this.queue.length > 0) {
+ if (this._aborted) {
+ this.logger.log("drain: aborted; stopping");
+ return;
+ }
+ const item = this.queue.shift();
+ try {
+ yield this.processItem(item);
+ }
+ catch (err) {
+ const error = err instanceof Error ? err : new Error(String(err));
+ this.events.dispatchItemError(item, error);
+ try {
+ (_a = item.onError) === null || _a === void 0 ? void 0 : _a.call(item, error);
+ }
+ catch (cbErr) {
+ this.logger.danger(`onError callback threw: ${cbErr}`);
+ }
+ this.events.dispatchChainError({
+ message: error.message,
+ failedItem: item,
+ cause: error,
+ });
+ // Abort the rest of the chain.
+ this.queue = [];
+ throw error;
+ }
}
- const currencyArray = {
- USD: "$",
- EUR: "β¬",
- GBP: "Β£",
- AUD: "$",
- CAD: "$",
- JPY: "Β₯",
+ });
+ }
+ /**
+ * Process a single item: create the iframe, post populate, wait for
+ * the matching Thank-You ping (or error/timeout). Resolves on success
+ * and rejects on error/timeout.
+ */
+ processItem(item) {
+ return new Promise((resolve, reject) => {
+ var _a, _b;
+ const url = this.prepareIframeUrl(item.url);
+ const expectedPageId = engrid_ENGrid.getPageIdFromUrl(url);
+ if (!expectedPageId) {
+ reject(new Error(`IframeQueue: could not parse Page ID from URL "${item.url}".`));
+ return;
+ }
+ this.events.dispatchItemStart(item);
+ const container = (_a = item.container) !== null && _a !== void 0 ? _a : document.body;
+ const iframe = this.createIframe(url, item.iframeStyle);
+ const timeoutMs = (_b = item.timeout) !== null && _b !== void 0 ? _b : DEFAULT_TIMEOUT_MS;
+ let settled = false;
+ let timeoutId = null;
+ const detachListeners = () => {
+ if (timeoutId !== null) {
+ window.clearTimeout(timeoutId);
+ timeoutId = null;
+ }
+ window.removeEventListener("message", onMessage);
+ iframe.removeEventListener("load", onIframeLoad);
+ iframe.removeEventListener("error", onIframeError);
};
- return currencyArray[currencyField.value] || "$";
- }
- return engrid_ENGrid.getOption("CurrencySymbol") || "$";
+ const removeIframe = () => {
+ if (iframe.parentNode) {
+ iframe.parentNode.removeChild(iframe);
+ }
+ };
+ const succeed = () => {
+ var _a;
+ if (settled)
+ return;
+ settled = true;
+ detachListeners();
+ removeIframe();
+ this.events.dispatchItemComplete(item);
+ try {
+ (_a = item.onComplete) === null || _a === void 0 ? void 0 : _a.call(item);
+ }
+ catch (cbErr) {
+ this.logger.danger(`onComplete callback threw: ${cbErr}`);
+ }
+ resolve();
+ };
+ const fail = (error) => {
+ if (settled)
+ return;
+ settled = true;
+ detachListeners();
+ if (this.shouldKeepIframeOnError(item)) {
+ this.markIframeFailed(iframe, error);
+ this.logger.danger(`Item failed β iframe kept in DOM for inspection: ${error.message}`);
+ }
+ else {
+ removeIframe();
+ }
+ reject(error);
+ };
+ const onMessage = (event) => {
+ var _a;
+ // Only accept messages from this specific iframe β origin
+ // string matching is unreliable because EN may serve embedded
+ // pages from different subdomains. `event.source` identity is
+ // what matters here.
+ if (event.source !== iframe.contentWindow)
+ return;
+ const data = event.data;
+ if (!data || typeof data !== "object" || !data.type)
+ return;
+ if (data.type === MSG_THANK_YOU) {
+ if (data.pageId !== expectedPageId) {
+ this.logger.log(`Ignoring thank-you ping with mismatched pageId ` +
+ `(expected ${expectedPageId}, got ${data.pageId})`);
+ return;
+ }
+ this.logger.log(`Item complete: ${url} (pageId ${expectedPageId})`);
+ succeed();
+ }
+ else if (data.type === MSG_ERROR) {
+ if (data.pageId !== expectedPageId)
+ return;
+ fail(new Error(`IframeQueue: embedded page reported error: ${(_a = data.message) !== null && _a !== void 0 ? _a : "unknown error"}`));
+ }
+ };
+ const onIframeLoad = () => {
+ var _a, _b;
+ if (settled)
+ return;
+ const populate = {
+ type: MSG_POPULATE,
+ pageId: expectedPageId,
+ fields: (_a = item.fields) !== null && _a !== void 0 ? _a : {},
+ autoSubmit: item.autoSubmit !== false, // default true
+ };
+ this.logger.log(`Posting populate to iframe (pageId=${expectedPageId}, ` +
+ `fieldCount=${Object.keys(populate.fields).length}, ` +
+ `autoSubmit=${populate.autoSubmit})`);
+ // Use "*" for the same reason origin matching is skipped on
+ // inbound messages β EN may serve embedded pages from a
+ // different subdomain than the host page.
+ (_b = iframe.contentWindow) === null || _b === void 0 ? void 0 : _b.postMessage(populate, "*");
+ };
+ const onIframeError = () => {
+ fail(new Error(`IframeQueue: iframe failed to load: ${url}`));
+ };
+ window.addEventListener("message", onMessage);
+ iframe.addEventListener("load", onIframeLoad);
+ iframe.addEventListener("error", onIframeError);
+ timeoutId = window.setTimeout(() => {
+ fail(new Error(`IframeQueue: timed out after ${timeoutMs}ms waiting for ` +
+ `Thank-You-page ping from ${url}`));
+ }, timeoutMs);
+ this.logger.log(`Item start: ${url} (pageId ${expectedPageId}, timeout ${timeoutMs}ms)`);
+ container.appendChild(iframe);
+ });
}
- static getCurrencyCode() {
- const currencyField = engrid_ENGrid.getField("transaction.paycurrency");
- if (currencyField) {
- return currencyField.value || "USD";
+ /**
+ * Normalise the URL for a queued iframe:
+ * 1. Strip any `chain` query parameter defensively β the queue
+ * replaces `?chain` with sequential processing.
+ * 2. Inherit a small allowlist of loader / dev-mode params (see
+ * {@link PROPAGATED_PARENT_PARAMS}) when they're not already set
+ * on the item URL. Each key is resolved with the same precedence
+ * `loader.ts#getOption` uses: parent URL param first, then
+ * `window.EngridLoader[key]`.
+ *
+ * Item-specified params always take precedence over inherited ones.
+ * Returns the original string unchanged if URL parsing fails.
+ */
+ prepareIframeUrl(rawUrl) {
+ let url;
+ try {
+ url = new URL(rawUrl, window.location.href);
}
- return engrid_ENGrid.getOption("CurrencyCode") || "USD";
- }
- static addHtml(html, target = "body", position = "before") {
- var _a, _b;
- const targetElement = document.querySelector(target);
- if (typeof html === "object") {
- html = html.outerHTML;
+ catch (_a) {
+ return rawUrl;
}
- if (targetElement) {
- const htmlElement = document.createRange().createContextualFragment(html);
- if (position === "before") {
- (_a = targetElement.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(htmlElement, targetElement);
+ url.searchParams.delete("chain");
+ const parentUrlParams = this.getParentSearchParams();
+ const parentLoader = this.getParentEngridLoader();
+ const inherited = [];
+ for (const key of PROPAGATED_PARENT_PARAMS) {
+ if (url.searchParams.has(key))
+ continue;
+ let value = null;
+ let source = "";
+ if (parentUrlParams) {
+ const v = parentUrlParams.get(key);
+ if (v !== null) {
+ value = v;
+ source = "url";
+ }
+ }
+ if (value === null && parentLoader) {
+ const v = parentLoader[key];
+ if (typeof v === "string" && v !== "") {
+ value = v;
+ source = "EngridLoader";
+ }
}
- else {
- (_b = targetElement.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(htmlElement, targetElement.nextSibling);
+ if (value !== null) {
+ url.searchParams.set(key, value);
+ inherited.push(`${key}=${value} (from parent ${source})`);
}
}
+ if (inherited.length > 0) {
+ this.logger.log(`Inherited parent params on iframe URL: ${inherited.join(", ")}`);
+ }
+ return url.href;
}
- static removeHtml(target) {
- const targetElement = document.querySelector(target);
- if (targetElement) {
- targetElement.remove();
+ /** Returns the parent page's URLSearchParams, or null on failure. */
+ getParentSearchParams() {
+ try {
+ return new URL(window.location.href).searchParams;
+ }
+ catch (_a) {
+ return null;
}
}
- static slugify(text) {
- return text
- .toString()
- .toLowerCase()
- .replace(/\s+/g, "-") // Replace spaces with -
- .replace(/[^\w\-]+/g, "") // Remove all non-word chars
- .replace(/\-\-+/g, "-") // Replace multiple - with single -
- .replace(/^-+/, "") // Trim - from start of text
- .replace(/-+$/, ""); // Trim - from end of text
+ /**
+ * Returns the parent page's `window.EngridLoader` object if set, or
+ * null. Used by {@link prepareIframeUrl} as a fallback source for
+ * loader/dev-mode param values when EN has stripped URL parameters
+ * from the Thank You page.
+ */
+ getParentEngridLoader() {
+ const w = window;
+ if (!w.EngridLoader || typeof w.EngridLoader !== "object")
+ return null;
+ return w.EngridLoader;
}
- // This function is used to run a callback function when an error is displayed on the page
- static watchForError(callback) {
- const errorElement = document.querySelector(".en__errorList");
- const capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
- // Avoid duplicate callbacks
- let callbackType = callback.toString();
- if (callbackType.indexOf("function") === 0) {
- callbackType = callbackType.replace("function ", "");
- }
- if (callbackType.indexOf("(") > 0) {
- callbackType = callbackType.substring(0, callbackType.indexOf("("));
+ /**
+ * Decide whether to leave a failed iframe in the DOM (for
+ * inspection) instead of removing it. True when the item explicitly
+ * asks for it via `keepIframeOnError`, OR whenever ENgrid debug
+ * mode is on (since debugging is when this is useful and we don't
+ * want to make consumers opt in just to inspect failures).
+ */
+ shouldKeepIframeOnError(item) {
+ if (item.keepIframeOnError)
+ return true;
+ try {
+ return engrid_ENGrid.debug === true;
}
- // Remove invalid characters
- callbackType = callbackType.replace(/[^a-zA-Z0-9]/g, "");
- // Limit to 20 characters and add prefix
- callbackType = callbackType.substring(0, 20);
- callbackType = "engrid" + capitalize(callbackType);
- if (errorElement && !errorElement.dataset[callbackType]) {
- errorElement.dataset[callbackType] = "true";
- const observer = new MutationObserver(function (mutations) {
- mutations.forEach(function (mutation) {
- if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
- callback();
- }
- });
- });
- observer.observe(errorElement, { childList: true });
+ catch (_a) {
+ return false;
}
}
- // Get the Payment Type
- static getPaymentType() {
- return engrid_ENGrid.getFieldValue("transaction.paymenttype");
+ /**
+ * Reposition and style a failed iframe so it's visible in the
+ * viewport (overriding the visually-hidden default), and tag it
+ * with a class + tooltip so the developer knows why it's there.
+ * Right-click the iframe β Inspect frame to dive in.
+ */
+ markIframeFailed(iframe, error) {
+ Object.assign(iframe.style, {
+ position: "fixed",
+ top: "10px",
+ right: "10px",
+ bottom: "auto",
+ left: "auto",
+ width: "min(600px, 90vw)",
+ height: "min(500px, 80vh)",
+ opacity: "1",
+ zIndex: "99999",
+ border: "3px solid #d33",
+ background: "white",
+ boxShadow: "0 4px 24px rgba(0, 0, 0, 0.25)",
+ });
+ iframe.classList.add("engrid-iframe--queue-failed");
+ iframe.title = `Iframe Queue: failed item β ${error.message}`;
}
- // Set the Payment Type
- static setPaymentType(paymentType) {
- const enFieldPaymentType = engrid_ENGrid.getField("transaction.paymenttype");
- if (enFieldPaymentType) {
- const paymentTypeOption = Array.from(enFieldPaymentType.options).find((option) => paymentType.toLowerCase() === "card"
- ? ["card", "visa", "vi"].includes(option.value.toLowerCase())
- : paymentType.toLowerCase() === option.value.toLowerCase());
- if (paymentTypeOption) {
- paymentTypeOption.selected = true;
- enFieldPaymentType.value = paymentTypeOption.value;
- }
- else {
- enFieldPaymentType.value = paymentType;
- }
- const event = new Event("change", {
- bubbles: true,
- cancelable: true,
- });
- enFieldPaymentType.dispatchEvent(event);
- }
+ /** Create a hidden iframe element for a queue item. */
+ createIframe(url, styleOverride) {
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("src", url);
+ iframe.setAttribute("frameborder", "0");
+ iframe.setAttribute("scrolling", "no");
+ iframe.setAttribute("aria-hidden", "true");
+ iframe.setAttribute("title", "ENgrid Iframe Queue");
+ iframe.classList.add("engrid-iframe", "engrid-iframe--queue");
+ const style = Object.assign(Object.assign({}, DEFAULT_HIDDEN_STYLE), (styleOverride !== null && styleOverride !== void 0 ? styleOverride : {}));
+ Object.assign(iframe.style, style);
+ return iframe;
}
- static isInViewport(element) {
- const rect = element.getBoundingClientRect();
- return (rect.top >= 0 &&
- rect.left >= 0 &&
- rect.bottom <=
- (window.innerHeight ||
- document.documentElement.clientHeight) /* or $(window).height() */ &&
- rect.right <=
- (window.innerWidth ||
- document.documentElement.clientWidth) /* or $(window).width() */);
+ // ---------------------------------------------------------------------------
+ // Embedded-mode internals
+ // ---------------------------------------------------------------------------
+ /**
+ * In embedded mode we register a `message` listener that accepts
+ * populate messages from `window.parent`, fills form fields, and
+ * (optionally) submits. The Thank-You-page ping is sent by the iFrame
+ * component (iframe.ts) β not here β so this method does not need to
+ * concern itself with completion signalling.
+ */
+ setupEmbeddedMode() {
+ this.logger.log("setupEmbeddedMode");
+ window.addEventListener("message", (event) => {
+ if (event.source !== window.parent)
+ return;
+ const data = event.data;
+ if (!data || typeof data !== "object" || data.type !== MSG_POPULATE) {
+ return;
+ }
+ this.handlePopulate(data);
+ });
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/donation-frequency.js
-
-
-class DonationFrequency {
- constructor() {
- this._onFrequencyChange = new dist/* SimpleEventDispatcher */.IL();
- this._frequency = "onetime";
- this._recurring = "n";
- this._dispatch = true;
- // Watch the Radios for Changes
- document.addEventListener("change", (e) => {
- const element = e.target;
- if (element && element.name == "transaction.recurrpay") {
- this.recurring = element.value;
- // When this element is a radio, that means you're between onetime and monthly only
- if (element.type == "radio") {
- this.frequency =
- element.value.toLowerCase() == "n" ? "onetime" : "monthly";
- // This field is hidden when transaction.recurrpay is radio
- engrid_ENGrid.setFieldValue("transaction.recurrfreq", this.frequency.toUpperCase());
- }
+ /** Handle a populate message sent by an IframeQueue parent. */
+ handlePopulate(data) {
+ var _a, _b;
+ const fields = (_a = data.fields) !== null && _a !== void 0 ? _a : {};
+ const autoSubmit = data.autoSubmit !== false;
+ this.logger.log(`Received populate (pageId=${data.pageId}, ` +
+ `fieldCount=${Object.keys(fields).length}, autoSubmit=${autoSubmit})`);
+ try {
+ for (const [name, value] of Object.entries(fields)) {
+ // Pass `dispatchEvents = true` so each field fires
+ // `change` + `blur` after the value is set. Without that,
+ // EN's form-validation state machine doesn't see the new
+ // values and leaves `en__submit--disabled` on the submit
+ // button, causing the auto-click below to no-op.
+ engrid_ENGrid.setFieldValue(name, value, true, true);
}
- if (element && element.name == "transaction.recurrfreq") {
- this.frequency = element.value;
+ if (autoSubmit) {
+ // Defer slightly so any synchronous EN dependency parsing in
+ // setFieldValue settles before the form is submitted.
+ window.setTimeout(() => {
+ // Belt-and-braces: clear EN's "submit disabled" state in
+ // case its validators didn't re-evaluate (e.g. async
+ // validators that hadn't completed when the events fired).
+ this.forceEnableSubmitButton();
+ this._form.submitForm();
+ }, 0);
}
- });
- //Thank you page handling for utility classes
- if (engrid_ENGrid.getGiftProcess()) {
- engrid_ENGrid.setBodyData("transaction-recurring-frequency", sessionStorage.getItem("engrid-transaction-recurring-frequency") ||
- "onetime");
- engrid_ENGrid.setBodyData("transaction-recurring", window.pageJson.recurring ? "y" : "n");
}
- }
- static getInstance() {
- if (!DonationFrequency.instance) {
- DonationFrequency.instance = new DonationFrequency();
+ catch (err) {
+ const error = err instanceof Error ? err : new Error(String(err));
+ this.logger.danger(`handlePopulate failed: ${error.message}`);
+ window.parent.postMessage({
+ type: MSG_ERROR,
+ pageId: (_b = data.pageId) !== null && _b !== void 0 ? _b : engrid_ENGrid.getPageID(),
+ message: error.message,
+ }, "*");
}
- return DonationFrequency.instance;
- }
- get frequency() {
- return this._frequency;
- }
- // Every time we set a frequency, trigger the onFrequencyChange event
- set frequency(value) {
- this._frequency = value.toLowerCase() || "onetime";
- if (this._dispatch)
- this._onFrequencyChange.dispatch(this._frequency);
- engrid_ENGrid.setBodyData("transaction-recurring-frequency", this._frequency);
- sessionStorage.setItem("engrid-transaction-recurring-frequency", this._frequency);
- }
- get recurring() {
- return this._recurring;
- }
- set recurring(value) {
- this._recurring = value.toLowerCase() || "n";
- engrid_ENGrid.setBodyData("transaction-recurring", this._recurring);
- }
- get onFrequencyChange() {
- return this._onFrequencyChange.asEvent();
}
- // Set amount var with currently selected amount
- load() {
- var _a;
- this.frequency =
- engrid_ENGrid.getFieldValue("transaction.recurrfreq") ||
- sessionStorage.getItem("engrid-transaction-recurring-frequency") ||
- "onetime";
- const recurrField = engrid_ENGrid.getField("transaction.recurrpay");
- if (recurrField) {
- this.recurring = engrid_ENGrid.getFieldValue("transaction.recurrpay");
- }
- else if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getSupporterData")) {
- this.recurring =
- ((_a = window.EngagingNetworks.require._defined.enjs
- .getSupporterData("recurrpay")) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "n";
+ /**
+ * Strip every "disabled" marker from the EN submit button so the
+ * programmatic `submitForm()` click is honoured. Removes:
+ * - the `disabled` DOM property/attribute on the button,
+ * - the `en__submit--disabled` BEM modifier (EN's own class),
+ * - the `en__submit--disabled` modifier on the `.en__submit`
+ * wrapper (some templates style the wrapper instead),
+ * - ENgrid's own loader markup if a previous `disableSubmit()`
+ * call left it in place.
+ *
+ * Used only by embedded-mode populate flow when `autoSubmit` is on.
+ */
+ forceEnableSubmitButton() {
+ const button = document.querySelector("form .en__submit button");
+ if (button) {
+ if (button.disabled)
+ button.disabled = false;
+ button.removeAttribute("disabled");
+ button.classList.remove("en__submit--disabled");
}
- // ENGrid.enParseDependencies();
- }
- // Force a new recurrency
- setRecurrency(recurr, dispatch = true) {
- // Run only if it is a Donation Page with a Recurrency
- if (!document.getElementsByName("transaction.recurrpay").length) {
- return;
+ const wrapper = document.querySelector(".en__submit");
+ if (wrapper) {
+ wrapper.classList.remove("en__submit--disabled");
}
- // Set dispatch to be checked by the SET method
- this._dispatch = dispatch;
- engrid_ENGrid.setFieldValue("transaction.recurrpay", recurr.toUpperCase());
- // Revert dispatch to default value (true)
- this._dispatch = true;
}
- // Force a new frequency
- setFrequency(freq, dispatch = true) {
- // Run only if it is a Donation Page with a Frequency
- if (!document.getElementsByName("transaction.recurrfreq").length) {
- return;
+ // ---------------------------------------------------------------------------
+ // Helpers
+ // ---------------------------------------------------------------------------
+ /** True when this script is executing inside an iframe. */
+ inIframe() {
+ try {
+ return window.self !== window.top;
}
- // Set dispatch to be checked by the SET method
- this._dispatch = dispatch;
- // Search for the current amount on radio boxes
- let found = Array.from(document.querySelectorAll('input[name="transaction.recurrfreq"]')).filter((el) => el instanceof HTMLInputElement && el.value == freq.toUpperCase());
- // We found the amount on the radio boxes, so check it
- if (found.length) {
- const freqField = found[0];
- freqField.checked = true;
- this.frequency = freq.toLowerCase();
- if (this.frequency === "onetime") {
- this.setRecurrency("N", dispatch);
- }
- else {
- this.setRecurrency("Y", dispatch);
- }
+ catch (_a) {
+ return true;
}
- // Revert dispatch to default value (true)
- this._dispatch = true;
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/processing-fees.js
-
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/input-has-value-and-focus.js
+// Component that adds has-value and has-focus classes to form inputs
-class ProcessingFees {
+class InputHasValueAndFocus {
constructor() {
- this._onFeeChange = new dist/* SimpleEventDispatcher */.IL();
- this._amount = DonationAmount.getInstance();
- this._form = en_form_EnForm.getInstance();
- this._fee = 0;
- this._field = null;
- // console.log('%c Processing Fees Constructor', 'font-size: 30px; background-color: #000; color: #FF0');
- // Run only if it is a Donation Page with a Donation Amount field
- if (!document.getElementsByName("transaction.donationAmt").length) {
- return;
- }
- this._field = this.isENfeeCover()
- ? document.querySelector("#en__field_transaction_feeCover")
- : document.querySelector('input[name="supporter.processing_fees"]');
- // Watch the Radios for Changes
- if (this._field instanceof HTMLInputElement) {
- // console.log('%c Processing Fees Start', 'font-size: 30px; background-color: #000; color: #FF0');
- this._field.addEventListener("change", (e) => {
- if (this._field instanceof HTMLInputElement &&
- this._field.checked &&
- !this._subscribe) {
- this._subscribe = this._form.onSubmit.subscribe(() => this.addFees());
- }
- this._onFeeChange.dispatch(this.fee);
- // // console.log('%c Processing Fees Script Applied', 'font-size: 30px; background-color: #000; color: #FF0');
- });
+ this.logger = new logger_EngridLogger("InputHasValueAndFocus", "yellow", "#333", "π");
+ this.formInputs = document.querySelectorAll(".en__field--text, .en__field--email:not(.en__field--checkbox), .en__field--telephone, .en__field--number, .en__field--textarea, .en__field--select, .en__field--checkbox");
+ if (this.shouldRun()) {
+ this.run();
}
- // this._amount = amount;
}
- static getInstance() {
- if (!ProcessingFees.instance) {
- ProcessingFees.instance = new ProcessingFees();
- }
- return ProcessingFees.instance;
+ shouldRun() {
+ return this.formInputs.length > 0;
}
- get onFeeChange() {
- return this._onFeeChange.asEvent();
+ run() {
+ this.formInputs.forEach((el) => {
+ const input = el.querySelector("input, textarea, select");
+ if (input && input.value) {
+ el.classList.add("has-value");
+ }
+ this.bindEvents(el);
+ });
}
- get fee() {
- return this.calculateFees();
+ bindEvents(el) {
+ const input = el.querySelector("input, textarea, select");
+ if (!input) {
+ return;
+ }
+ input.addEventListener("focus", () => {
+ this.log("Focus added", input);
+ el.classList.add("has-focus");
+ });
+ input.addEventListener("blur", () => {
+ this.log("Focus removed", input);
+ el.classList.remove("has-focus");
+ });
+ input.addEventListener("input", () => {
+ if (input.value) {
+ this.log("Value added", input);
+ el.classList.add("has-value");
+ }
+ else {
+ this.log("Value removed", input);
+ el.classList.remove("has-value");
+ }
+ });
}
- // Every time we set a frequency, trigger the onFrequencyChange event
- set fee(value) {
- this._fee = value;
- this._onFeeChange.dispatch(this._fee);
+ log(message, input) {
+ this.logger.log(`${message} on ${input.name}: ${input.value}`);
}
- calculateFees(amount = 0) {
- var _a;
- if (this._field instanceof HTMLInputElement && this._field.checked) {
- if (this.isENfeeCover()) {
- return amount > 0
- ? window.EngagingNetworks.require._defined.enjs.feeCover.fee(amount)
- : window.EngagingNetworks.require._defined.enjs.getDonationFee();
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/input-placeholders.js
+// Component that adds input placeholders
+// You can override the default placeholders by adding a Placeholders option to the EngridOptions on the client theme.
+// You can also add an EngridPageOptions override to the page, if you want to override the placeholders on a specific page. Example:
+//
+
+class InputPlaceholders {
+ constructor() {
+ this.defaultPlaceholders = {
+ "input#en__field_supporter_firstName": "First Name",
+ "input#en__field_supporter_lastName": "Last Name",
+ "input#en__field_supporter_emailAddress": "Email Address",
+ "input#en__field_supporter_phoneNumber": "Phone Number (Optional)",
+ ".en__mandatory input#en__field_supporter_phoneNumber": "Phone Number",
+ ".i-required input#en__field_supporter_phoneNumber": "Phone Number",
+ "input#en__field_supporter_phoneNumber2": "000-000-0000 (Optional)",
+ ".en__mandatory input#en__field_supporter_phoneNumber2": "000-000-0000",
+ ".i-required input#en__field_supporter_phoneNumber2": "000-000-0000",
+ "input#en__field_supporter_country": "Country",
+ "input#en__field_supporter_address1": "Street Address",
+ "input#en__field_supporter_address2": "Apt., Ste., Bldg.",
+ "input#en__field_supporter_city": "City",
+ "input#en__field_supporter_region": "Region",
+ "input#en__field_supporter_postcode": "ZIP Code",
+ ".en__field--donationAmt.en__field--withOther .en__field__input--other": "Other",
+ "input#en__field_transaction_ccexpire": "MM / YY",
+ "input#en__field_supporter_bankAccountNumber": "Bank Account Number",
+ "input#en__field_supporter_bankRoutingNumber": "Bank Routing Number",
+ "input#en__field_transaction_honname": "Honoree Name",
+ "input#en__field_transaction_infname": "Recipient Name",
+ "input#en__field_transaction_infemail": "Recipient Email Address",
+ "input#en__field_transaction_infcountry": "Country",
+ "input#en__field_transaction_infadd1": "Recipient Street Address",
+ "input#en__field_transaction_infadd2": "Recipient Apt., Ste., Bldg.",
+ "input#en__field_transaction_infcity": "Recipient City",
+ "input#en__field_transaction_infpostcd": "Recipient Postal Code",
+ "input#en__field_transaction_gftrsn": "Reason for your gift",
+ "input#en__field_transaction_shipfname": "Shipping First Name",
+ "input#en__field_transaction_shiplname": "Shipping Last Name",
+ "input#en__field_transaction_shipemail": "Shipping Email Address",
+ "input#en__field_transaction_shipcountry": "Shipping Country",
+ "input#en__field_transaction_shipadd1": "Shipping Street Address",
+ "input#en__field_transaction_shipadd2": "Shipping Apt., Ste., Bldg.",
+ "input#en__field_transaction_shipcity": "Shipping City",
+ "input#en__field_transaction_shipregion": "Shipping Region",
+ "input#en__field_transaction_shippostcode": "Shipping Postal Code",
+ "input#en__field_supporter_billingCountry": "Billing Country",
+ "input#en__field_supporter_billingAddress1": "Billing Street Address",
+ "input#en__field_supporter_billingAddress2": "Billing Apt., Ste., Bldg.",
+ "input#en__field_supporter_billingCity": "Billing City",
+ "input#en__field_supporter_billingRegion": "Billing Region",
+ "input#en__field_supporter_billingPostcode": "Billing Postal Code",
+ };
+ if (this.shouldRun()) {
+ // If there's a Placeholders option, merge it with the default placeholders
+ const placeholders = engrid_ENGrid.getOption("Placeholders");
+ if (placeholders) {
+ this.defaultPlaceholders = Object.assign(Object.assign({}, this.defaultPlaceholders), placeholders);
}
- const fees = Object.assign({
- processingfeepercentadded: "0",
- processingfeefixedamountadded: "0",
- }, (_a = this._field) === null || _a === void 0 ? void 0 : _a.dataset);
- const amountToFee = amount > 0 ? amount : this._amount.amount;
- const processing_fee = (parseFloat(fees.processingfeepercentadded) / 100) * amountToFee +
- parseFloat(fees.processingfeefixedamountadded);
- return Math.round(processing_fee * 100) / 100;
- }
- return 0;
- }
- // Add Fees to Amount
- addFees() {
- if (this._form.submit && !this.isENfeeCover()) {
- this._amount.setAmount(this._amount.amount + this.fee, false);
+ this.run();
}
}
- // Remove Fees From Amount
- removeFees() {
- if (!this.isENfeeCover())
- this._amount.setAmount(this._amount.amount - this.fee);
+ shouldRun() {
+ return engrid_ENGrid.hasBodyData("add-input-placeholders");
}
- // Check if this is a Processing Fee from EN
- isENfeeCover() {
- if ("feeCover" in window.EngagingNetworks) {
- for (const key in window.EngagingNetworks.feeCover) {
- if (window.EngagingNetworks.feeCover.hasOwnProperty(key)) {
- return true;
- }
- }
+ run() {
+ Object.keys(this.defaultPlaceholders).forEach((selector) => {
+ if (selector in this.defaultPlaceholders)
+ this.addPlaceholder(selector, this.defaultPlaceholders[selector]);
+ });
+ }
+ addPlaceholder(selector, placeholder) {
+ const fieldEl = document.querySelector(selector);
+ if (fieldEl) {
+ fieldEl.placeholder = placeholder;
}
- return false;
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/remember-me-events.js
-/**
- * This class is responsible for managing events related to the "Remember Me" functionality.
- * It uses the Singleton design pattern to ensure only one instance of this class exists.
- * It provides methods for dispatching load and clear events, and getters for accessing these events.
- */
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/media-attribution.js
+/*
+ Looks for specially crafted links and will transform its markup to display an attribution overlay on top of the image
+ Depends on "_engrid-media-attribution.scss" for styling
+ Example Image Input
+
+
+
-class RememberMeEvents {
+ Example Video Input (Doesn't currently visually display)
+ @TODO Video tags are processed but their is not visually displayed. Need to update "_engrid-media-attribution.scss"
+
+
+ Example Image Output
+ Jane Doe 1
+*/
+
+const tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
+class MediaAttribution {
constructor() {
- this.logger = new logger_EngridLogger("RememberMeEvents");
- this._onLoad = new dist/* SimpleEventDispatcher */.IL();
- this._onClear = new dist/* SignalDispatcher */.UD();
- this.hasData = false;
- }
- static getInstance() {
- if (!RememberMeEvents.instance) {
- RememberMeEvents.instance = new RememberMeEvents();
- }
- return RememberMeEvents.instance;
- }
- dispatchLoad(hasData) {
- this.hasData = hasData;
- this._onLoad.dispatch(hasData);
- this.logger.log(`dispatchLoad: ${hasData}`);
- }
- dispatchClear() {
- this._onClear.dispatch();
- this.logger.log("dispatchClear");
- }
- get onLoad() {
- return this._onLoad.asEvent();
- }
- get onClear() {
- return this._onClear.asEvent();
+ // Find all images with attribution but not with the "data-attribution-hide-overlay" attribute
+ this.mediaWithAttribution = document.querySelectorAll("img[data-attribution-source]:not([data-attribution-hide-overlay]), video[data-attribution-source]:not([data-attribution-hide-overlay])");
+ this.mediaWithAttribution.forEach((element) => {
+ if (engrid_ENGrid.debug)
+ console.log("The following image was found with data attribution fields on it. It's markup will be changed to add caption support.", element);
+ // Creates the wapping element
+ let figure = document.createElement("figure");
+ figure.classList.add("media-with-attribution");
+ // Moves the inside its element
+ let mediaWithAttributionParent = element.parentNode;
+ if (mediaWithAttributionParent) {
+ mediaWithAttributionParent.insertBefore(figure, element);
+ figure.appendChild(element);
+ let mediaWithAttributionElement = element;
+ // Append the element after the and conditionally add the Source's Link to it
+ let attributionSource = mediaWithAttributionElement.dataset.attributionSource;
+ if (attributionSource) {
+ let attributionSourceLink = mediaWithAttributionElement.dataset.attributionSourceLink;
+ if (attributionSourceLink) {
+ mediaWithAttributionElement.insertAdjacentHTML("afterend", '' +
+ attributionSource +
+ " ");
+ }
+ else {
+ mediaWithAttributionElement.insertAdjacentHTML("afterend", "" + attributionSource + " ");
+ }
+ const attributionSourceTooltip = "attributionSourceTooltip" in mediaWithAttributionElement.dataset
+ ? mediaWithAttributionElement.dataset.attributionSourceTooltip
+ : false;
+ if (attributionSourceTooltip) {
+ tippy(mediaWithAttributionElement.nextSibling, {
+ content: attributionSourceTooltip,
+ arrow: true,
+ arrowType: "default",
+ placement: "left",
+ trigger: "click mouseenter focus",
+ interactive: true,
+ });
+ }
+ }
+ }
+ });
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/iframe-queue-events.js
-/**
- * Singleton event hub for the Iframe Queue component.
- *
- * Mirrors the structure of RememberMeEvents: private constructor,
- * static `getInstance()`, internal dispatchers exposed via `.asEvent()`
- * getters, and `dispatch*` methods called by the IframeQueue class.
- *
- * External code subscribes to these events to react to queue
- * lifecycle without holding a reference to the IframeQueue itself.
- * The TNC Bequest Lightbox, for example, will subscribe to
- * `onChainComplete` so it only opens after the QCB opt-in chain has
- * finished submitting.
- *
- * @example
- * IframeQueueEvents.getInstance().onChainComplete.subscribe(() => {
- * openBequestLightbox();
- * });
- */
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/live-variables.js
-class iframe_queue_events_IframeQueueEvents {
- constructor() {
- this.logger = new EngridLogger("IframeQueueEvents");
- this._onChainComplete = new SignalDispatcher();
- this._onChainError = new SimpleEventDispatcher();
- this._onItemStart = new SimpleEventDispatcher();
- this._onItemComplete = new SimpleEventDispatcher();
- this._onItemError = new SimpleEventDispatcher();
- }
- /** Returns the shared IframeQueueEvents singleton. */
- static getInstance() {
- if (!iframe_queue_events_IframeQueueEvents.instance) {
- iframe_queue_events_IframeQueueEvents.instance = new iframe_queue_events_IframeQueueEvents();
- }
- return iframe_queue_events_IframeQueueEvents.instance;
- }
- /**
- * Fires once when the entire queue completes successfully.
- * Use to trigger work that must wait for all chained iframe submits
- * (e.g. opening a bequest lightbox after QCB opt-ins are recorded).
- */
- get onChainComplete() {
- return this._onChainComplete.asEvent();
- }
- /**
- * Fires when the queue aborts due to an error (timeout, iframe load
- * error, or error message from an embedded page). Carries the failed
- * item (if known) and the underlying error.
- */
- get onChainError() {
- return this._onChainError.asEvent();
+class LiveVariables {
+ constructor(options) {
+ var _a;
+ this._amount = DonationAmount.getInstance();
+ this._fees = ProcessingFees.getInstance();
+ this._frequency = DonationFrequency.getInstance();
+ this._form = en_form_EnForm.getInstance();
+ this.multiplier = 1 / 12;
+ this.options = Object.assign(Object.assign({}, OptionsDefaults), options);
+ this.submitLabel =
+ ((_a = document.querySelector(".en__submit button")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "Donate";
+ this._amount.onAmountChange.subscribe(() => this.changeSubmitButton());
+ this._amount.onAmountChange.subscribe(() => this.changeLiveAmount());
+ this._amount.onAmountChange.subscribe(() => this.changeLiveUpsellAmount());
+ this._fees.onFeeChange.subscribe(() => this.changeLiveAmount());
+ this._fees.onFeeChange.subscribe(() => this.changeLiveUpsellAmount());
+ this._fees.onFeeChange.subscribe(() => this.changeSubmitButton());
+ this._frequency.onFrequencyChange.subscribe(() => this.changeLiveFrequency());
+ this._frequency.onFrequencyChange.subscribe(() => this.changeRecurrency());
+ this._frequency.onFrequencyChange.subscribe(() => this.changeSubmitButton());
+ this._form.onSubmit.subscribe(() => {
+ if (engrid_ENGrid.getPageType() !== "SUPPORTERHUB")
+ engrid_ENGrid.disableSubmit("Processing...");
+ });
+ this._form.onError.subscribe(() => engrid_ENGrid.enableSubmit());
+ // Watch the monthly-upsell links
+ document.addEventListener("click", (e) => {
+ const element = e.target;
+ if (element) {
+ if (element.classList.contains("monthly-upsell")) {
+ this.upsold(e);
+ }
+ else if (element.classList.contains("form-submit")) {
+ e.preventDefault();
+ this._form.submitForm();
+ }
+ }
+ });
}
- /** Fires immediately before an item begins processing. */
- get onItemStart() {
- return this._onItemStart.asEvent();
+ getAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = this.options.DecimalSeparator) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = this.options.ThousandsSeparator) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = this.options.DecimalPlaces) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
+ return amount > 0
+ ? (`${symbol} ${amountTxt} `)
+ : "";
}
- /** Fires when an item completes (its iframe reached its Thank You page). */
- get onItemComplete() {
- return this._onItemComplete.asEvent();
+ getUpsellAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = this.options.DecimalSeparator) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = this.options.ThousandsSeparator) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = this.options.DecimalPlaces) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = engrid_ENGrid.formatNumber(Math.ceil(amount / 5) * 5, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? symbol + amountTxt : "";
}
- /** Fires when an item fails. The queue aborts after this event. */
- get onItemError() {
- return this._onItemError.asEvent();
+ getUpsellAmountRaw(amount = 0) {
+ const amountRaw = Math.ceil(amount / 5) * 5;
+ return amount > 0 ? amountRaw.toString() : "";
}
- /** Internal β called by IframeQueue when the queue drains successfully. */
- dispatchChainComplete() {
- this.logger.log("dispatchChainComplete");
- this._onChainComplete.dispatch();
+ changeSubmitButton() {
+ const submit = document.querySelector(".en__submit button");
+ const amount = this.getAmountTxt(this._amount.amount + this._fees.fee);
+ const frequency = this._frequency.frequency == "onetime"
+ ? ""
+ : this._frequency.frequency == "annual"
+ ? "annually"
+ : this._frequency.frequency;
+ let label = this.submitLabel;
+ if (amount) {
+ label = label.replace("$AMOUNT", amount);
+ label = label.replace("$FREQUENCY", `${frequency} `);
+ }
+ else {
+ label = label.replace("$AMOUNT", "");
+ label = label.replace("$FREQUENCY", "");
+ }
+ if (submit && label) {
+ submit.innerHTML = label;
+ }
}
- /** Internal β called by IframeQueue when the queue aborts on error. */
- dispatchChainError(payload) {
- this.logger.log(`dispatchChainError: ${payload.message}`);
- this._onChainError.dispatch(payload);
+ changeLiveAmount() {
+ const value = this._amount.amount + this._fees.fee;
+ const live_amount = document.querySelectorAll(".live-giving-amount");
+ live_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(value)));
}
- /** Internal β called by IframeQueue immediately before an item starts. */
- dispatchItemStart(item) {
- this.logger.log(`dispatchItemStart: ${item.url}`);
- this._onItemStart.dispatch(item);
+ changeLiveUpsellAmount() {
+ const value = (this._amount.amount + this._fees.fee) * this.multiplier;
+ const live_upsell_amount = document.querySelectorAll(".live-giving-upsell-amount");
+ live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getUpsellAmountTxt(value)));
+ const live_upsell_amount_raw = document.querySelectorAll(".live-giving-upsell-amount-raw");
+ live_upsell_amount_raw.forEach((elem) => (elem.innerHTML = this.getUpsellAmountRaw(value)));
}
- /** Internal β called by IframeQueue when an item finishes successfully. */
- dispatchItemComplete(item) {
- this.logger.log(`dispatchItemComplete: ${item.url}`);
- this._onItemComplete.dispatch(item);
+ changeLiveFrequency() {
+ const live_frequency = document.querySelectorAll(".live-giving-frequency");
+ live_frequency.forEach((elem) => (elem.innerHTML =
+ this._frequency.frequency == "onetime"
+ ? ""
+ : this._frequency.frequency));
}
- /** Internal β called by IframeQueue when an item errors. */
- dispatchItemError(item, error) {
- this.logger.log(`dispatchItemError: ${item.url} - ${error.message}`);
- this._onItemError.dispatch({ item, error });
+ changeRecurrency() {
+ const recurrpay = document.querySelector("[name='transaction.recurrpay']");
+ if (recurrpay && recurrpay.type != "radio") {
+ recurrpay.value = this._frequency.frequency == "onetime" ? "N" : "Y";
+ this._frequency.recurring = recurrpay.value;
+ if (engrid_ENGrid.getOption("Debug"))
+ console.log("Recurpay Changed!");
+ // Trigger the onChange event for the field
+ const event = new Event("change", { bubbles: true });
+ recurrpay.dispatchEvent(event);
+ }
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/country.js
-
-
-class Country {
- constructor() {
- this._onCountryChange = new dist/* SimpleEventDispatcher */.IL();
- this._country = "";
- this._field = null;
- // Run only if it is a Page with a Country field
- this._field = document.getElementById("en__field_supporter_country");
- if (!this._field) {
- return;
+ // Watch for a clicks on monthly-upsell link
+ upsold(e) {
+ // Find and select monthly giving
+ const enFieldRecurrpay = document.querySelector(".en__field--recurrpay input[value='Y']");
+ if (enFieldRecurrpay) {
+ enFieldRecurrpay.checked = true;
}
- document.addEventListener("change", (e) => {
- const element = e.target;
- if (element && element.name == "supporter.country") {
- this.country = element.value;
+ // Find the hidden radio select that needs to be selected when entering an "Other" amount
+ const enFieldOtherAmountRadio = document.querySelector(".en__field--donationAmt input[value='other']");
+ if (enFieldOtherAmountRadio) {
+ enFieldOtherAmountRadio.checked = true;
+ }
+ // Enter the other amount and remove the "en__field__item--hidden" class from the input's parent
+ const enFieldOtherAmount = document.querySelector("input[name='transaction.donationAmt.other']");
+ if (enFieldOtherAmount) {
+ enFieldOtherAmount.value = this.getUpsellAmountRaw(this._amount.amount * this.multiplier);
+ this._amount.load();
+ this._frequency.load();
+ if (enFieldOtherAmount.parentElement) {
+ enFieldOtherAmount.parentElement.classList.remove("en__field__item--hidden");
}
- });
- // Set the country to the current value on the field
- this.country = engrid_ENGrid.getFieldValue("supporter.country");
- }
- static getInstance() {
- if (!Country.instance) {
- Country.instance = new Country();
}
- return Country.instance;
- }
- get countryField() {
- return this._field;
- }
- get onCountryChange() {
- return this._onCountryChange.asEvent();
- }
- get country() {
- return this._country;
- }
- // Every time we set a country, trigger the onCountryChange event
- set country(value) {
- this._country = value;
- this._onCountryChange.dispatch(this._country);
+ const target = e.target;
+ if (target && target.classList.contains("form-submit")) {
+ e.preventDefault();
+ // Form submit
+ this._form.submitForm();
+ }
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/events/index.js
-
-
-
-
-
-
-
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/app.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/upsell-lightbox.js
-class App extends engrid_ENGrid {
- constructor(options) {
- super();
- // Events
+class UpsellLightbox {
+ constructor() {
+ this.overlay = document.createElement("div");
this._form = en_form_EnForm.getInstance();
+ this._amount = DonationAmount.getInstance();
this._fees = ProcessingFees.getInstance();
- this._amount = DonationAmount.getInstance("transaction.donationAmt", "transaction.donationAmt.other");
this._frequency = DonationFrequency.getInstance();
- this._country = Country.getInstance();
- this.logger = new logger_EngridLogger("App", "black", "white", "π");
- const loader = new Loader();
- this.options = Object.assign(Object.assign({}, OptionsDefaults), options);
- // Add Options to window
- window.EngridOptions = this.options;
this._dataLayer = DataLayer.getInstance();
- // If there's a ?pbedit query string, redirect to the page builder to edit on EN
- if (engrid_ENGrid.getUrlParameter("pbedit") === true ||
- engrid_ENGrid.getUrlParameter("pbedit") === "true") {
- window.location.href = `https://${engrid_ENGrid.getDataCenter()}.engagingnetworks.app/index.html#pages/${engrid_ENGrid.getPageID()}/edit`;
+ this._suggestAmount = 0;
+ this.logger = new logger_EngridLogger("UpsellLightbox", "black", "pink", "πͺ");
+ let options = "EngridUpsell" in window ? window.EngridUpsell : {};
+ this.options = Object.assign(Object.assign({}, UpsellOptionsDefaults), options);
+ //Disable for "applepay" via Vantiv payment method. Adding it to the array like this so it persists
+ //even if the client provides custom options.
+ this.options.disablePaymentMethods.push("applepay");
+ if (!this.shouldRun()) {
+ this.logger.log("Upsell script should NOT run");
+ // If we're not on a Donation Page, get out
return;
}
- if (loader.reload())
- return;
- // Turn Debug ON if you use local assets
- if (engrid_ENGrid.getBodyData("assets") === "local" &&
- engrid_ENGrid.getUrlParameter("debug") !== "false" &&
- engrid_ENGrid.getUrlParameter("debug") !== "log") {
- window.EngridOptions.Debug = true;
+ this.overlay.id = "enModal";
+ this.overlay.classList.add("is-hidden");
+ this.overlay.classList.add("image-" + this.options.imagePosition);
+ this.renderLightbox();
+ this._form.onSubmit.subscribe(() => this.open());
+ }
+ renderLightbox() {
+ const title = this.options.title
+ .replace("{new-amount}", " ")
+ .replace("{old-amount}", " ")
+ .replace("{old-frequency}", " ");
+ const paragraph = this.options.paragraph
+ .replace("{new-amount}", " ")
+ .replace("{old-amount}", " ")
+ .replace("{old-frequency}", " ");
+ const yes = this.options.yesLabel
+ .replace("{new-amount}", " ")
+ .replace("{old-amount}", " ")
+ .replace("{old-frequency}", " ");
+ const no = this.options.noLabel
+ .replace("{new-amount}", " ")
+ .replace("{old-amount}", " ")
+ .replace("{old-frequency}", " ");
+ const markup = `
+
+
+
+
+ ${this.options.canClose ? `
` : ``}
+
+ ${title}
+
+ ${this.options.otherAmount
+ ? `
+
+
+
+ ${this.options.otherLabel}
+
+
+
+
+ Minimum ${this.getAmountTxt(this.options.minAmount)}
+
+
+ `
+ : ``}
+
+
+ ${paragraph}
+
+
+
+
+
+
+
+ `;
+ this.overlay.innerHTML = markup;
+ const closeButton = this.overlay.querySelector("#goMonthlyClose");
+ const yesButton = this.overlay.querySelector("#upsellYesButton a");
+ const noButton = this.overlay.querySelector("#upsellNoButton button");
+ yesButton.addEventListener("click", this.continue.bind(this));
+ noButton.addEventListener("click", this.continue.bind(this));
+ if (closeButton)
+ closeButton.addEventListener("click", this.close.bind(this));
+ this.overlay.addEventListener("click", (e) => {
+ if (e.target instanceof Element &&
+ e.target.id == this.overlay.id &&
+ this.options.canClose) {
+ this.close(e);
+ }
+ });
+ document.addEventListener("keyup", (e) => {
+ if (e.key === "Escape" && closeButton) {
+ closeButton.click();
+ }
+ });
+ document.body.appendChild(this.overlay);
+ const otherField = document.querySelector("#secondOtherField");
+ if (otherField) {
+ otherField.addEventListener("keyup", this.popupOtherField.bind(this));
+ }
+ this.logger.log("Upsell script rendered");
+ }
+ // Should we run the script?
+ shouldRun() {
+ // if it's a first page of a Donation page
+ return (
+ // !hideModal &&
+ !this.shouldSkip() &&
+ "EngridUpsell" in window &&
+ !!window.pageJson &&
+ window.pageJson.pageNumber == 1 &&
+ ["donation", "premiumgift"].includes(window.pageJson.pageType));
+ }
+ shouldSkip() {
+ if ("EngridUpsell" in window && window.EngridUpsell.skipUpsell) {
+ return true;
}
- // Document Load
- if (document.readyState !== "loading") {
- this.run();
+ return this.options.skipUpsell;
+ }
+ popupOtherField() {
+ var _a, _b;
+ const value = parseFloat((_b = (_a = this.overlay.querySelector("#secondOtherField")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
+ const live_upsell_amount = document.querySelectorAll("#upsellYesButton .upsell_suggestion");
+ const upsellAmount = this.getUpsellAmount();
+ if (!isNaN(value) && value > 0) {
+ this.checkOtherAmount(value);
}
else {
- document.addEventListener("DOMContentLoaded", () => {
- this.run();
- });
+ this.checkOtherAmount(upsellAmount);
}
- // Window Resize
- window.onresize = () => {
- this.onResize();
- };
+ live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(upsellAmount + this._fees.calculateFees(upsellAmount))));
}
- run() {
- if (!engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs")) {
- this.logger.danger("Engaging Networks JS Framework NOT FOUND");
- setTimeout(() => {
- this.run();
- }, 100);
- return;
+ liveAmounts() {
+ const live_upsell_amount = document.querySelectorAll(".upsell_suggestion");
+ const live_amount = document.querySelectorAll(".upsell_amount");
+ const upsellAmount = this.getUpsellAmount();
+ const suggestedAmount = upsellAmount + this._fees.calculateFees(upsellAmount);
+ live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(suggestedAmount)));
+ live_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(this._amount.amount + this._fees.fee)));
+ }
+ liveFrequency() {
+ const live_upsell_frequency = document.querySelectorAll(".upsell_frequency");
+ live_upsell_frequency.forEach((elem) => (elem.innerHTML = this.getFrequencyTxt()));
+ }
+ // Return the Suggested Upsell Amount
+ getUpsellAmount() {
+ var _a, _b;
+ const amount = this._amount.amount;
+ const otherAmount = parseFloat((_b = (_a = this.overlay.querySelector("#secondOtherField")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
+ if (otherAmount > 0) {
+ return otherAmount > this.options.minAmount
+ ? otherAmount
+ : this.options.minAmount;
}
- // If there's an option object on the page, override the defaults
- if (window.hasOwnProperty("EngridPageOptions")) {
- this.options = Object.assign(Object.assign({}, this.options), window.EngridPageOptions);
- // Add Options to window
- window.EngridOptions = this.options;
+ let upsellAmount = 0;
+ for (let i = 0; i < this.options.amountRange.length; i++) {
+ let val = this.options.amountRange[i];
+ if (upsellAmount == 0 && amount <= val.max) {
+ upsellAmount = val.suggestion;
+ if (upsellAmount === 0)
+ return 0;
+ if (typeof upsellAmount !== "number") {
+ const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
+ upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
+ }
+ break;
+ }
}
- // If there's no pageJson.pageType, add a big red warning to the console
- if (!engrid_ENGrid.checkNested(window, "pageJson", "pageType")) {
- window.setTimeout(() => {
- console.log("%c βοΈ pageJson.pageType NOT FOUND - Go to the Account Settings and Expose the Transaction Details %s", "background-color: red; color: white; font-size: 22px; font-weight: bold;", "https://knowledge.engagingnetworks.net/datareports/expose-transaction-details-pagejson");
- }, 2000);
+ return upsellAmount > this.options.minAmount
+ ? upsellAmount
+ : this.options.minAmount;
+ }
+ shouldOpen() {
+ const upsellAmount = this.getUpsellAmount();
+ const paymenttype = engrid_ENGrid.getFieldValue("transaction.paymenttype") || "";
+ this._suggestAmount = upsellAmount;
+ // If frequency is not onetime or
+ // the modal is already opened or
+ // there's no suggestion for this donation amount,
+ // we should not open
+ if (this.freqAllowed() &&
+ !this.shouldSkip() &&
+ !this.options.disablePaymentMethods.includes(paymenttype.toLowerCase()) &&
+ !this.overlay.classList.contains("is-submitting") &&
+ upsellAmount > 0) {
+ this.logger.log("Upsell Frequency " + this._frequency.frequency);
+ this.logger.log("Upsell Amount " + this._amount.amount);
+ this.logger.log("Upsell Suggested Amount " + upsellAmount);
+ return true;
}
- if (this.options.Debug || App.getUrlParameter("debug") == "true")
- // Enable debug if available is the first thing
- App.setBodyData("debug", "");
- new Advocacy();
- new InputPlaceholders();
- new InputHasValueAndFocus();
- // Give By Select
- new GiveBySelect();
- new ShowHideRadioCheckboxes("transaction.giveBySelect", "giveBySelect-");
- new ShowHideRadioCheckboxes("transaction.inmem", "inmem-");
- new ShowHideRadioCheckboxes("transaction.recurrpay", "recurrpay-");
- new ShowHideRadioCheckboxes("transaction.shipenabled", "shipenabled-");
- // Automatically show/hide all radios
- let radioFields = [];
- const allRadios = document.querySelectorAll("input[type=radio]");
- allRadios.forEach((radio) => {
- if ("name" in radio && radioFields.includes(radio.name) === false) {
- radioFields.push(radio.name);
- }
- });
- radioFields.forEach((field) => {
- new ShowHideRadioCheckboxes(field, "engrid__" + field.replace(/\./g, "") + "-");
- });
- // Automatically show/hide all checkboxes
- const allCheckboxes = document.querySelectorAll("input[type=checkbox]");
- allCheckboxes.forEach((checkbox) => {
- if ("name" in checkbox) {
- new ShowHideRadioCheckboxes(checkbox.name, "engrid__" + checkbox.name.replace(/\./g, "") + "-");
+ return false;
+ }
+ // Return true if the current frequency is allowed by the options
+ freqAllowed() {
+ const freq = this._frequency.frequency;
+ const allowed = [];
+ if (this.options.oneTime)
+ allowed.push("onetime");
+ if (this.options.annual)
+ allowed.push("annual");
+ return allowed.includes(freq);
+ }
+ open() {
+ this.logger.log("Upsell script opened");
+ if (!this.shouldOpen()) {
+ // In the circumstance when the form fails to validate via server-side validation, the page will reload
+ // When that happens, we should place the original amount saved in sessionStorage into the upsell original amount field
+ let original = window.sessionStorage.getItem("original");
+ if (original &&
+ document.querySelectorAll(".en__errorList .en__error").length > 0) {
+ this.setOriginalAmount(original);
}
- });
- // Client onSubmit and onError functions
- this._form.onIntentSubmit.subscribe(() => this.onIntentSubmit());
- this._form.onSubmit.subscribe(() => this.onSubmit());
- this._form.onError.subscribe(() => this.onError());
- this._form.onValidate.subscribe(() => this.onValidate());
- // Event Listener Examples
- this._amount.onAmountChange.subscribe((s) => this.logger.success(`Live Amount: ${s}`));
- this._frequency.onFrequencyChange.subscribe((s) => {
- this.logger.success(`Live Frequency: ${s}`);
- setTimeout(() => {
- this._amount.load();
- }, 150);
- });
- this._form.onSubmit.subscribe((s) => this.logger.success("Submit: " + JSON.stringify(s)));
- this._form.onError.subscribe((s) => this.logger.danger("Error: " + JSON.stringify(s)));
- this._country.onCountryChange.subscribe((s) => this.logger.success(`Country: ${s}`));
- window.enOnSubmit = () => {
+ // Returning true will give the "go ahead" to submit the form
this._form.submit = true;
- this._form.submitPromise = false;
- this._form.dispatchIntentSubmit();
- this._form.dispatchSubmit();
- engrid_ENGrid.watchForError(engrid_ENGrid.enableSubmit);
- if (!this._form.submit)
- return false;
- if (this._form.submitPromise)
- return this._form.submitPromise;
- this.logger.success("enOnSubmit Success");
- // If all validation passes, we'll watch for Digital Wallets Errors, which
- // will not reload the page (thanks EN), so we will enable the submit button if
- // an error is programmatically thrown by the Digital Wallets
- return true;
- };
- window.enOnError = () => {
- this._form.dispatchError();
- };
- window.enOnValidate = () => {
- this._form.validate = true;
- this._form.validatePromise = false;
- this._form.dispatchValidate();
- if (!this._form.validate)
- return false;
- if (this._form.validatePromise)
- return this._form.validatePromise;
- this.logger.success("Validation Passed");
return true;
- };
- new DataAttributes();
- // Country Redirect
- new CountryRedirect();
- // iFrame Logic
- new iFrame();
- // Live Variables
- new LiveVariables(this.options);
- // Dynamically set Recurrency Frequency
- new setRecurrFreq();
- // Upsell Checkbox
- new UpsellCheckbox();
- // Upsell Lightbox
- new UpsellLightbox();
- // Amount Labels
- new AmountLabel();
- // Engrid Data Replacement
- new DataReplace();
- // ENgrid Hide Script
- new DataHide();
- // Autosubmit script
- new Autosubmit();
- // Adjust display of event tickets.
- new EventTickets();
- // StickyNSG - Must load before SwapAmounts
- new StickyNSG();
- // Swap Amounts
- new SwapAmounts();
- // On the end of the script, after all subscribers defined, let's load the current frequency
- // The amount will be loaded by the frequency change event
- // This timeout is needed because when you have alternative amounts, EN is slower than Engrid
- // about 20% of the time and we get a race condition if the client is also using the SwapAmounts feature
- window.setTimeout(() => {
- this._frequency.load();
- }, 1000);
- // Fast Form Fill
- new FastFormFill();
- // Currency Related Components
- new LiveCurrency();
- new CustomCurrency();
- // Auto Country Select
- new AutoCountrySelect();
- // Add Image Attribution
- if (this.options.MediaAttribution)
- new MediaAttribution();
- // Apple Pay
- if (this.options.applePay)
- new ApplePay();
- // Capitalize Fields
- if (this.options.CapitalizeFields)
- new CapitalizeFields();
- // Auto Year Class
- if (this.options.AutoYear)
- new AutoYear();
- // Autocomplete Class
- new Autocomplete();
- // Ecard Class
- new Ecard();
- // Click To Expand
- if (this.options.ClickToExpand)
- new ClickToExpand();
- if (this.options.SkipToMainContentLink)
- new SkipToMainContentLink();
- if (this.options.SrcDefer)
- new SrcDefer();
- // Progress Bar
- if (this.options.ProgressBar)
- new ProgressBar();
- // RememberMe
- try {
- // Accessing window.localStorage will throw an exception if it isn't permitted due to security reasons
- // For example, this happens in Firefox when cookies are disabled. If it isn't available, we shouldn't
- // bother with enabling RememberMe
- if (this.options.RememberMe &&
- typeof this.options.RememberMe === "object" &&
- window.localStorage) {
- new RememberMe(this.options.RememberMe);
- }
- }
- catch (e) { }
- if (this.options.NeverBounceAPI)
- new NeverBounce(this.options.NeverBounceAPI, this.options.NeverBounceDateField, this.options.NeverBounceStatusField, this.options.NeverBounceDateFormat);
- // FreshAddress
- if (this.options.FreshAddress)
- new FreshAddress();
- new ShowIfAmount();
- new OtherAmount();
- new MinMaxAmount();
- new Ticker();
- new A11y();
- new AddNameToMessage();
- new ExpandRegionName();
- // Page Background
- new PageBackground();
- // Url Params to Form Fields
- new UrlToForm();
- // Required if Visible Fields
- new RequiredIfVisible();
- // EN Custom Validators (behind a feature flag, off by default)
- new ENValidators();
- //Debug hidden fields
- if (this.options.Debug)
- new DebugHiddenFields();
- // TidyContact
- if (this.options.TidyContact)
- new TidyContact();
- // Translate Fields
- if (this.options.TranslateFields)
- new TranslateFields();
- // Country Disable
- new CountryDisable();
- // Premium Gift Features
- new PremiumGift();
- // Custom Premium filtering (frequency/amount-based visibility)
- new CustomPremium();
- // Supporter Hub Features
- new SupporterHub();
- // Digital Wallets Features
- if (engrid_ENGrid.getPageType() === "DONATION") {
- new DigitalWallets();
- new PreferredPaymentMethod();
}
- // Mobile CTA
- new MobileCTA();
- // Live Frequency
- new LiveFrequency();
- // Universal Opt In
- new UniversalOptIn();
- new StripeFinancialConnections();
- //Exit Intent Lightbox
- new ExitIntentLightbox();
- new UrlParamsToBodyAttrs();
- new SetAttr();
- new ShowIfPresent();
- new PostalCodeValidator();
- // Very Good Security
- new VGS();
- new WelcomeBack();
- new EcardToTarget();
- new UsOnlyForm();
- new ThankYouPageConditionalContent();
- new EmbeddedEcard();
- new CheckboxLabel();
- new PostDonationEmbed();
- new FrequencyUpsell();
- new StickyPrepopulation();
- //Debug panel
- let showDebugPanel = this.options.Debug;
- try {
- // accessing storage can throw an exception if it isn't available in Firefox
- if (!showDebugPanel &&
- window.sessionStorage.hasOwnProperty(DebugPanel.debugSessionStorageKey)) {
- showDebugPanel = true;
+ this.liveAmounts();
+ this.liveFrequency();
+ this.overlay.classList.remove("is-hidden");
+ this._form.submit = false;
+ engrid_ENGrid.setBodyData("has-lightbox", "");
+ return false;
+ }
+ // Set the original amount into a hidden field using the upsellOriginalGiftAmountFieldName, if provided
+ setOriginalAmount(original) {
+ if (this.options.upsellOriginalGiftAmountFieldName) {
+ let enFieldUpsellOriginalAmount = document.querySelector(".en__field__input.en__field__input--hidden[name='" +
+ this.options.upsellOriginalGiftAmountFieldName +
+ "']");
+ if (!enFieldUpsellOriginalAmount) {
+ let pageform = document.querySelector("form.en__component--page");
+ if (pageform) {
+ let input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("name", this.options.upsellOriginalGiftAmountFieldName);
+ input.classList.add("en__field__input", "en__field__input--hidden");
+ pageform.appendChild(input);
+ enFieldUpsellOriginalAmount = document.querySelector('.en__field__input.en__field__input--hidden[name="' +
+ this.options.upsellOriginalGiftAmountFieldName +
+ '"]');
+ }
+ }
+ if (enFieldUpsellOriginalAmount) {
+ // save it to a session variable just in case this page reloaded due to server-side validation error
+ window.sessionStorage.setItem("original", original);
+ enFieldUpsellOriginalAmount.setAttribute("value", original);
}
}
- catch (e) { }
- if (showDebugPanel) {
- new DebugPanel(this.options.PageLayouts);
- }
- if (engrid_ENGrid.getUrlParameter("development") === "branding") {
- new BrandingHtml().show();
- }
- engrid_ENGrid.setBodyData("js-loading", "finished");
- window.EngridVersion = AppVersion;
- this.logger.success(`VERSION: ${AppVersion}`);
- // Window Load
- let onLoad = typeof window.onload === "function" ? window.onload : null;
- if (document.readyState !== "loading") {
- this.onLoad();
+ }
+ // Proceed to the next page (upsold or not)
+ continue(e) {
+ var _a;
+ e.preventDefault();
+ if (e.target instanceof Element &&
+ ((_a = document.querySelector("#upsellYesButton")) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
+ this.logger.success("Upsold");
+ this.setOriginalAmount(this._amount.amount.toString());
+ const upsoldAmount = this.getUpsellAmount();
+ const originalAmount = this._amount.amount;
+ this._frequency.setFrequency("monthly");
+ this._amount.setAmount(upsoldAmount);
+ this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL", {
+ eventValue: true,
+ originalAmount: originalAmount,
+ upsoldAmount: upsoldAmount,
+ frequency: "monthly",
+ });
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL", true);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT", originalAmount);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "MONTHLY");
+ this.renderConversionField("upsellSuccess", "onetime", originalAmount, "monthly", this._suggestAmount, "monthly", upsoldAmount);
}
else {
- window.onload = (e) => {
- this.onLoad();
- if (onLoad) {
- onLoad.bind(window, e);
- }
- };
+ this.setOriginalAmount("");
+ window.sessionStorage.removeItem("original");
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL", false);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "ONE-TIME");
+ this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._suggestAmount, this._frequency.frequency, this._amount.amount);
}
+ this._form.submitForm();
}
- onLoad() {
- if (this.options.onLoad) {
- this.options.onLoad();
+ // Close the lightbox
+ close(e) {
+ e.preventDefault();
+ this.overlay.classList.add("is-hidden");
+ engrid_ENGrid.setBodyData("has-lightbox", false);
+ if (this.options.submitOnClose) {
+ this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._suggestAmount, this._frequency.frequency, this._amount.amount);
+ this._form.submitForm();
}
- }
- onResize() {
- if (this.options.onResize) {
- this.options.onResize();
+ else {
+ this._form.dispatchError();
}
}
- onValidate() {
- if (this.options.onValidate) {
- this.logger.log("Client onValidate Triggered");
- this.options.onValidate();
- }
+ getAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = engrid_ENGrid.getOption("DecimalSeparator")) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = engrid_ENGrid.getOption("ThousandsSeparator")) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = engrid_ENGrid.getOption("DecimalPlaces")) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? symbol + amountTxt : "";
}
- onIntentSubmit() {
- if (this.options.onIntentSubmit) {
- this.logger.log("Client onIntentSubmit Triggered");
- this.options.onIntentSubmit();
- }
+ getFrequencyTxt() {
+ const freqTxt = {
+ onetime: "one-time",
+ monthly: "monthly",
+ annual: "annual",
+ };
+ const frequency = this._frequency.frequency;
+ return frequency in freqTxt ? freqTxt[frequency] : frequency;
}
- onSubmit() {
- if (this.options.onSubmit) {
- this.logger.log("Client onSubmit Triggered");
- this.options.onSubmit();
+ checkOtherAmount(value) {
+ const otherInput = document.querySelector(".upsellOtherAmountInput");
+ if (otherInput) {
+ if (value >= this.options.minAmount) {
+ otherInput.classList.remove("is-invalid");
+ }
+ else {
+ otherInput.classList.add("is-invalid");
+ }
}
}
- onError() {
- if (this.options.onError) {
- this.logger.danger("Client onError Triggered");
- this.options.onError();
+ renderConversionField(event, // The event that triggered the conversion
+ freq, // The frequency of the donation (onetime, monthly, annual)
+ amt, // The original amount of the donation (before the upsell)
+ sugFreq, // The suggested frequency of the upsell (monthly)
+ sugAmt, // The suggested amount of the upsell
+ subFreq, // The submitted frequency of the upsell (onetime, monthly, annual)
+ subAmt // The submitted amount of the upsell
+ ) {
+ if (this.options.conversionField === "")
+ return;
+ const conversionField = document.querySelector("input[name='" + this.options.conversionField + "']") ||
+ engrid_ENGrid.createHiddenInput(this.options.conversionField);
+ if (!conversionField) {
+ this.logger.error("Could not find or create the conversion field");
+ return;
}
- }
- static log(message) {
- const logger = new logger_EngridLogger("Client", "brown", "aliceblue", "πͺ");
- logger.log(message);
+ const conversionValue = `event:${event},freq:${freq},amt:${amt},sugFreq:${sugFreq},sugAmt:${sugAmt},subFreq:${subFreq},subAmt:${subAmt}`;
+ conversionField.value = conversionValue;
+ this.logger.log(`Conversion Field ${event}`, conversionValue);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/amount-label.js
-// This script checks if the donations amounts are numbers and if they are, appends the correct currency symbol
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/upsell-checkbox.js
+// This component will add a checkbox to the donation form that will allow the user to upgrade their donation to a monthly donation.
-class AmountLabel {
+
+class UpsellCheckbox {
constructor() {
+ this.checkboxOptions = false;
+ this.checkboxOptionsDefaults = {
+ label: "Make my gift a monthly gift of {new-amount}/mo ",
+ location: "before .en__component .en__submit",
+ cssClass: "",
+ };
+ this._amount = DonationAmount.getInstance();
+ this._fees = ProcessingFees.getInstance();
this._frequency = DonationFrequency.getInstance();
+ this._dataLayer = DataLayer.getInstance();
+ this.checkboxContainer = null;
+ this.oldAmount = 0;
+ this.oldFrequency = "one-time";
+ this.resetCheckbox = false;
+ this.logger = new logger_EngridLogger("UpsellCheckbox", "black", "LemonChiffon", "β
");
+ let options = "EngridUpsell" in window ? window.EngridUpsell : {};
+ this.options = Object.assign(Object.assign({}, UpsellOptionsDefaults), options);
+ if (this.options.upsellCheckbox === false) {
+ this.logger.log("Skipped");
+ return;
+ }
+ // To avoid using both UpsellLightbox and UpsellCheckbox at the same time, set window.EngridUpsell.skipUpsell to true if there's an upsellCheckbox
+ if ("upsellCheckbox" in options && options.upsellCheckbox !== false) {
+ window.EngridUpsell.skipUpsell = true; // Skip the upsell lightbox
+ }
+ this.checkboxOptions = Object.assign(Object.assign({}, this.checkboxOptionsDefaults), this.options.upsellCheckbox);
if (!this.shouldRun()) {
+ this.logger.log("should NOT run");
// If we're not on a Donation Page, get out
return;
}
- this._frequency.onFrequencyChange.subscribe((s) => window.setTimeout(this.fixAmountLabels.bind(this), 100));
- // Run the main function on page load so we can analyze the amounts of the current frequency
- window.setTimeout(this.fixAmountLabels.bind(this), 300);
- }
- // Should we run the script?
- shouldRun() {
- return !!(engrid_ENGrid.getPageType() === "DONATION" &&
- engrid_ENGrid.getOption("AddCurrencySymbol"));
+ this.renderCheckbox();
+ this.updateLiveData();
+ this._frequency.onFrequencyChange.subscribe(() => this.updateLiveData());
+ this._frequency.onFrequencyChange.subscribe(() => this.resetUpsellCheckbox());
+ this._amount.onAmountChange.subscribe(() => this.updateLiveData());
+ this._amount.onAmountChange.subscribe(() => this.resetUpsellCheckbox());
+ this._fees.onFeeChange.subscribe(() => this.updateLiveData());
}
- // Fix Amount Labels
- fixAmountLabels() {
- let amounts = document.querySelectorAll(".en__field--donationAmt label");
- const currencySymbol = engrid_ENGrid.getCurrencySymbol() || "";
- amounts.forEach((element) => {
- const amountText = element.innerText.replace(/,/g, "").replace(/\./g, "");
- if (!isNaN(amountText)) {
- element.innerText = currencySymbol + element.innerText;
- }
- });
+ updateLiveData() {
+ this.liveAmounts();
+ this.liveFrequency();
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/apple-pay.js
-var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-
-/*global window */
-const ApplePaySession = window.ApplePaySession;
-const merchantIdentifier = window.merchantIdentifier;
-const merchantDomainName = window.merchantDomainName;
-const merchantDisplayName = window.merchantDisplayName;
-const merchantSessionIdentifier = window.merchantSessionIdentifier;
-const merchantNonce = window.merchantNonce;
-const merchantEpochTimestamp = window.merchantEpochTimestamp;
-const merchantSignature = window.merchantSignature;
-const merchantCountryCode = window.merchantCountryCode;
-const merchantCurrencyCode = window.merchantCurrencyCode;
-const merchantSupportedNetworks = window.merchantSupportedNetworks;
-const merchantCapabilities = window.merchantCapabilities;
-const merchantTotalLabel = window.merchantTotalLabel;
-class ApplePay {
- constructor() {
- this.applePay = document.querySelector('.en__field__input.en__field__input--radio[value="applepay"]');
- this._amount = DonationAmount.getInstance();
- this._fees = ProcessingFees.getInstance();
- this._form = en_form_EnForm.getInstance();
- this.checkApplePay();
+ resetUpsellCheckbox() {
+ var _a, _b;
+ // Only reset the upsell checkbox if it has been checked
+ if (!this.resetCheckbox)
+ return;
+ this.logger.log("Reset");
+ // Uncheck the upsell checkbox
+ const checkbox = (_a = this.checkboxContainer) === null || _a === void 0 ? void 0 : _a.querySelector("#upsellCheckbox");
+ if (checkbox) {
+ checkbox.checked = false;
+ }
+ // Hide the upsell checkbox
+ (_b = this.checkboxContainer) === null || _b === void 0 ? void 0 : _b.classList.add("recurring-frequency-y-hide");
+ this.oldAmount = 0;
+ this.oldFrequency = "one-time";
+ this.resetCheckbox = false;
}
- checkApplePay() {
- return __awaiter(this, void 0, void 0, function* () {
- const pageform = document.querySelector("form.en__component--page");
- if (!this.applePay || !window.hasOwnProperty("ApplePaySession")) {
- const applePayContainer = document.querySelector(".en__field__item.applepay");
- if (applePayContainer)
- applePayContainer.remove();
- if (engrid_ENGrid.debug)
- console.log("Apple Pay DISABLED");
- return false;
- }
- const promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantIdentifier);
- let applePayEnabled = false;
- yield promise.then((canMakePayments) => {
- applePayEnabled = canMakePayments;
- if (canMakePayments) {
- let input = document.createElement("input");
- input.setAttribute("type", "hidden");
- input.setAttribute("name", "PkPaymentToken");
- input.setAttribute("id", "applePayToken");
- pageform.appendChild(input);
- this._form.onSubmit.subscribe(() => this.onPayClicked());
- }
- });
- if (engrid_ENGrid.debug)
- console.log("applePayEnabled", applePayEnabled);
- let applePayWrapper = this.applePay.closest(".en__field__item");
- if (applePayEnabled) {
- // Set Apple Pay Class
- applePayWrapper === null || applePayWrapper === void 0 ? void 0 : applePayWrapper.classList.add("applePayWrapper");
+ renderCheckbox() {
+ if (this.checkboxOptions === false)
+ return;
+ const label = this.checkboxOptions.label
+ .replace("{new-amount}", " ")
+ .replace("{old-amount}", " ")
+ .replace("{old-frequency}", " ");
+ const formBlock = document.createElement("div");
+ formBlock.classList.add("en__component", "en__component--formblock", "recurring-frequency-y-hide", "engrid-upsell-checkbox");
+ if (this.checkboxOptions.cssClass)
+ formBlock.classList.add(this.checkboxOptions.cssClass);
+ formBlock.innerHTML = `
+ `;
+ const checkbox = formBlock.querySelector("#upsellCheckbox");
+ if (checkbox)
+ checkbox.addEventListener("change", this.toggleCheck.bind(this));
+ const position = this.checkboxOptions.location.split(" ")[0];
+ // Location is everything after the first space
+ const location = this.checkboxOptions.location
+ .split(" ")
+ .slice(1)
+ .join(" ")
+ .trim();
+ const target = document.querySelector(location);
+ this.checkboxContainer = formBlock;
+ if (target) {
+ if (position === "before") {
+ this.logger.log("rendered before");
+ target.before(formBlock);
}
else {
- // Hide Apple Pay Wrapper
- if (applePayWrapper)
- applePayWrapper.style.display = "none";
+ this.logger.log("rendered after");
+ target.after(formBlock);
}
- return applePayEnabled;
- });
+ }
+ else {
+ this.logger.error("could not render - target not found");
+ }
}
- performValidation(url) {
- return new Promise(function (resolve, reject) {
- var merchantSession = {};
- merchantSession.merchantIdentifier = merchantIdentifier;
- merchantSession.merchantSessionIdentifier = merchantSessionIdentifier;
- merchantSession.nonce = merchantNonce;
- merchantSession.domainName = merchantDomainName;
- merchantSession.epochTimestamp = merchantEpochTimestamp;
- merchantSession.signature = merchantSignature;
- var validationData = "&merchantIdentifier=" +
- merchantIdentifier +
- "&merchantDomain=" +
- merchantDomainName +
- "&displayName=" +
- merchantDisplayName;
- var validationUrl = "/ea-dataservice/rest/applepay/validateurl?url=" + url + validationData;
- var xhr = new XMLHttpRequest();
- xhr.onload = function () {
- var data = JSON.parse(this.responseText);
- if (engrid_ENGrid.debug)
- console.log("Apple Pay Validation", data);
- resolve(data);
- };
- xhr.onerror = reject;
- xhr.open("GET", validationUrl);
- xhr.send();
- });
+ // Should we run the script?
+ shouldRun() {
+ // if it's a first page of a Donation page
+ return engrid_ENGrid.getPageNumber() === 1 && engrid_ENGrid.getPageType() === "DONATION";
}
- log(name, msg) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/ea-dataservice/rest/applepay/log?name=" + name + "&msg=" + msg);
- xhr.send();
+ showCheckbox() {
+ if (this.checkboxContainer)
+ this.checkboxContainer.classList.remove("hide");
}
- sendPaymentToken(token) {
- return new Promise(function (resolve, reject) {
- resolve(true);
- });
+ hideCheckbox() {
+ if (this.checkboxContainer)
+ this.checkboxContainer.classList.add("hide");
}
- onPayClicked() {
- if (!this._form.submit)
+ liveAmounts() {
+ // Only update live data if the current frequency is one-time
+ if (this._frequency.frequency !== "onetime")
return;
- const enFieldPaymentType = document.querySelector("#en__field_transaction_paymenttype");
- const applePayToken = document.getElementById("applePayToken");
- const formClass = this._form;
- // Only work if Payment Type is Apple Pay
- if (enFieldPaymentType.value == "applepay" && applePayToken.value == "") {
- try {
- let donationAmount = this._amount.amount + this._fees.fee;
- var request = {
- supportedNetworks: merchantSupportedNetworks,
- merchantCapabilities: merchantCapabilities,
- countryCode: merchantCountryCode,
- currencyCode: merchantCurrencyCode,
- total: {
- label: merchantTotalLabel,
- amount: donationAmount,
- },
- };
- var session = new ApplePaySession(1, request);
- var thisClass = this;
- session.onvalidatemerchant = function (event) {
- thisClass
- .performValidation(event.validationURL)
- .then(function (merchantSession) {
- if (engrid_ENGrid.debug)
- console.log("Apple Pay merchantSession", merchantSession);
- session.completeMerchantValidation(merchantSession);
- });
- };
- session.onpaymentauthorized = function (event) {
- thisClass
- .sendPaymentToken(event.payment.token)
- .then(function (success) {
- if (engrid_ENGrid.debug)
- console.log("Apple Pay Token", event.payment.token);
- document.getElementById("applePayToken").value = JSON.stringify(event.payment.token);
- formClass.submitForm();
- });
- };
- session.oncancel = function (event) {
- if (engrid_ENGrid.debug)
- console.log("Cancelled", event);
- alert("You cancelled. Sorry it didn't work out.");
- formClass.dispatchError();
- };
- session.begin();
- this._form.submit = false;
- return false;
- }
- catch (e) {
- alert("Developer mistake: '" + e.message + "'");
- formClass.dispatchError();
- }
+ const live_upsell_amount = document.querySelectorAll(".upsell_suggestion");
+ const live_amount = document.querySelectorAll(".upsell_amount");
+ const upsellAmount = this.getUpsellAmount();
+ const suggestedAmount = upsellAmount + this._fees.calculateFees(upsellAmount);
+ if (suggestedAmount > 0) {
+ this.showCheckbox();
}
- this._form.submit = true;
- return true;
+ else {
+ this.hideCheckbox();
+ }
+ live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(suggestedAmount)));
+ live_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(this._amount.amount + this._fees.fee)));
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/a11y.js
-// a11y means accessibility
-// This Component is supposed to be used as a helper for Aria Attributes & Other Accessibility Features
-class A11y {
- constructor() {
- this.addRequired();
- this.addLabel();
- this.addGroupRole();
- this.updateFrequencyLabel();
- const ecardImages = document.querySelectorAll('.en__ecarditems__list img');
- this.setAutoGeneratedAltTags(ecardImages);
- this.manageErrorListAlertRole();
+ liveFrequency() {
+ const live_upsell_frequency = document.querySelectorAll(".upsell_frequency");
+ live_upsell_frequency.forEach((elem) => (elem.innerHTML = this.getFrequencyTxt()));
}
- addGroupRole() {
- // Add role="group" to all EN Radio fields
- const radioFields = document.querySelectorAll(".en__field--radio");
- radioFields.forEach((field) => {
- field.setAttribute("role", "group");
- // Add random ID to the label
- const label = field.querySelector("label");
- if (label) {
- label.setAttribute("id", `en__field__label--${Math.random().toString(36).slice(2, 7)}`);
- field.setAttribute("aria-labelledby", label.id);
+ // Return the Suggested Upsell Amount
+ getUpsellAmount() {
+ const amount = this._amount.amount;
+ let upsellAmount = 0;
+ for (let i = 0; i < this.options.amountRange.length; i++) {
+ let val = this.options.amountRange[i];
+ if (upsellAmount == 0 && amount <= val.max) {
+ upsellAmount = val.suggestion;
+ if (upsellAmount === 0)
+ return 0;
+ if (typeof upsellAmount !== "number") {
+ const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
+ upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
+ }
+ break;
}
- });
- }
- addRequired() {
- const mandatoryFields = document.querySelectorAll(".en__mandatory .en__field__input");
- mandatoryFields.forEach((field) => {
- field.setAttribute("aria-required", "true");
- });
+ }
+ return upsellAmount > this.options.minAmount
+ ? upsellAmount
+ : this.options.minAmount;
}
- addLabel() {
- const otherAmount = document.querySelector(".en__field__input--otheramount");
- if (otherAmount) {
- otherAmount.setAttribute("aria-label", "Enter your custom donation amount");
+ // Proceed to the next page (upsold or not)
+ toggleCheck(e) {
+ var _a, _b;
+ e.preventDefault();
+ if (e.target.checked) {
+ this.logger.success("Upsold");
+ const upsoldAmount = this.getUpsellAmount();
+ const originalAmount = this._amount.amount;
+ this.oldAmount = originalAmount;
+ this.oldFrequency = this._frequency.frequency;
+ // If we're checking the upsell checkbox, remove the class that hides it on different frequencies
+ (_a = this.checkboxContainer) === null || _a === void 0 ? void 0 : _a.classList.remove("recurring-frequency-y-hide");
+ this._frequency.setFrequency("monthly");
+ this._amount.setAmount(upsoldAmount);
+ this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL_CHECKBOX", {
+ eventValue: true,
+ originalAmount: originalAmount,
+ upsoldAmount: upsoldAmount,
+ frequency: "monthly",
+ });
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX", true);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT", originalAmount);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "MONTHLY");
+ this.renderConversionField("upsellSuccess", "onetime", originalAmount, "monthly", upsoldAmount, "monthly", upsoldAmount);
+ // Set the resetCheckbox flag to true so it will reset if the user changes the amount or frequency
+ window.setTimeout(() => {
+ this.resetCheckbox = true;
+ }, 500);
+ }
+ else {
+ this.resetCheckbox = false;
+ this.logger.success("Not Upsold");
+ this._amount.setAmount(this.oldAmount);
+ this._frequency.setFrequency(this.oldFrequency);
+ (_b = this.checkboxContainer) === null || _b === void 0 ? void 0 : _b.classList.add("recurring-frequency-y-hide");
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX", false);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "ONE-TIME");
+ this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._amount.amount, this._frequency.frequency, this._amount.amount);
}
- // Split selects usually don't have a label, so let's make the first option the label
- const splitSelects = document.querySelectorAll(".en__field__input--splitselect");
- splitSelects.forEach((select) => {
- var _a, _b, _c, _d;
- const firstOption = select.querySelector("option");
- if (firstOption &&
- firstOption.value === "" &&
- !((_b = (_a = firstOption.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.includes("select")) &&
- !((_d = (_c = firstOption.textContent) === null || _c === void 0 ? void 0 : _c.toLowerCase()) === null || _d === void 0 ? void 0 : _d.includes("choose"))) {
- select.setAttribute("aria-label", firstOption.textContent || "");
- }
- });
}
- // Update the label for the frequency field based on the selected radio button
- updateFrequencyLabel() {
- const frequencyLabels = document.querySelectorAll('div.en__field__item input[id^="en__field_transaction_recurrfreq"]');
- const frequencyMainLabel = document.querySelector('label[for="en__field_transaction_recurrfreq"]');
- frequencyLabels.forEach((item) => {
- if (item) {
- // Set the label for the checked item on load
- if (item.checked) {
- frequencyMainLabel === null || frequencyMainLabel === void 0 ? void 0 : frequencyMainLabel.setAttribute('for', item.id);
- }
- // Then, detect if it changes with the click event
- item.addEventListener('click', () => {
- let frequencyId = item.id;
- frequencyMainLabel === null || frequencyMainLabel === void 0 ? void 0 : frequencyMainLabel.setAttribute('for', frequencyId);
- });
- }
- });
+ getAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = engrid_ENGrid.getOption("DecimalSeparator")) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = engrid_ENGrid.getOption("ThousandsSeparator")) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = engrid_ENGrid.getOption("DecimalPlaces")) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? symbol + amountTxt : "";
}
- setAutoGeneratedAltTags(images) {
- images.forEach((img) => {
- var _a;
- // Skip if the alt tag is already set
- if (img.alt)
- return;
- try {
- // Extract the filename from the `src` attribute
- const src = img.src;
- if (!src)
- throw new Error("Image src is null or undefined");
- const url = new URL(src);
- const fileNameWithExtension = url.pathname.split('/').pop();
- if (!fileNameWithExtension)
- throw new Error("No filename found in src");
- // Remove the file extension and replace `-` and `_` with spaces
- let altText = ((_a = fileNameWithExtension.split('.').shift()) === null || _a === void 0 ? void 0 : _a.replace(/[-_]/g, ' ')) || '';
- // Remove dimensions (#x#) and anything that follows
- altText = altText.replace(/\d+x\d+.*$/, '').trim();
- // Wrap in the disclaimer
- altText = `This is an auto-generated alt tag from the filename: ${altText}`;
- // Set the generated alt text on the image
- img.alt = altText;
- }
- catch (error) {
- console.error(`Error processing image: ${img.src}`, error);
- }
- });
+ getFrequencyTxt() {
+ const freqTxt = {
+ onetime: "one-time",
+ monthly: "monthly",
+ annual: "annual",
+ };
+ const frequency = this._frequency.frequency;
+ return frequency in freqTxt ? freqTxt[frequency] : frequency;
}
- manageErrorListAlertRole() {
- const errorList = document.querySelector('ul.en__errorList');
- if (!errorList)
+ renderConversionField(event, // The event that triggered the conversion
+ freq, // The frequency of the donation (onetime, monthly, annual)
+ amt, // The original amount of the donation (before the upsell)
+ sugFreq, // The suggested frequency of the upsell (monthly)
+ sugAmt, // The suggested amount of the upsell
+ subFreq, // The submitted frequency of the upsell (onetime, monthly, annual)
+ subAmt // The submitted amount of the upsell
+ ) {
+ if (this.options.conversionField === "")
return;
- const hasErrorItems = () => Boolean(errorList.querySelector('li'));
- const enableAlert = () => {
- if (!errorList.hasAttribute('role')) {
- errorList.setAttribute('role', 'alert');
- }
- };
- const disableAlert = () => {
- if (errorList.hasAttribute('role')) {
- errorList.removeAttribute('role');
- }
- };
- hasErrorItems() ? enableAlert() : disableAlert();
- new MutationObserver(records => {
- for (const record of records) {
- if (record.type === 'childList') {
- hasErrorItems() ? enableAlert() : disableAlert();
- break;
- }
- }
- }).observe(errorList, { childList: true });
+ const conversionField = document.querySelector("input[name='" + this.options.conversionField + "']") ||
+ engrid_ENGrid.createHiddenInput(this.options.conversionField);
+ if (!conversionField) {
+ this.logger.error("Could not find or create the conversion field");
+ return;
+ }
+ const conversionValue = `event:${event},freq:${freq},amt:${amt},sugFreq:${sugFreq},sugAmt:${sugAmt},subFreq:${subFreq},subAmt:${subAmt}`;
+ conversionField.value = conversionValue;
+ this.logger.log(`Conversion Field ${event}`, conversionValue);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/capitalize-fields.js
-// CapitalizeFields is a class that capitalizes the first letter of the fields passed to it.
-// It subscribes to the onSubmit event of the EnForm class and capitalizes the fields on submit.
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/show-hide-radio-checkboxes.js
-class CapitalizeFields {
- constructor() {
- this._form = en_form_EnForm.getInstance();
- this._form.onSubmit.subscribe(() => this.capitalizeFields("en__field_supporter_firstName", "en__field_supporter_lastName", "en__field_supporter_address1", "en__field_supporter_city"));
+class ShowHideRadioCheckboxes {
+ // Create default data attributes on all fields
+ createDataAttributes() {
+ this.elements.forEach((item) => {
+ if (item instanceof HTMLInputElement) {
+ let inputValue = item.value.replace(/\W/g, "");
+ document
+ .querySelectorAll("." + this.classes + inputValue)
+ .forEach((el) => {
+ // Consider toggling "hide" class so these fields can be displayed when in a debug state
+ if (el instanceof HTMLElement) {
+ const fields = el.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");
+ if (fields.length > 0) {
+ fields.forEach((field) => {
+ if (field instanceof HTMLInputElement ||
+ field instanceof HTMLSelectElement) {
+ if (!field.hasAttribute("data-original-value")) {
+ field.setAttribute("data-original-value", field.value);
+ }
+ if (!field.hasAttribute("data-value")) {
+ field.setAttribute("data-value", field.value);
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+ });
}
- capitalizeFields(...fields) {
- fields.forEach((f) => this.capitalize(f));
+ // Hide All Divs
+ hideAll() {
+ this.elements.forEach((item, index) => {
+ if (item instanceof HTMLInputElement)
+ this.hide(item);
+ });
}
- capitalize(f) {
- let field = document.getElementById(f);
- if (field) {
- field.value = field.value.replace(/\w\S*/g, (w) => w.replace(/^\w/, (c) => c.toUpperCase()));
- if (engrid_ENGrid.debug)
- console.log("Capitalized", field.value);
- }
- return true;
+ // Hide Single Element Div
+ hide(item) {
+ let inputValue = item.value.replace(/\W/g, "");
+ document.querySelectorAll("." + this.classes + inputValue).forEach((el) => {
+ // Consider toggling "hide" class so these fields can be displayed when in a debug state
+ if (el instanceof HTMLElement) {
+ this.toggleValue(el, "hide");
+ el.style.display = "none";
+ this.logger.log("Hiding", el);
+ const input = el.querySelector("input");
+ if (input instanceof HTMLInputElement) {
+ input.setAttribute("aria-required", "false");
+ this.logger.log("aria-required set to FALSE", input);
+ }
+ }
+ });
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/auto-year.js
-// This class changes the Credit Card Expiration Year Field Options to
-// include the current year and the next 19 years.
-class AutoYear {
- constructor() {
- this.yearField = document.querySelector("select[name='transaction.ccexpire']:not(#en__field_transaction_ccexpire)");
- this.years = 20;
- this.yearLength = 2;
- if (this.yearField) {
- this.clearFieldOptions();
- for (let i = 0; i < this.years; i++) {
- const year = new Date().getFullYear() + i;
- const newOption = document.createElement("option");
- const optionText = document.createTextNode(year.toString());
- newOption.appendChild(optionText);
- newOption.value =
- this.yearLength == 2 ? year.toString().substr(-2) : year.toString();
- this.yearField.appendChild(newOption);
+ // Show Single Element Div
+ show(item) {
+ let inputValue = item.value.replace(/\W/g, "");
+ document.querySelectorAll("." + this.classes + inputValue).forEach((el) => {
+ // Consider toggling "hide" class so these fields can be displayed when in a debug state
+ if (el instanceof HTMLElement) {
+ this.toggleValue(el, "show");
+ el.style.display = "";
+ this.logger.log("Showing", el);
+ const input = el.querySelector("input");
+ if (input instanceof HTMLInputElement) {
+ input.setAttribute("aria-required", "true");
+ this.logger.log("aria-required set to TRUE", input);
+ }
}
+ });
+ if (item.type == "checkbox" && !item.checked) {
+ this.hide(item);
}
}
- clearFieldOptions() {
- if (this.yearField) {
- this.yearLength =
- this.yearField.options[this.yearField.options.length - 1].value.length;
- [...this.yearField.options].forEach((option) => {
+ // Take the field values and add to a data attribute on the field
+ toggleValue(item, type) {
+ if (type == "hide" && !engrid_ENGrid.isVisible(item))
+ return;
+ this.logger.log(`toggleValue: ${type}`);
+ const fields = item.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");
+ if (fields.length > 0) {
+ fields.forEach((field) => {
var _a;
- if (option.value !== "" && !isNaN(Number(option.value))) {
- // @ts-ignore
- const index = [...this.yearField.options].findIndex((i) => i.value === option.value);
- (_a = this.yearField) === null || _a === void 0 ? void 0 : _a.remove(index);
+ if (field instanceof HTMLInputElement ||
+ field instanceof HTMLSelectElement) {
+ if (field.name) {
+ const fieldValue = engrid_ENGrid.getFieldValue(field.name);
+ const originalValue = field.getAttribute("data-original-value");
+ const dataValue = (_a = field.getAttribute("data-value")) !== null && _a !== void 0 ? _a : "";
+ if (type === "hide") {
+ field.setAttribute("data-value", fieldValue);
+ engrid_ENGrid.setFieldValue(field.name, originalValue);
+ }
+ else {
+ engrid_ENGrid.setFieldValue(field.name, dataValue);
+ }
+ }
}
});
}
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/autocomplete.js
-// This class adds the autocomplete attribute to
-// the most common input elements
-
-class Autocomplete {
- constructor() {
- this.logger = new logger_EngridLogger("Autocomplete", "#330033", "#f0f0f0", "π");
- this.autoCompleteField('[name="supporter.firstName"]', "given-name");
- this.autoCompleteField('[name="supporter.lastName"]', "family-name");
- this.autoCompleteField("#en__field_transaction_ccexpire", "cc-exp-month");
- this.autoCompleteField('[name="transaction.ccexpire"]:not(#en__field_transaction_ccexpire)', "cc-exp-year");
- this.autoCompleteField('[name="supporter.emailAddress"]', "email");
- this.autoCompleteField('[name="supporter.phoneNumber"]', "tel");
- this.autoCompleteField('[name="supporter.country"]', "country");
- this.autoCompleteField('[name="supporter.address1"]', "address-line1");
- this.autoCompleteField('[name="supporter.address2"]', "address-line2");
- this.autoCompleteField('[name="supporter.city"]', "address-level2");
- this.autoCompleteField('[name="supporter.region"]', "address-level1");
- this.autoCompleteField('[name="supporter.postcode"]', "postal-code");
- // Ignore Autocomplete on the Recipient Email Field & Address ("none" is intentional because "off" doesn't work)
- this.autoCompleteField('[name="transaction.honname"]', "none");
- this.autoCompleteField('[name="transaction.infemail"]', "none");
- this.autoCompleteField('[name="transaction.infname"]', "none");
- this.autoCompleteField('[name="transaction.infadd1"]', "none");
- this.autoCompleteField('[name="transaction.infadd2"]', "none");
- this.autoCompleteField('[name="transaction.infcity"]', "none");
- this.autoCompleteField('[name="transaction.infpostcd"]', "none");
- }
- autoCompleteField(querySelector, autoCompleteValue) {
- let field = document.querySelector(querySelector);
- if (field) {
- field.autocomplete = autoCompleteValue;
- return true;
- }
- if (autoCompleteValue !== "none")
- this.logger.log("Field Not Found", querySelector);
- return false;
- }
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/ecard.js
-
-class Ecard {
- constructor() {
- this._form = en_form_EnForm.getInstance();
- this.logger = new logger_EngridLogger("Ecard", "red", "#f5f5f5", "πͺͺ");
- if (!this.shouldRun())
- return;
- this._form.onValidate.subscribe(() => this.checkRecipientFields());
- const schedule = engrid_ENGrid.getUrlParameter("engrid_ecard.schedule");
- const scheduleField = engrid_ENGrid.getField("ecard.schedule");
- const name = engrid_ENGrid.getUrlParameter("engrid_ecard.name");
- const nameField = document.querySelector(".en__ecardrecipients__name input");
- const email = engrid_ENGrid.getUrlParameter("engrid_ecard.email");
- const emailField = document.querySelector(".en__ecardrecipients__email input");
- if (schedule && scheduleField) {
- // Check if chedule date is in the past
- const scheduleDate = new Date(schedule.toString());
- const today = new Date();
- if (scheduleDate.setHours(0, 0, 0, 0) < today.setHours(0, 0, 0, 0)) {
- // If it is, set the schedule to today
- scheduleField.value = engrid_ENGrid.formatDate(today, "YYYY-MM-DD");
- }
- else {
- // Otherwise, set the schedule to the date provided
- scheduleField.value = schedule.toString();
- }
- this.logger.log("Schedule set to " + scheduleField.value);
- }
- if (name && nameField) {
- nameField.value = name.toString();
- this.logger.log("Name set to " + nameField.value);
- }
- if (email && emailField) {
- emailField.value = email.toString();
- this.logger.log("Email set to " + emailField.value);
- }
- // Replace the Future Delivery Label with a H2
- const futureDeliveryLabel = document.querySelector(".en__ecardrecipients__futureDelivery label");
- if (futureDeliveryLabel) {
- const futureDeliveryH2 = document.createElement("h2");
- futureDeliveryH2.innerText = futureDeliveryLabel.innerText;
- futureDeliveryLabel.replaceWith(futureDeliveryH2);
- }
- if (emailField) {
- emailField.setAttribute("type", "email");
- emailField.setAttribute("autocomplete", "off");
+ getSessionState() {
+ var _a;
+ try {
+ const plainState = (_a = window.sessionStorage.getItem(`engrid_ShowHideRadioCheckboxesState`)) !== null && _a !== void 0 ? _a : "";
+ return JSON.parse(plainState);
}
- }
- shouldRun() {
- return engrid_ENGrid.getPageType() === "ECARD";
- }
- checkRecipientFields() {
- const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
- // If we find the "+" button and there's no hidden recipient field, click on the button
- if (addRecipientButton &&
- !document.querySelector(".ecardrecipient__email")) {
- addRecipientButton.click();
+ catch (err) {
+ return [];
}
- return true;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/click-to-expand.js
-// This class is used to expand content when a user clicks on a div with the class "click-to-expand".
-// The content is shortened by default and will expand when clicked.
-
-// Works when the user has adds ".click-to-expand" as a class to any field
-class ClickToExpand {
- constructor() {
- this.clickToExpandWrapper = document.querySelectorAll("div.click-to-expand");
- if (this.clickToExpandWrapper.length) {
- this.clickToExpandWrapper.forEach((element) => {
- const content = element.innerHTML;
- const wrapper_html = '
' +
- content +
- "
";
- element.innerHTML = wrapper_html;
- element.addEventListener("click", (event) => {
- if (event) {
- if (engrid_ENGrid.debug)
- console.log("A click-to-expand div was clicked");
- element.classList.add("expanded");
+ storeSessionState() {
+ const state = this.getSessionState();
+ [...this.elements].forEach((element) => {
+ var _a, _b;
+ if (!(element instanceof HTMLInputElement))
+ return;
+ if (element.type == "radio" && element.checked) {
+ //remove other items that have the same "class" property
+ state.forEach((item, index) => {
+ if (item.class == this.classes) {
+ state.splice(index, 1);
}
});
- element.addEventListener("keydown", (event) => {
- if (event.key === "Enter") {
- if (engrid_ENGrid.debug)
- console.log("A click-to-expand div had the 'Enter' key pressed on it");
- element.classList.add("expanded");
- }
- else if (event.key === " ") {
- if (engrid_ENGrid.debug)
- console.log("A click-to-expand div had the 'Spacebar' key pressed on it");
- element.classList.add("expanded");
- event.preventDefault(); // Prevents the page from scrolling
- event.stopPropagation(); // Prevent a console error generated by LastPass https://github.com/KillerCodeMonkey/ngx-quill/issues/351#issuecomment-476017960
+ //add the current item, with the currently active value
+ state.push({
+ page: engrid_ENGrid.getPageID(),
+ class: this.classes,
+ value: element.value,
+ });
+ this.logger.log("storing radio state", state[state.length - 1]);
+ }
+ if (element.type == "checkbox") {
+ //remove other items that have the same "class" property
+ state.forEach((item, index) => {
+ if (item.class == this.classes) {
+ state.splice(index, 1);
}
});
+ //add the current item, with the first checked value or "N" if none are checked
+ state.push({
+ page: engrid_ENGrid.getPageID(),
+ class: this.classes,
+ value: (_b = (_a = [...this.elements].find((el) => el.checked)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "N", // First checked value or "N" if none
+ });
+ this.logger.log("storing checkbox state", state[state.length - 1]);
+ }
+ });
+ window.sessionStorage.setItem(`engrid_ShowHideRadioCheckboxesState`, JSON.stringify(state));
+ }
+ constructor(elements, classes) {
+ this.logger = new logger_EngridLogger("ShowHideRadioCheckboxes", "black", "lightblue", "π");
+ this.elements = document.getElementsByName(elements);
+ this.classes = classes;
+ this.createDataAttributes();
+ this.hideAll();
+ this.storeSessionState();
+ for (let i = 0; i < this.elements.length; i++) {
+ let element = this.elements[i];
+ if (element.checked) {
+ this.show(element);
+ }
+ element.addEventListener("change", (e) => {
+ this.hideAll();
+ this.show(element);
+ this.storeSessionState();
});
}
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/advocacy.js
-// Component to handle advocacy features
-// 1 - Adds EN Polyfill to support "label" clicking on Advocacy Recipient "labels"
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/cookie.js
+/**
+Example:
+import * as cookie from "./cookie";
-class Advocacy {
- constructor() {
- this.logger = new logger_EngridLogger("Advocacy", "#232323", "#f7b500", "π¨ββοΈ");
- if (!this.shoudRun())
- return;
- this.setClickableLabels();
- }
- shoudRun() {
- return ["ADVOCACY", "EMAILTOTARGET"].includes(engrid_ENGrid.getPageType());
- }
- setClickableLabels() {
- const contactItems = document.querySelectorAll(".en__contactDetails__rows");
- if (!contactItems)
- return;
- contactItems.forEach((contact) => {
- contact.addEventListener("click", (e) => {
- this.toggleCheckbox(contact);
- });
- });
+cookie.set('name', 'value');
+cookie.get('name'); // => 'value'
+cookie.remove('name');
+cookie.set('name', 'value', { expires: 7 }); // 7 Days cookie
+cookie.set('name', 'value', { expires: 7, path: '' }); // Set Path
+cookie.remove('name', { path: '' });
+ */
+function stringifyAttribute(name, value) {
+ if (!value) {
+ return "";
}
- toggleCheckbox(contact) {
- const wrapper = contact.closest(".en__contactDetails");
- if (!wrapper)
- return;
- const checkbox = wrapper.querySelector("input[type='checkbox']");
- if (!checkbox)
- return;
- this.logger.log("toggleCheckbox", checkbox.checked);
- checkbox.checked = !checkbox.checked;
+ let stringified = "; " + name;
+ if (value === true) {
+ return stringified; // boolean attributes shouldn't have a value
}
+ return stringified + "=" + value;
}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-attributes.js
-// Component that adds data attributes to the Body
-
-class DataAttributes {
- constructor() {
- this.logger = new logger_EngridLogger("Data Attribute Changed", "#FFFFFF", "#4d9068", "π οΈ");
- this._country = Country.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this.setDataAttributes();
+function stringifyAttributes(attributes) {
+ if (typeof attributes.expires === "number") {
+ let expires = new Date();
+ expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e5);
+ attributes.expires = expires;
}
- setDataAttributes() {
- // Apple Pay Availability
- if (window.hasOwnProperty("ApplePaySession")) {
- engrid_ENGrid.setBodyData("apple-pay-available", "true");
- }
- else {
- engrid_ENGrid.setBodyData("apple-pay-available", "false");
- }
- // Add the Page Type as a Data Attribute on the Body Tag
- if (engrid_ENGrid.checkNested(window, "pageJson", "pageType")) {
- engrid_ENGrid.setBodyData("page-type", window.pageJson.pageType);
- }
- // Add the currency code as a Data Attribute on the Body Tag
- engrid_ENGrid.setBodyData("currency-code", engrid_ENGrid.getCurrencyCode());
- // Add a body banner data attribute if the banner contains no image or video
- if (!document.querySelector(".body-banner img, .body-banner video")) {
- engrid_ENGrid.setBodyData("body-banner", "empty");
- }
- // Add a page-alert data attribute if it is empty
- if (!document.querySelector(".page-alert *")) {
- engrid_ENGrid.setBodyData("no-page-alert", "");
- }
- // Add a content-header data attribute if it is empty
- if (!document.querySelector(".content-header *")) {
- engrid_ENGrid.setBodyData("no-content-header", "");
- }
- // Add a body-headerOutside data attribute if it is empty
- if (!document.querySelector(".body-headerOutside *")) {
- engrid_ENGrid.setBodyData("no-body-headerOutside", "");
- }
- // Add a body-header data attribute if it is empty
- if (!document.querySelector(".body-header *")) {
- engrid_ENGrid.setBodyData("no-body-header", "");
- }
- // Add a body-title data attribute if it is empty
- if (!document.querySelector(".body-title *")) {
- engrid_ENGrid.setBodyData("no-body-title", "");
- }
- // Add a body-banner data attribute if it is empty
- if (!document.querySelector(".body-banner *")) {
- engrid_ENGrid.setBodyData("no-body-banner", "");
- }
- // Add a body-bannerOverlay data attribute if it is empty
- if (!document.querySelector(".body-bannerOverlay *")) {
- engrid_ENGrid.setBodyData("no-body-bannerOverlay", "");
- }
- // Add a body-top data attribute if it is empty
- if (!document.querySelector(".body-top *")) {
- engrid_ENGrid.setBodyData("no-body-top", "");
- }
- // Add a body-main data attribute if it is empty
- if (!document.querySelector(".body-main *")) {
- engrid_ENGrid.setBodyData("no-body-main", "");
- }
- // Add a body-bottom data attribute if it is empty
- if (!document.querySelector(".body-bottom *")) {
- engrid_ENGrid.setBodyData("no-body-bottom", "");
- }
- // Add a body-footer data attribute if it is empty
- if (!document.querySelector(".body-footer *")) {
- engrid_ENGrid.setBodyData("no-body-footer", "");
- }
- // Add a body-footerOutside data attribute if it is empty
- if (!document.querySelector(".body-footerOutside *")) {
- engrid_ENGrid.setBodyData("no-body-footerOutside", "");
- }
- // Add a content-footerSpacer data attribute if it is empty
- if (!document.querySelector(".content-footerSpacer *")) {
- engrid_ENGrid.setBodyData("no-content-footerSpacer", "");
- }
- // Add a content-preFooter data attribute if it is empty
- if (!document.querySelector(".content-preFooter *")) {
- engrid_ENGrid.setBodyData("no-content-preFooter", "");
- }
- // Add a content-footer data attribute if it is empty
- if (!document.querySelector(".content-footer *")) {
- engrid_ENGrid.setBodyData("no-content-footer", "");
- }
- // Add a page-backgroundImage banner data attribute if the page background image contains no image or video
- if (!document.querySelector(".page-backgroundImage img, .page-backgroundImage video")) {
- engrid_ENGrid.setBodyData("no-page-backgroundImage", "");
- }
- // Add a page-backgroundImageOverlay data attribute if it is empty
- if (!document.querySelector(".page-backgroundImageOverlay *")) {
- engrid_ENGrid.setBodyData("no-page-backgroundImageOverlay", "");
- }
- // Add a page-customCode data attribute if it is empty
- if (!document.querySelector(".page-customCode *")) {
- engrid_ENGrid.setBodyData("no-page-customCode", "");
- }
- // Add a country data attribute
- if (this._country.country) {
- engrid_ENGrid.setBodyData("country", this._country.country);
- this._country.onCountryChange.subscribe((country) => {
- engrid_ENGrid.setBodyData("country", country);
- });
+ return (stringifyAttribute("Expires", attributes.expires ? attributes.expires.toUTCString() : "") +
+ stringifyAttribute("Domain", attributes.domain) +
+ stringifyAttribute("Path", attributes.path) +
+ stringifyAttribute("Secure", attributes.secure) +
+ stringifyAttribute("SameSite", attributes.sameSite));
+}
+function encode(name, value, attributes) {
+ return (encodeURIComponent(name)
+ .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent) // allowed special characters
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29") + // replace opening and closing parens
+ "=" +
+ encodeURIComponent(value)
+ // allowed special characters
+ .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent) +
+ stringifyAttributes(attributes));
+}
+function parse(cookieString) {
+ let result = {};
+ let cookies = cookieString ? cookieString.split("; ") : [];
+ let rdecode = /(%[\dA-F]{2})+/gi;
+ for (let i = 0; i < cookies.length; i++) {
+ let parts = cookies[i].split("=");
+ let cookie = parts.slice(1).join("=");
+ if (cookie.charAt(0) === '"') {
+ cookie = cookie.slice(1, -1);
}
- const otherAmountDiv = document.querySelector(".en__field--donationAmt .en__field__item--other");
- if (otherAmountDiv) {
- otherAmountDiv.setAttribute("data-currency-symbol", engrid_ENGrid.getCurrencySymbol());
+ try {
+ let name = parts[0].replace(rdecode, decodeURIComponent);
+ result[name] = cookie.replace(rdecode, decodeURIComponent);
}
- // Add a payment type data attribute
- const paymentTypeSelect = engrid_ENGrid.getField("transaction.paymenttype");
- if (paymentTypeSelect) {
- engrid_ENGrid.setBodyData("payment-type", paymentTypeSelect.value);
- paymentTypeSelect.addEventListener("change", () => {
- engrid_ENGrid.setBodyData("payment-type", paymentTypeSelect.value);
- });
+ catch (e) {
+ // ignore cookies with invalid name/value encoding
}
- // Footer in Viewport Check
- const contentFooter = document.querySelector(".content-footer");
- if (contentFooter && engrid_ENGrid.isInViewport(contentFooter)) {
- engrid_ENGrid.setBodyData("footer-above-fold", "");
+ }
+ return result;
+}
+function getAll() {
+ return parse(document.cookie);
+}
+function get(name) {
+ return getAll()[name];
+}
+function set(name, value, attributes) {
+ document.cookie = encode(name, value, Object.assign({ path: "/" }, attributes));
+}
+function remove(name, attributes) {
+ set(name, "", Object.assign(Object.assign({}, attributes), { expires: -1 }));
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/translate-fields.js
+// Component to translate fields based on the country selected
+// It will also adapt the state field to the country selected
+
+
+class TranslateFields {
+ constructor() {
+ this.countryToStateFields = {
+ "supporter.country": "supporter.region",
+ "transaction.shipcountry": "transaction.shipregion",
+ "supporter.billingCountry": "supporter.billingRegion",
+ "transaction.infcountry": "transaction.infreg",
+ };
+ this.countriesSelect = document.querySelectorAll('select[name="supporter.country"], select[name="transaction.shipcountry"], select[name="supporter.billingCountry"], select[name="transaction.infcountry"]');
+ let options = "EngridTranslate" in window ? window.EngridTranslate : {};
+ this.options = TranslateOptionsDefaults;
+ // Don't run this for US-only forms.
+ if (document.querySelector(".en__component--formblock.us-only-form .en__field--country")) {
+ return;
}
- else {
- engrid_ENGrid.setBodyData("footer-below-fold", "");
+ if (options) {
+ for (let key in options) {
+ this.options[key] = this.options[key]
+ ? [...this.options[key], ...options[key]]
+ : options[key];
+ }
}
- // Add demo data attribute
- if (engrid_ENGrid.demo)
- engrid_ENGrid.setBodyData("demo", "");
- // Add data-first-page and data-last-page
- if (engrid_ENGrid.getPageNumber() === 1) {
- engrid_ENGrid.setBodyData("first-page", "");
+ //Storing these values on load so we can set them back after the translation/swap.
+ let countryAndStateValuesOnLoad = {};
+ if (this.countriesSelect && this.countriesSelect.length > 0) {
+ this.countriesSelect.forEach((select) => {
+ select.addEventListener("change", this.translateFields.bind(this, select.name));
+ if (select.value) {
+ countryAndStateValuesOnLoad[select.name] = select.value;
+ }
+ const stateField = document.querySelector(`select[name="${this.countryToStateFields[select.name]}"]`);
+ if (stateField) {
+ stateField.addEventListener("change", this.rememberState.bind(this, select.name));
+ if (stateField.value) {
+ countryAndStateValuesOnLoad[stateField.name] = stateField.value;
+ }
+ }
+ });
+ this.translateFields("supporter.country");
+ //dont set these back if submission failed. EN / cookie will handle it.
+ const submissionFailed = !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
+ window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
+ if (!submissionFailed) {
+ for (let field in countryAndStateValuesOnLoad) {
+ engrid_ENGrid.setFieldValue(field, countryAndStateValuesOnLoad[field], false);
+ }
+ }
}
- if (engrid_ENGrid.getPageNumber() === engrid_ENGrid.getPageCount()) {
- engrid_ENGrid.setBodyData("last-page", "");
+ }
+ translateFields(countryName = "supporter.country") {
+ this.resetTranslatedFields();
+ const countryValue = engrid_ENGrid.getFieldValue(countryName);
+ // Translate the State Field
+ this.setStateField(countryValue, this.countryToStateFields[countryName]);
+ if (countryName === "supporter.country") {
+ if (countryValue in this.options) {
+ this.options[countryValue].forEach((field) => {
+ // console.log(field);
+ this.translateField(field.field, field.translation);
+ });
+ }
+ // Translate the "To:"
+ const recipient_block = document.querySelectorAll(".recipient-block");
+ if (!!recipient_block.length) {
+ switch (countryValue) {
+ case "FR":
+ case "FRA":
+ case "France":
+ recipient_block.forEach((elem) => (elem.innerHTML = "Γ:"));
+ break;
+ case "DE":
+ case "DEU":
+ case "Germany":
+ recipient_block.forEach((elem) => (elem.innerHTML = "Zu:"));
+ break;
+ case "NL":
+ case "NLD":
+ case "Netherlands":
+ recipient_block.forEach((elem) => (elem.innerHTML = "Aan:"));
+ break;
+ }
+ }
}
- // "Temporary solutions are forever, you know..."
- // - Fernando Santos
- // "I know, but what if we just..."
- // - Bryan Casler
- // Add data attribute if browser does not support :has selector
- if (!CSS.supports("selector(:has(*))")) {
- engrid_ENGrid.setBodyData("css-has-selector", "false");
+ }
+ translateField(name, translation) {
+ const field = document.querySelector(`[name="${name}"]`);
+ if (field) {
+ const fieldWrapper = field.closest(".en__field");
+ if (fieldWrapper) {
+ const fieldLabel = fieldWrapper.querySelector(".en__field__label");
+ // Check if there's the simple country select class
+ const simplecountriesSelect = fieldLabel.querySelector(".engrid-simple-country");
+ let simplecountriesSelectClone = simplecountriesSelect
+ ? simplecountriesSelect.cloneNode(true)
+ : null;
+ if (field instanceof HTMLInputElement && field.placeholder != "") {
+ if (!fieldLabel || fieldLabel.innerHTML == field.placeholder) {
+ field.dataset.original = field.placeholder;
+ field.placeholder = translation;
+ }
+ }
+ if (fieldLabel) {
+ fieldLabel.dataset.original = fieldLabel.innerHTML;
+ fieldLabel.innerHTML = translation;
+ if (simplecountriesSelectClone) {
+ fieldLabel.appendChild(simplecountriesSelectClone);
+ }
+ }
+ }
}
- if (engrid_ENGrid.getPageType() === "DONATION") {
- this.addFrequencyDataAttribute();
- this.addGiftAmountDataAttribute();
+ }
+ resetTranslatedFields() {
+ const fields = document.querySelectorAll("[data-original]");
+ fields.forEach((field) => {
+ if (field instanceof HTMLInputElement && field.dataset.original) {
+ field.placeholder = field.dataset.original;
+ }
+ else {
+ // Check if there's the simple country select class
+ const simplecountriesSelect = field.querySelector(".engrid-simple-country");
+ let simplecountriesSelectClone = simplecountriesSelect
+ ? simplecountriesSelect.cloneNode(true)
+ : null;
+ field.innerHTML = field.dataset.original;
+ if (simplecountriesSelectClone) {
+ field.appendChild(simplecountriesSelectClone);
+ }
+ }
+ field.removeAttribute("data-original");
+ });
+ }
+ setStateField(country, state) {
+ switch (country) {
+ case "ES":
+ case "ESP":
+ case "Spain":
+ this.setStateValues(state, "Provincia", null);
+ break;
+ case "BR":
+ case "BRA":
+ case "Brazil":
+ this.setStateValues(state, "Estado", null);
+ break;
+ case "FR":
+ case "FRA":
+ case "France":
+ this.setStateValues(state, "RΓ©gion", null);
+ break;
+ case "GB":
+ case "GBR":
+ case "United Kingdom":
+ this.setStateValues(state, "State/Region", null);
+ break;
+ case "DE":
+ case "DEU":
+ case "Germany":
+ this.setStateValues(state, "Bundesland", null);
+ break;
+ case "NL":
+ case "NLD":
+ case "Netherlands":
+ this.setStateValues(state, "Provincie", null);
+ break;
+ case "AU":
+ case "AUS":
+ this.setStateValues(state, "Province / State", [
+ { label: "Select", value: "" },
+ { label: "New South Wales", value: "NSW" },
+ { label: "Victoria", value: "VIC" },
+ { label: "Queensland", value: "QLD" },
+ { label: "South Australia", value: "SA" },
+ { label: "Western Australia", value: "WA" },
+ { label: "Tasmania", value: "TAS" },
+ { label: "Northern Territory", value: "NT" },
+ { label: "Australian Capital Territory", value: "ACT" },
+ ]);
+ break;
+ case "Australia":
+ this.setStateValues(state, "Province / State", [
+ { label: "Select", value: "" },
+ { label: "New South Wales", value: "New South Wales" },
+ { label: "Victoria", value: "Victoria" },
+ { label: "Queensland", value: "Queensland" },
+ { label: "South Australia", value: "South Australia" },
+ { label: "Western Australia", value: "Western Australia" },
+ { label: "Tasmania", value: "Tasmania" },
+ { label: "Northern Territory", value: "Northern Territory" },
+ {
+ label: "Australian Capital Territory",
+ value: "Australian Capital Territory",
+ },
+ ]);
+ break;
+ case "US":
+ case "USA":
+ this.setStateValues(state, "State", [
+ { label: "Select State", value: "" },
+ { label: "Alabama", value: "AL" },
+ { label: "Alaska", value: "AK" },
+ { label: "Arizona", value: "AZ" },
+ { label: "Arkansas", value: "AR" },
+ { label: "California", value: "CA" },
+ { label: "Colorado", value: "CO" },
+ { label: "Connecticut", value: "CT" },
+ { label: "Delaware", value: "DE" },
+ { label: "District of Columbia", value: "DC" },
+ { label: "Florida", value: "FL" },
+ { label: "Georgia", value: "GA" },
+ { label: "Hawaii", value: "HI" },
+ { label: "Idaho", value: "ID" },
+ { label: "Illinois", value: "IL" },
+ { label: "Indiana", value: "IN" },
+ { label: "Iowa", value: "IA" },
+ { label: "Kansas", value: "KS" },
+ { label: "Kentucky", value: "KY" },
+ { label: "Louisiana", value: "LA" },
+ { label: "Maine", value: "ME" },
+ { label: "Maryland", value: "MD" },
+ { label: "Massachusetts", value: "MA" },
+ { label: "Michigan", value: "MI" },
+ { label: "Minnesota", value: "MN" },
+ { label: "Mississippi", value: "MS" },
+ { label: "Missouri", value: "MO" },
+ { label: "Montana", value: "MT" },
+ { label: "Nebraska", value: "NE" },
+ { label: "Nevada", value: "NV" },
+ { label: "New Hampshire", value: "NH" },
+ { label: "New Jersey", value: "NJ" },
+ { label: "New Mexico", value: "NM" },
+ { label: "New York", value: "NY" },
+ { label: "North Carolina", value: "NC" },
+ { label: "North Dakota", value: "ND" },
+ { label: "Ohio", value: "OH" },
+ { label: "Oklahoma", value: "OK" },
+ { label: "Oregon", value: "OR" },
+ { label: "Pennsylvania", value: "PA" },
+ { label: "Rhode Island", value: "RI" },
+ { label: "South Carolina", value: "SC" },
+ { label: "South Dakota", value: "SD" },
+ { label: "Tennessee", value: "TN" },
+ { label: "Texas", value: "TX" },
+ { label: "Utah", value: "UT" },
+ { label: "Vermont", value: "VT" },
+ { label: "Virginia", value: "VA" },
+ { label: "Washington", value: "WA" },
+ { label: "West Virginia", value: "WV" },
+ { label: "Wisconsin", value: "WI" },
+ { label: "Wyoming", value: "WY" },
+ {
+ label: "── US Territories ──",
+ value: "",
+ disabled: true,
+ },
+ { label: "American Samoa", value: "AS" },
+ { label: "Guam", value: "GU" },
+ { label: "Northern Mariana Islands", value: "MP" },
+ { label: "Puerto Rico", value: "PR" },
+ { label: "US Minor Outlying Islands", value: "UM" },
+ { label: "Virgin Islands", value: "VI" },
+ {
+ label: "── Armed Forces ──",
+ value: "",
+ disabled: true,
+ },
+ { label: "Armed Forces Americas", value: "AA" },
+ { label: "Armed Forces Africa", value: "AE" },
+ { label: "Armed Forces Canada", value: "AE" },
+ { label: "Armed Forces Europe", value: "AE" },
+ { label: "Armed Forces Middle East", value: "AE" },
+ { label: "Armed Forces Pacific", value: "AP" },
+ ]);
+ break;
+ case "United States":
+ this.setStateValues(state, "State", [
+ { label: "Select State", value: "" },
+ { label: "Alabama", value: "Alabama" },
+ { label: "Alaska", value: "Alaska" },
+ { label: "Arizona", value: "Arizona" },
+ { label: "Arkansas", value: "Arkansas" },
+ { label: "California", value: "California" },
+ { label: "Colorado", value: "Colorado" },
+ { label: "Connecticut", value: "Connecticut" },
+ { label: "Delaware", value: "Delaware" },
+ { label: "District of Columbia", value: "District of Columbia" },
+ { label: "Florida", value: "Florida" },
+ { label: "Georgia", value: "Georgia" },
+ { label: "Hawaii", value: "Hawaii" },
+ { label: "Idaho", value: "Idaho" },
+ { label: "Illinois", value: "Illinois" },
+ { label: "Indiana", value: "Indiana" },
+ { label: "Iowa", value: "Iowa" },
+ { label: "Kansas", value: "Kansas" },
+ { label: "Kentucky", value: "Kentucky" },
+ { label: "Louisiana", value: "Louisiana" },
+ { label: "Maine", value: "Maine" },
+ { label: "Maryland", value: "Maryland" },
+ { label: "Massachusetts", value: "Massachusetts" },
+ { label: "Michigan", value: "Michigan" },
+ { label: "Minnesota", value: "Minnesota" },
+ { label: "Mississippi", value: "Mississippi" },
+ { label: "Missouri", value: "Missouri" },
+ { label: "Montana", value: "Montana" },
+ { label: "Nebraska", value: "Nebraska" },
+ { label: "Nevada", value: "Nevada" },
+ { label: "New Hampshire", value: "New Hampshire" },
+ { label: "New Jersey", value: "New Jersey" },
+ { label: "New Mexico", value: "New Mexico" },
+ { label: "New York", value: "New York" },
+ { label: "North Carolina", value: "North Carolina" },
+ { label: "North Dakota", value: "North Dakota" },
+ { label: "Ohio", value: "Ohio" },
+ { label: "Oklahoma", value: "Oklahoma" },
+ { label: "Oregon", value: "Oregon" },
+ { label: "Pennsylvania", value: "Pennsylvania" },
+ { label: "Rhode Island", value: "Rhode Island" },
+ { label: "South Carolina", value: "South Carolina" },
+ { label: "South Dakota", value: "South Dakota" },
+ { label: "Tennessee", value: "Tennessee" },
+ { label: "Texas", value: "Texas" },
+ { label: "Utah", value: "Utah" },
+ { label: "Vermont", value: "Vermont" },
+ { label: "Virginia", value: "Virginia" },
+ { label: "Washington", value: "Washington" },
+ { label: "West Virginia", value: "West Virginia" },
+ { label: "Wisconsin", value: "Wisconsin" },
+ { label: "Wyoming", value: "Wyoming" },
+ {
+ label: "── US Territories ──",
+ value: "",
+ disabled: true,
+ },
+ { label: "American Samoa", value: "American Samoa" },
+ { label: "Guam", value: "Guam" },
+ {
+ label: "Northern Mariana Islands",
+ value: "Northern Mariana Islands",
+ },
+ { label: "Puerto Rico", value: "Puerto Rico" },
+ {
+ label: "US Minor Outlying Islands",
+ value: "US Minor Outlying Islands",
+ },
+ { label: "Virgin Islands", value: "Virgin Islands" },
+ {
+ label: "── Armed Forces ──",
+ value: "",
+ disabled: true,
+ },
+ { label: "Armed Forces Americas", value: "Armed Forces Americas" },
+ { label: "Armed Forces Africa", value: "Armed Forces Africa" },
+ { label: "Armed Forces Canada", value: "Armed Forces Canada" },
+ { label: "Armed Forces Europe", value: "Armed Forces Europe" },
+ {
+ label: "Armed Forces Middle East",
+ value: "Armed Forces Middle East",
+ },
+ { label: "Armed Forces Pacific", value: "Armed Forces Pacific" },
+ ]);
+ break;
+ case "CA":
+ case "CAN":
+ this.setStateValues(state, "Province / Territory", [
+ { label: "Select", value: "" },
+ { label: "Alberta", value: "AB" },
+ { label: "British Columbia", value: "BC" },
+ { label: "Manitoba", value: "MB" },
+ { label: "New Brunswick", value: "NB" },
+ { label: "Newfoundland and Labrador", value: "NL" },
+ { label: "Northwest Territories", value: "NT" },
+ { label: "Nova Scotia", value: "NS" },
+ { label: "Nunavut", value: "NU" },
+ { label: "Ontario", value: "ON" },
+ { label: "Prince Edward Island", value: "PE" },
+ { label: "Quebec", value: "QC" },
+ { label: "Saskatchewan", value: "SK" },
+ { label: "Yukon", value: "YT" },
+ ]);
+ break;
+ case "Canada":
+ this.setStateValues(state, "Province / Territory", [
+ { label: "Select", value: "" },
+ { label: "Alberta", value: "Alberta" },
+ { label: "British Columbia", value: "British Columbia" },
+ { label: "Manitoba", value: "Manitoba" },
+ { label: "New Brunswick", value: "New Brunswick" },
+ {
+ label: "Newfoundland and Labrador",
+ value: "Newfoundland and Labrador",
+ },
+ { label: "Northwest Territories", value: "Northwest Territories" },
+ { label: "Nova Scotia", value: "Nova Scotia" },
+ { label: "Nunavut", value: "Nunavut" },
+ { label: "Ontario", value: "Ontario" },
+ { label: "Prince Edward Island", value: "Prince Edward Island" },
+ { label: "Quebec", value: "Quebec" },
+ { label: "Saskatchewan", value: "Saskatchewan" },
+ { label: "Yukon", value: "Yukon" },
+ ]);
+ break;
+ case "MX":
+ case "MEX":
+ this.setStateValues(state, "Estado", [
+ { label: "Seleccione Estado", value: "" },
+ { label: "Aguascalientes", value: "AGU" },
+ { label: "Baja California", value: "BCN" },
+ { label: "Baja California Sur", value: "BCS" },
+ { label: "Campeche", value: "CAM" },
+ { label: "Chiapas", value: "CHP" },
+ { label: "Ciudad de Mexico", value: "CMX" },
+ { label: "Chihuahua", value: "CHH" },
+ { label: "Coahuila", value: "COA" },
+ { label: "Colima", value: "COL" },
+ { label: "Durango", value: "DUR" },
+ { label: "Guanajuato", value: "GUA" },
+ { label: "Guerrero", value: "GRO" },
+ { label: "Hidalgo", value: "HID" },
+ { label: "Jalisco", value: "JAL" },
+ { label: "Michoacan", value: "MIC" },
+ { label: "Morelos", value: "MOR" },
+ { label: "Nayarit", value: "NAY" },
+ { label: "Nuevo Leon", value: "NLE" },
+ { label: "Oaxaca", value: "OAX" },
+ { label: "Puebla", value: "PUE" },
+ { label: "Queretaro", value: "QUE" },
+ { label: "Quintana Roo", value: "ROO" },
+ { label: "San Luis Potosi", value: "SLP" },
+ { label: "Sinaloa", value: "SIN" },
+ { label: "Sonora", value: "SON" },
+ { label: "Tabasco", value: "TAB" },
+ { label: "Tamaulipas", value: "TAM" },
+ { label: "Tlaxcala", value: "TLA" },
+ { label: "Veracruz", value: "VER" },
+ { label: "Yucatan", value: "YUC" },
+ { label: "Zacatecas", value: "ZAC" },
+ ]);
+ break;
+ case "Mexico":
+ this.setStateValues(state, "Estado", [
+ { label: "Seleccione Estado", value: "" },
+ { label: "Aguascalientes", value: "Aguascalientes" },
+ { label: "Baja California", value: "Baja California" },
+ { label: "Baja California Sur", value: "Baja California Sur" },
+ { label: "Campeche", value: "Campeche" },
+ { label: "Chiapas", value: "Chiapas" },
+ { label: "Ciudad de Mexico", value: "Ciudad de Mexico" },
+ { label: "Chihuahua", value: "Chihuahua" },
+ { label: "Coahuila", value: "Coahuila" },
+ { label: "Colima", value: "Colima" },
+ { label: "Durango", value: "Durango" },
+ { label: "Guanajuato", value: "Guanajuato" },
+ { label: "Guerrero", value: "Guerrero" },
+ { label: "Hidalgo", value: "Hidalgo" },
+ { label: "Jalisco", value: "Jalisco" },
+ { label: "Michoacan", value: "Michoacan" },
+ { label: "Morelos", value: "Morelos" },
+ { label: "Nayarit", value: "Nayarit" },
+ { label: "Nuevo Leon", value: "Nuevo Leon" },
+ { label: "Oaxaca", value: "Oaxaca" },
+ { label: "Puebla", value: "Puebla" },
+ { label: "Queretaro", value: "Queretaro" },
+ { label: "Quintana Roo", value: "Quintana Roo" },
+ { label: "San Luis Potosi", value: "San Luis Potosi" },
+ { label: "Sinaloa", value: "Sinaloa" },
+ { label: "Sonora", value: "Sonora" },
+ { label: "Tabasco", value: "Tabasco" },
+ { label: "Tamaulipas", value: "Tamaulipas" },
+ { label: "Tlaxcala", value: "Tlaxcala" },
+ { label: "Veracruz", value: "Veracruz" },
+ { label: "Yucatan", value: "Yucatan" },
+ { label: "Zacatecas", value: "Zacatecas" },
+ ]);
+ break;
+ default:
+ this.setStateValues(state, "Province / State", null);
+ break;
}
}
- // Add a data attribute to the body tag with how many visible frequency options there are
- addFrequencyDataAttribute() {
- const frequencyOptions = document.querySelectorAll(".en__field--recurrfreq .en__field__item label.en__field__label");
- let visibleFrequencyOptions = 0;
- frequencyOptions.forEach((option) => {
- if (engrid_ENGrid.isVisible(option)) {
- visibleFrequencyOptions++;
+ setStateValues(state, label, values) {
+ const stateField = engrid_ENGrid.getField(state);
+ const stateWrapper = stateField ? stateField.closest(".en__field") : null;
+ if (stateWrapper) {
+ const stateLabel = stateWrapper.querySelector(".en__field__label");
+ const elementWrapper = stateWrapper.querySelector(".en__field__element");
+ if (stateLabel) {
+ stateLabel.innerHTML = label;
}
- });
- engrid_ENGrid.setBodyData("visible-frequency", visibleFrequencyOptions.toString());
- }
- // Add a data attribute to the body tag with how many visible gift amount options there are
- addGiftAmountDataAttribute() {
- const updateGiftAmountData = () => {
- const giftAmountOptions = document.querySelectorAll(".en__field--donationAmt .en__field__element .en__field__item");
- let visibleGiftAmountOptions = 0;
- giftAmountOptions.forEach((option) => {
- if (engrid_ENGrid.isVisible(option)) {
- visibleGiftAmountOptions++;
+ if (elementWrapper) {
+ const selectedState = get(`engrid-state-${state}`);
+ if (values === null || values === void 0 ? void 0 : values.length) {
+ const select = document.createElement("select");
+ select.name = state;
+ select.id = "en__field_" + state.toLowerCase().replace(".", "_");
+ select.classList.add("en__field__input");
+ select.classList.add("en__field__input--select");
+ select.autocomplete = "address-level1";
+ let valueSelected = false;
+ values.forEach((value) => {
+ const option = document.createElement("option");
+ option.value = value.value;
+ option.innerHTML = value.label;
+ if (selectedState === value.value && !valueSelected) {
+ option.selected = true;
+ valueSelected = true;
+ }
+ if (value.disabled) {
+ option.disabled = true;
+ }
+ select.appendChild(option);
+ });
+ elementWrapper.innerHTML = "";
+ elementWrapper.appendChild(select);
+ select.addEventListener("change", this.rememberState.bind(this, state));
+ select.dispatchEvent(new Event("change", { bubbles: true }));
}
- });
- engrid_ENGrid.setBodyData("visible-gift-amount", visibleGiftAmountOptions.toString());
- this.logger.log("Visible Gift Amount Changed to: " + visibleGiftAmountOptions.toString());
- };
- // Initial update
- updateGiftAmountData();
- // Observe changes in the donation amount section
- const observer = new MutationObserver(updateGiftAmountData);
- const targetNode = document.querySelector(".en__field--donationAmt");
- if (targetNode) {
- observer.observe(targetNode, {
- childList: true,
- subtree: true,
- attributes: true,
+ else {
+ elementWrapper.innerHTML = "";
+ const input = document.createElement("input");
+ input.type = "text";
+ input.name = state;
+ input.placeholder = label;
+ input.id = "en__field_" + state.toLowerCase().replace(".", "_");
+ input.classList.add("en__field__input");
+ input.classList.add("en__field__input--text");
+ input.autocomplete = "address-level1";
+ if (selectedState) {
+ input.value = selectedState;
+ }
+ elementWrapper.appendChild(input);
+ input.addEventListener("change", this.rememberState.bind(this, state));
+ }
+ }
+ }
+ }
+ rememberState(state) {
+ const stateField = engrid_ENGrid.getField(state);
+ if (stateField) {
+ set(`engrid-state-${stateField.name}`, stateField.value, {
+ expires: 1,
+ sameSite: "none",
+ secure: true,
});
}
- // Run update updateGiftAmountData when frequency changes
- this._frequency.onFrequencyChange.subscribe(() => {
- setTimeout(() => {
- updateGiftAmountData();
- }, 10);
- });
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/iframe.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/auto-country-select.js
+// This class works when the user has added ".simple_country_select" as a class in page builder for the Country select
-class iFrame {
+class AutoCountrySelect {
constructor() {
- this._form = en_form_EnForm.getInstance();
- this.logger = new logger_EngridLogger("iFrame", "brown", "gray", "π‘");
- if (this.inIframe()) {
- // Add the data-engrid-embedded attribute when inside an iFrame if it wasn't already added by a script in the Page Template
- engrid_ENGrid.setBodyData("embedded", "");
- // Check if the parent page URL matches the criteria for a thank you page donation
- const getParentUrl = () => {
- try {
- return window.parent.location.href;
- }
- catch (e) {
- // If we can't access parent location due to same-origin policy, fall back to referrer
- return document.referrer;
- }
- };
- const parentUrl = getParentUrl();
- const thankYouPageRegex = /\/page\/\d+\/[^\/]+\/(\d+)(\?|$)/;
- const match = parentUrl.match(thankYouPageRegex);
- if (match) {
- const pageNumber = parseInt(match[1], 10);
- if (pageNumber > 1) {
- engrid_ENGrid.setBodyData("embedded", "thank-you-page-donation");
- this.hideFormComponents();
- this.logger.log("iFrame Event - Set embedded attribute to thank-you-page-donation");
- }
- }
- // Fire the resize event
- this.logger.log("iFrame Event - Begin Resizing");
- // Run onLoaded function
- console.log("document.readyState", document.readyState);
- // Document Load
- if (document.readyState !== "loading") {
- this.onLoaded();
- }
- else {
- document.addEventListener("DOMContentLoaded", () => {
- this.onLoaded();
- });
- }
- window.setTimeout(() => {
- this.sendIframeHeight();
- }, 300);
- window.addEventListener("resize", this.debounceWithImmediate(() => {
- this.logger.log("iFrame Event - window resized");
- this.sendIframeHeight();
- }));
- // Listen for the form submit event
- this._form.onSubmit.subscribe((e) => {
- this.logger.log("iFrame Event - onSubmit");
- this.sendIframeFormStatus("submit");
- });
- // If the iFrame is Chained, check if the form has data
- if (this.isChained() && engrid_ENGrid.getPaymentType()) {
- this.logger.log("iFrame Event - Chained iFrame");
- this.sendIframeFormStatus("chained");
- // this.addChainedBanner();
- }
- // Remove the skip link markup when inside an iFrame
- const skipLink = document.querySelector(".skip-link");
- if (skipLink) {
- skipLink.remove();
- }
- this._form.onError.subscribe(() => {
- // Get the first .en__field--validationFailed element
- const firstError = document.querySelector(".en__field--validationFailed");
- // Send scrollTo message
- // Parent pages listens for this message and scrolls to the correct position
- const scrollTo = firstError
- ? firstError.getBoundingClientRect().top
- : 0;
- this.logger.log(`iFrame Event 'scrollTo' - Position of top of first error ${scrollTo} px`); // check the message is being sent correctly
- window.parent.postMessage({ scrollTo }, "*");
- // Send the height of the iFrame
- window.setTimeout(() => {
- this.sendIframeHeight();
- }, 100);
+ this._countryEvent = Country.getInstance();
+ this.countryWrapper = document.querySelector(".simple_country_select");
+ this.countrySelect = this._countryEvent
+ .countryField;
+ this.country = null;
+ const engridAutofill = get("engrid-autofill");
+ const submissionFailed = !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
+ const hasIntlSupport = !!engrid_ENGrid.checkNested(window.Intl, "DisplayNames");
+ // Only run if there's no engrid-autofill cookie && if it has Intl support && no country data in url
+ const locationDataInUrl = engrid_ENGrid.getUrlParameter("supporter.country") ||
+ engrid_ENGrid.getUrlParameter("supporter.region") ||
+ (engrid_ENGrid.getUrlParameter("ea.url.id") &&
+ !engrid_ENGrid.getUrlParameter("forwarded"));
+ // If fast form is active, then personal details have already been filled somehow and we should not override the country selection
+ // The client is also likely using WelcomeBack.
+ const fastFormActive = engrid_ENGrid.getBodyData("hide-fast-address-details") ||
+ engrid_ENGrid.getBodyData("hide-fast-personal-details");
+ if (!engridAutofill &&
+ !submissionFailed &&
+ hasIntlSupport &&
+ !locationDataInUrl &&
+ !fastFormActive) {
+ fetch(`https://${window.location.hostname}/cdn-cgi/trace`)
+ .then((res) => res.text())
+ .then((t) => {
+ let data = t.replace(/[\r\n]+/g, '","').replace(/\=+/g, '":"');
+ data = '{"' + data.slice(0, data.lastIndexOf('","')) + '"}';
+ const jsondata = JSON.parse(data);
+ this.country = jsondata.loc;
+ this.init();
+ // console.log("Country:", this.country);
});
}
else {
- // When not in iframe, default behaviour, smooth scroll to first error
- this._form.onError.subscribe(() => {
- // Smooth Scroll to the first .en__field--validationFailed element
- const firstError = document.querySelector(".en__field--validationFailed");
- if (firstError) {
- firstError.scrollIntoView({ behavior: "smooth" });
- }
- });
- // Parent Page Logic (when an ENgrid form is embedded in an ENgrid page)
- window.addEventListener("message", (event) => {
- const iframe = this.getIFrameByEvent(event);
- if (iframe) {
- if (event.data.hasOwnProperty("frameHeight")) {
- iframe.style.height = event.data.frameHeight + "px";
- if (event.data.frameHeight > 0) {
- iframe.classList.add("loaded");
- }
- else {
- iframe.classList.remove("loaded");
- }
- }
- // Old scroll event logic "scroll", scrolls to correct iframe?
- else if (event.data.hasOwnProperty("scroll") &&
- event.data.scroll > 0) {
- const elDistanceToTop = window.pageYOffset + iframe.getBoundingClientRect().top;
- let scrollTo = elDistanceToTop + event.data.scroll;
- window.scrollTo({
- top: scrollTo,
- left: 0,
- behavior: "smooth",
- });
- this.logger.log("iFrame Event - Scrolling Window to " + scrollTo);
- }
- // New scroll event logic "scrollTo", scrolls to the first error
- else if (event.data.hasOwnProperty("scrollTo")) {
- const scrollToPosition = event.data.scrollTo +
- window.scrollY +
- iframe.getBoundingClientRect().top;
- window.scrollTo({
- top: scrollToPosition,
- left: 0,
- behavior: "smooth",
- });
- this.logger.log("iFrame Event - Scrolling Window to " + scrollToPosition);
- }
- }
- });
+ this.init();
}
}
- onLoaded() {
- // Scroll to top of iFrame
- this.logger.log("iFrame Event - window.onload");
- this.sendIframeHeight();
- window.parent.postMessage({
- scroll: this.shouldScroll(),
- }, "*");
- // Iframe Queue: signal Thank-You-page completion to the parent window.
- // The IframeQueue component (in parent mode) listens for this ping and
- // matches it by Page ID to advance to the next queued iframe. Fires
- // exactly once per Thank-You-page load. See iframe-queue.ts.
- this.sendIframeQueueThankYouPing();
- // On click fire the resize event
- document.addEventListener("click", (e) => {
- this.logger.log("iFrame Event - click");
- setTimeout(() => {
- this.sendIframeHeight();
- }, 100);
- });
- // Watch for errors and send the height
- engrid_ENGrid.watchForError(this.sendIframeHeight.bind(this));
- }
- /**
- * Posts a `engrid-iframe-queue:thank-you` message to the parent window
- * when the embedded EN page reaches its Thank You page (the last page
- * in the page sequence). Carries the Page ID of the submitting form so
- * the IframeQueue parent can match the ping against the queued item it
- * is waiting on, ignoring pings from unrelated EN iframes that may exist
- * on the same parent page (e.g. an Embedded Ecard iframe).
- *
- * Only fires when:
- * - the script is running inside an iframe (already guaranteed by the
- * code path that calls onLoaded()), AND
- * - the embedded page is a Thank You page (ENGrid.isThankYouPage()).
- *
- * Consumed by: IframeQueue (engrid/packages/scripts/src/iframe-queue.ts).
- */
- sendIframeQueueThankYouPing() {
- if (!engrid_ENGrid.isThankYouPage())
- return;
- const pageId = engrid_ENGrid.getPageID();
- const message = {
- type: "engrid-iframe-queue:thank-you",
- pageId,
- pageNumber: engrid_ENGrid.getPageNumber(),
- pageCount: engrid_ENGrid.getPageCount(),
- url: window.location.href,
- };
- this.logger.log(`iFrame Event - Iframe Queue thank-you ping (pageId=${pageId})`);
- window.parent.postMessage(message, "*");
- }
- sendIframeHeight() {
- let height = document.body.offsetHeight;
- this.logger.log("iFrame Event - Sending iFrame height of: " + height + "px"); // check the message is being sent correctly
- window.parent.postMessage({
- frameHeight: height,
- pageNumber: engrid_ENGrid.getPageNumber(),
- pageCount: engrid_ENGrid.getPageCount(),
- giftProcess: engrid_ENGrid.getGiftProcess(),
- }, "*");
- }
- sendIframeFormStatus(status) {
- window.parent.postMessage({
- status: status,
- pageNumber: engrid_ENGrid.getPageNumber(),
- pageCount: engrid_ENGrid.getPageCount(),
- giftProcess: engrid_ENGrid.getGiftProcess(),
- }, "*");
+ init() {
+ if (this.countrySelect) {
+ if (this.country) {
+ const countriesNames = new Intl.DisplayNames(["en"], {
+ type: "region",
+ });
+ // We are setting the country by Name because the ISO code is not always the same. They have 2 and 3 letter codes.
+ this.setCountryByName(countriesNames.of(this.country), this.country);
+ }
+ }
}
- getIFrameByEvent(event) {
- return [].slice
- .call(document.getElementsByTagName("iframe"))
- .filter((iframe) => {
- return iframe.contentWindow === event.source;
- })[0];
+ setCountryByName(countryName, countryCode) {
+ if (this.countrySelect) {
+ let countrySelectOptions = this.countrySelect.options;
+ for (let i = 0; i < countrySelectOptions.length; i++) {
+ if (countrySelectOptions[i].innerHTML.toLowerCase() ==
+ countryName.toLowerCase() ||
+ countrySelectOptions[i].value.toLowerCase() ==
+ countryCode.toLowerCase()) {
+ this.countrySelect.selectedIndex = i;
+ break;
+ }
+ }
+ const event = new Event("change", { bubbles: true });
+ this.countrySelect.dispatchEvent(event);
+ }
}
- shouldScroll() {
- // If you find a error, scroll
- if (document.querySelector(".en__errorHeader")) {
- return true;
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/skip-link.js
+// Javascript that adds an accessible "Skip Link" button after the opening that jumps to
+// the first or field in a "body-" section, or the first if none are found
+// in those sections
+// Depends on _engrid-skip-link.scss
+
+class SkipToMainContentLink {
+ constructor() {
+ const firstTitleInEngridBody = document.querySelector("div[class*='body-'] title");
+ const firstH1InEngridBody = document.querySelector("div[class*='body-'] h1");
+ const firstTitle = document.querySelector("title");
+ const firstH1 = document.querySelector("h1");
+ if (firstTitleInEngridBody && firstTitleInEngridBody.parentElement) {
+ firstTitleInEngridBody.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
}
- // If it's a chained iFrame, don't scroll
- if (this.isChained()) {
- return false;
+ else if (firstH1InEngridBody && firstH1InEngridBody.parentElement) {
+ firstH1InEngridBody.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
}
- // Try to match the iframe referrer URL by testing valid EN Page URLs
- let referrer = document.referrer;
- let enURLPattern = new RegExp(/^(.*)\/(page)\/(\d+.*)/);
- // Scroll if the Regex matches, don't scroll otherwise
- return enURLPattern.test(referrer);
- }
- inIframe() {
- try {
- return window.self !== window.top;
+ else if (firstTitle && firstTitle.parentElement) {
+ firstTitle.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
}
- catch (e) {
- return true;
+ else if (firstH1 && firstH1.parentElement) {
+ firstH1.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
+ }
+ else {
+ if (engrid_ENGrid.debug)
+ console.log("This page contains no or and a 'Skip to main content' link was not added");
}
}
- // This method checks if the URL has a parameter named "chain" and returns true if it exists, otherwise false.
- isChained() {
- return !!engrid_ENGrid.getUrlParameter("chain");
+ insertSkipLinkSpan() {
+ document.body.insertAdjacentHTML("afterbegin", 'Skip to main content ');
}
- hideFormComponents() {
- this.logger.log("iFrame Event - Hiding Form Components");
- const excludeClasses = [
- "giveBySelect-Card",
- "en__field--ccnumber",
- "en__field--survey",
- "en__component--ecardblock",
- "give-by-select",
- "give-by-select-header",
- "en__submit",
- "en__captcha",
- "force-visibility",
- "hide",
- "hide-iframe",
- "radio-to-buttons_donationAmt",
- ];
- const excludeIds = ["en__digitalWallet"];
- const components = Array.from(document.querySelectorAll(".body-main:not(.force-visibility) > div:not(:last-child)"));
- components.forEach((component) => {
- const shouldExclude = excludeClasses.some((cls) => component.classList.contains(cls) ||
- component.querySelector(`:scope > .${cls}`)) || excludeIds.some((id) => component.querySelector(`#${id}`));
- if (!shouldExclude) {
- component.classList.add("hide-iframe", "hide-chained");
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/src-defer.js
+// Build Notes: Add the vanilla Javascript version inline inside the page template right before
+// In the event the vanilla javascript is not inlined we should still process any assets with a data-src still defined on it. Plus we only process background video via this JS file as to not block the page with a large video file downloading.
+// // 4Site's simplified image lazy loader
+// var srcDefer = document.querySelectorAll("img[data-src]");
+// window.addEventListener('DOMContentLoaded', (event) => {
+// for (var i = 0; i < srcDefer.length; i++) {
+// let dataSrc = srcDefer[i].getAttribute("data-src");
+// if (dataSrc) {
+// srcDefer[i].setAttribute("decoding", "async"); // Gets image processing off the main working thread
+// srcDefer[i].setAttribute("loading", "lazy"); // Lets the browser determine when the asset should be downloaded
+// srcDefer[i].setAttribute("src", dataSrc); // Sets the src which will cause the browser to retrieve the asset
+// srcDefer[i].setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
+// srcDefer[i].removeAttribute("data-src"); // Removes the data-source
+// }
+// }
+// });
+class SrcDefer {
+ constructor() {
+ // Find all images and videos with a data-src defined
+ this.imgSrcDefer = document.querySelectorAll("img[data-src]");
+ this.videoBackground = document.querySelectorAll("video");
+ this.videoBackgroundSource = document.querySelectorAll("video source");
+ // Process images
+ for (let i = 0; i < this.imgSrcDefer.length; i++) {
+ let img = this.imgSrcDefer[i];
+ if (img) {
+ img.setAttribute("decoding", "async"); // Gets image processing off the main working thread, and decodes the image asynchronously to reduce delay in presenting other content
+ img.setAttribute("loading", "lazy"); // Lets the browser determine when the asset should be downloaded using it's native lazy loading
+ let imgDataSrc = img.getAttribute("data-src");
+ if (imgDataSrc) {
+ img.setAttribute("src", imgDataSrc); // Sets the src which will cause the browser to retrieve the asset
+ }
+ img.setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
+ img.removeAttribute("data-src"); // Removes the data-source
+ }
+ }
+ // Process video
+ for (let i = 0; i < this.videoBackground.length; i++) {
+ let video = this.videoBackground[i];
+ // Process one or more defined sources in the tag
+ this.videoBackgroundSource = video.querySelectorAll("source");
+ if (this.videoBackgroundSource) {
+ // loop through all the sources
+ for (let j = 0; j < this.videoBackgroundSource.length; j++) {
+ let videoSource = this.videoBackgroundSource[j];
+ if (videoSource) {
+ let videoBackgroundSourcedDataSrc = videoSource.getAttribute("data-src");
+ if (videoBackgroundSourcedDataSrc) {
+ videoSource.setAttribute("src", videoBackgroundSourcedDataSrc);
+ videoSource.setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
+ videoSource.removeAttribute("data-src"); // Removes the data-source
+ }
+ }
+ }
+ // To get the browser to request the video asset defined we need to remove the tag and re-add it
+ let videoBackgroundParent = video.parentNode; // Determine the parent of the tag
+ let copyOfVideoBackground = video; // Copy the tag
+ if (videoBackgroundParent && copyOfVideoBackground) {
+ videoBackgroundParent.replaceChild(copyOfVideoBackground, video); // Replace the with the copy of itself
+ // Update the video to auto play, mute, loop
+ video.muted = true; // Mute the video by default
+ video.controls = false; // Hide the browser controls
+ video.loop = true; // Loop the video
+ video.playsInline = true; // Encourage the user agent to display video content within the element's playback area
+ video.play(); // Plays the video
+ }
}
- });
- this.sendIframeHeight();
+ }
}
- showFormComponents() {
- this.logger.log("iFrame Event - Showing Form Components");
- const en__component = document.querySelectorAll(".body-main > div.hide-chained");
- en__component.forEach((component) => {
- component.classList.remove("hide-iframe");
- component.classList.remove("hide-chained");
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/set-recurr-freq.js
+
+
+class setRecurrFreq {
+ constructor() {
+ this._frequency = DonationFrequency.getInstance();
+ this._amount = DonationAmount.getInstance();
+ this.linkClass = "setRecurrFreq-";
+ this.checkboxName = "engrid.recurrfreq";
+ // Watch the links that starts with linkClass
+ document
+ .querySelectorAll(`a[class^="${this.linkClass}"]`)
+ .forEach((element) => {
+ element.addEventListener("click", (e) => {
+ // Get the right class
+ const setRecurrFreqClass = element.className
+ .split(" ")
+ .filter((linkClass) => linkClass.startsWith(this.linkClass));
+ if (engrid_ENGrid.debug)
+ console.log(setRecurrFreqClass);
+ if (setRecurrFreqClass.length) {
+ e.preventDefault();
+ engrid_ENGrid.setFieldValue("transaction.recurrfreq", setRecurrFreqClass[0]
+ .substring(this.linkClass.length)
+ .toUpperCase());
+ this._frequency.load();
+ }
+ });
});
- this.sendIframeHeight();
- }
- // private addChainedBanner() {
- // this.logger.log("iFrame Event - Adding Chained Banner");
- // const banner = document.createElement("div");
- // const lastComponent = document.querySelector(
- // ".body-main > div:last-of-type"
- // ) as HTMLDivElement;
- // banner.classList.add("en__component");
- // banner.classList.add("en__component--banner");
- // banner.classList.add("en__component--banner--chained");
- // banner.innerHTML = `
- // ${ENGrid.getFieldValue("supporter.firstName") ? `Giving as ${ENGrid.getFieldValue("supporter.firstName")} ${ENGrid.getFieldValue("supporter.lastName")} ` : "Testing as "}
- // with ${ENGrid.getFieldValue(
- // "transaction.paymenttype"
- // ).toUpperCase()}
- // (change )
`;
- // lastComponent?.parentNode?.insertBefore(banner, lastComponent);
- // banner
- // .querySelector(".en__component__content__link")
- // ?.addEventListener("click", (e) => {
- // e.preventDefault();
- // this.showFormComponents();
- // banner.remove();
- // });
- // }
- debounceWithImmediate(func, timeout = 1000) {
- let timer;
- let firstEvent = true;
- return (...args) => {
- clearTimeout(timer);
- if (firstEvent) {
- func.apply(this, args);
- firstEvent = false;
+ const currentFrequency = engrid_ENGrid.getFieldValue("transaction.recurrfreq").toUpperCase();
+ // Watch checkboxes with the name checkboxName
+ document.getElementsByName(this.checkboxName).forEach((element) => {
+ // Set checked status per currently-set frequency
+ const frequency = element.value.toUpperCase();
+ if (frequency === currentFrequency) {
+ element.checked = true;
}
- timer = setTimeout(() => {
- func.apply(this, args);
- firstEvent = true;
- }, timeout);
- };
+ else {
+ element.checked = false;
+ }
+ element.addEventListener("change", () => {
+ const frequency = element.value.toUpperCase();
+ if (element.checked) {
+ engrid_ENGrid.setFieldValue("transaction.recurrfreq", frequency);
+ engrid_ENGrid.setFieldValue("transaction.recurrpay", "Y");
+ this._frequency.load();
+ this._amount.setAmount(this._amount.amount, false);
+ }
+ else if (frequency !== "ONETIME") {
+ engrid_ENGrid.setFieldValue("transaction.recurrfreq", "ONETIME");
+ engrid_ENGrid.setFieldValue("transaction.recurrpay", "N");
+ this._frequency.load();
+ this._amount.setAmount(this._amount.amount, false);
+ }
+ });
+ });
+ // Uncheck the checkbox when frequency != checkbox value
+ this._frequency.onFrequencyChange.subscribe(() => {
+ const currentFrequency = this._frequency.frequency.toUpperCase();
+ document.getElementsByName(this.checkboxName).forEach((element) => {
+ const elementFrequency = element.value.toUpperCase();
+ if (element.checked && elementFrequency !== currentFrequency) {
+ element.checked = false;
+ }
+ else if (!element.checked && elementFrequency === currentFrequency) {
+ element.checked = true;
+ }
+ });
+ });
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/iframe-queue.js
-/**
- * Iframe Queue β load embedded EN pages sequentially.
- *
- * **This component is opt-in.** Like `OptInLadder`, it is exported from
- * `@4site/engrid-scripts` but is **not** auto-constructed by ENgrid's
- * core bootstrap (`app.ts`). To use it, instantiate it once in your
- * theme's bootstrap:
- *
- * ```ts
- * import { IframeQueue } from "@4site/engrid-scripts";
- * new IframeQueue();
- * ```
- *
- * On client themes that don't use this component, **nothing in this
- * file runs**: no `message` listener is registered, no singleton is
- * allocated, no bundle code beyond the unused class definition.
- *
- * **Why this exists.** Engaging Networks' platform handles concurrent
- * iframe submissions inconsistently β when several embedded EN forms
- * are submitted in parallel (e.g. QCB opt-ins for postal mail, mobile
- * phone, and double opt-in email), roughly 40% of records are lost.
- * Loading the iframes sequentially (without `?chain`) resolves the
- * issue. This component generalises that pattern.
- *
- * **What it does.** In _parent_ mode (top-level page) it holds an
- * ordered queue of {@link IframeQueueItem} configs and processes them
- * one at a time: create iframe β wait for `load` β post a populate
- * message with field values β wait for the embedded page to reach a
- * Thank You page β advance. In _embedded_ mode (running inside an
- * iframe owned by an IframeQueue parent) it listens for the populate
- * message, fills the form fields via {@link ENGrid.setFieldValue}, and
- * submits via {@link EnForm.submitForm} when `autoSubmit` is true.
- *
- * **Why not `?chain`?** Engaging Networks' `?chain` URL parameter is
- * unreliable for sequential iframe submission; the agreed solution is
- * to pass field data via `postMessage` instead. The queue defensively
- * strips any `chain` query parameter from queued URLs.
- *
- * **Page ID matching.** The Thank-You-page ping (sent by the iFrame
- * component, see iframe.ts) carries the Page ID of the submitting
- * form. The queue compares it against the Page ID parsed from the
- * queued URL so that pings from unrelated EN iframes on the same
- * parent page (such as an Embedded Ecard iframe) are ignored.
- *
- * **Events.** Lifecycle events are dispatched via the
- * {@link IframeQueueEvents} singleton. External code subscribes there
- * rather than holding a reference to the queue itself.
- *
- * @example Programmatic API
- * const queue = IframeQueue.getInstance();
- * queue.enqueue({
- * url: "https://example.org/page/123/data/1",
- * fields: { "supporter.emailAddress": "donor@example.org" },
- * autoSubmit: true,
- * });
- * queue.process().then(() => console.log("done"));
- *
- * @example Declarative API (set on the EN page before the bundle loads)
- * window.EngridIframeQueue = {
- * items: [
- * { url: "https://example.org/page/123/data/1",
- * fields: { "supporter.emailAddress": "donor@example.org" } },
- * ],
- * autoStart: true,
- * };
- */
-var iframe_queue_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/page-background.js
-/** Wire-format type for the populate message sent parent β iframe. */
-const MSG_POPULATE = "engrid-iframe-queue:populate";
-/** Wire-format type for the Thank-You-page ping sent iframe β parent. */
-const MSG_THANK_YOU = "engrid-iframe-queue:thank-you";
-/** Wire-format type for an error message sent iframe β parent. */
-const MSG_ERROR = "engrid-iframe-queue:error";
-/** Default per-item timeout in milliseconds. */
-const DEFAULT_TIMEOUT_MS = 30000;
-/**
- * Parameters that are automatically inherited from the parent page
- * onto each queued iframe URL. These are all ENgrid loader / dev-mode
- * flags β adding them to the parent is meant to affect "the ENgrid
- * bundle running on this browser tab," which conceptually includes
- * the embedded forms loaded by the queue.
- *
- * For each key, the value is resolved with the same precedence used by
- * `loader.ts#getOption`:
- * 1. The item's own URL β if the consumer hard-coded the param on
- * the iframe URL, that wins.
- * 2. The parent page's URL parameter (`?assets=local`).
- * 3. `window.EngridLoader[key]` on the parent page β useful when EN
- * strips URL params on the Thank You page, so themes set
- * ``
- * to pin the bundle source.
- *
- * Notable use case: any of the three works for forcing local-asset
- * loading on every queued QCB iframe during testing.
- */
-const PROPAGATED_PARENT_PARAMS = (/* unused pure expression or super */ null && ([
- "assets",
- "engridjs",
- "engridcss",
- "repo-name",
- "repo-owner",
- "debug",
- "mode",
-]));
-/** Default visually-hidden style for queue iframes. */
-const DEFAULT_HIDDEN_STYLE = {
- position: "absolute",
- width: "1px",
- height: "1px",
- left: "-9999px",
- top: "0",
- opacity: "0",
- border: "0",
-};
-class IframeQueue {
+class PageBackground {
+ constructor() {
+ // @TODO: Change page-backgroundImage to page-background
+ this.pageBackground = document.querySelector(".page-backgroundImage");
+ this.mutationObserver = null;
+ this.logger = new logger_EngridLogger("PageBackground", "lightblue", "darkblue", "πΌοΈ");
+ if (!this.pageBackground) {
+ this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");
+ return;
+ }
+ this.initializeBackgroundImage();
+ this.setDataAttributes();
+ this.processAttributionPositioning();
+ this.setupMutationObserver();
+ }
/**
- * Returns the shared IframeQueue singleton. The bootstrap in app.ts
- * instantiates this once via `new IframeQueue()`, but consumers that
- * need to enqueue items programmatically should always go through
- * `getInstance()` so they share the same queue state.
+ * Initialize background image by finding and setting CSS custom property
*/
- static getInstance() {
- if (!IframeQueue.instance) {
- IframeQueue.instance = new IframeQueue();
+ initializeBackgroundImage() {
+ if (!this.pageBackground)
+ return;
+ const pageBackgroundImg = this.pageBackground.querySelector("img");
+ if (!pageBackgroundImg) {
+ this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");
+ return;
}
- return IframeQueue.instance;
- }
- constructor() {
- this.logger = new EngridLogger("IframeQueue", "white", "#1f6feb", "π");
- this.events = IframeQueueEvents.getInstance();
- this._form = EnForm.getInstance();
- this.queue = [];
- this._isProcessing = false;
- this._aborted = false;
- this.inFlightPromise = null;
- // Singleton guard: if called via `new IframeQueue()` after an
- // instance already exists (e.g. by app.ts), return the existing
- // instance so behaviour stays consistent with `getInstance()`.
- if (IframeQueue.instance) {
- return IframeQueue.instance;
+ const dataSrc = pageBackgroundImg.getAttribute("data-src");
+ const src = pageBackgroundImg.src;
+ if (dataSrc) {
+ this.setBackgroundImageUrl(dataSrc, "data-src");
}
- IframeQueue.instance = this;
- if (this.inIframe()) {
- this.setupEmbeddedMode();
+ else if (src) {
+ this.setBackgroundImageUrl(src, "src");
}
else {
- this.setupParentMode();
+ this.logger.log("A background image set in the page was found but without a data-src or src value, no action taken", pageBackgroundImg);
}
}
- // ---------------------------------------------------------------------------
- // Public API (parent mode)
- // ---------------------------------------------------------------------------
- /** Whether the queue is currently processing. */
- get isProcessing() {
- return this._isProcessing;
- }
- /** Number of items currently in the queue (not counting the in-flight item). */
- get size() {
- return this.queue.length;
- }
/**
- * Add an item to the back of the queue. Items are processed in
- * insertion order. Calling `enqueue` while the queue is processing is
- * supported β the new item joins the chain and will be picked up
- * after the current item completes.
+ * Set the background image URL as a CSS custom property
*/
- enqueue(item) {
- if (!item || typeof item.url !== "string" || !item.url) {
- this.logger.danger("enqueue() called with invalid item; ignoring");
+ setBackgroundImageUrl(imageUrl, sourceType) {
+ if (!this.pageBackground || !imageUrl)
return;
+ try {
+ const cssUrl = `url('${imageUrl}')`;
+ this.pageBackground.style.setProperty("--engrid__page-backgroundImage_url", cssUrl);
+ this.logger.log(`A background image set in the page was found with a ${sourceType} value, setting it as --engrid__page-backgroundImage_url`, imageUrl);
+ }
+ catch (error) {
+ this.logger.error("Error setting background image URL:", error);
}
- this.queue.push(item);
- this.logger.log(`enqueue: ${item.url} (queue size = ${this.queue.length})`);
}
/**
- * Add many items at once, preserving order. Equivalent to calling
- * {@link enqueue} repeatedly.
+ * Processes attribution positioning for background images by moving positioning classes
+ * and data attributes from images to their parent column containers.
+ *
+ * This function handles two attribution patterns:
+ * 1. Class-based:
+ * 2. Data attribute-based:
+ *
+ * Examples:
+ *
+ * Class-based attribution:
+ *
+ * β Moves "attribution-bottomright" class to parent .en__component--column
+ *
+ * Data attribute-based attribution:
+ *
+ * β Converts to "attribution-top" class and moves to parent .en__component--column
+ *
+ * Supported positioning values:
+ * - center
+ * - top, topcenter (these result in the same positioning)
+ * - right, rightcenter (these result in the same positioning)
+ * - bottom, bottomcenter (these result in the same positioning)
+ * - left, leftcenter (these result in the same positioning)
+ * - topright
+ * - bottomright
+ * - bottomleft
+ * - topleft
*/
- enqueueAll(items) {
- if (!Array.isArray(items))
+ processAttributionPositioning() {
+ if (!this.pageBackground) {
+ this.logger.log("No background section found for attribution positioning processing");
return;
- for (const item of items)
- this.enqueue(item);
+ }
+ this.logger.log("Processing attribution positioning for background section:", this.pageBackground);
+ // Define all supported attribution positioning classes
+ const allowedClasses = [
+ "attribution-center",
+ "attribution-bottom",
+ "attribution-bottomcenter",
+ "attribution-bottomright",
+ "attribution-bottomleft",
+ "attribution-top",
+ "attribution-topcenter",
+ "attribution-topright",
+ "attribution-topleft",
+ "attribution-left",
+ "attribution-leftcenter",
+ "attribution-right",
+ "attribution-rightcenter",
+ ];
+ try {
+ // Find all images in the background section (after any DOM transformations)
+ const images = this.pageBackground.querySelectorAll("img");
+ this.logger.log("Found images in background section:", images.length);
+ images.forEach((img) => {
+ this.processImageAttribution(img, allowedClasses);
+ });
+ }
+ catch (error) {
+ this.logger.error("Error processing attribution positioning:", error);
+ }
}
/**
- * Begin processing the queue. Resolves when the queue drains
- * successfully and rejects on the first error. If already processing,
- * returns the in-flight promise so callers don't start a second drain.
+ * Process attribution for a single image
*/
- process() {
- if (this._isProcessing && this.inFlightPromise) {
- this.logger.log("process: already processing; returning in-flight promise");
- return this.inFlightPromise;
+ processImageAttribution(img, allowedClasses) {
+ // Pattern 1: Check for class-based attribution positioning
+ // Example:
+ const matchedClass = allowedClasses.find((cls) => img.classList.contains(cls));
+ // Pattern 2: Check for data attribute-based attribution positioning
+ // Example:
+ const dataPosition = img.getAttribute("data-background-position");
+ if (matchedClass) {
+ this.handleClassBasedAttribution(img, matchedClass);
}
- if (this.queue.length === 0) {
- this.logger.log("process: queue empty; nothing to do");
- return Promise.resolve();
+ else if (dataPosition) {
+ this.handleDataAttributeAttribution(img, dataPosition);
}
- this._aborted = false;
- this._isProcessing = true;
- this.inFlightPromise = this.drain()
- .then(() => {
- this.events.dispatchChainComplete();
- })
- .finally(() => {
- this._isProcessing = false;
- this.inFlightPromise = null;
- });
- return this.inFlightPromise;
}
/**
- * Empty the queue without processing. Stops the in-flight item if
- * any (the in-flight item rejects with an abort error which is
- * surfaced via `onChainError`).
+ * Handle class-based attribution positioning
*/
- clear() {
- this.logger.log(`clear: dropping ${this.queue.length} queued item(s)`);
- this.queue = [];
- this._aborted = true;
+ handleClassBasedAttribution(img, matchedClass) {
+ this.logger.log("Found attribution class on image:", matchedClass, img);
+ const parentDiv = img.closest(".en__component--column");
+ if (parentDiv) {
+ // Move the class from image to parent column
+ img.classList.remove(matchedClass);
+ parentDiv.classList.add(matchedClass);
+ this.logger.log("Moved attribution class from image to parent column:", matchedClass, parentDiv);
+ }
+ else {
+ this.logger.log("No parent .en__component--column found for image:", img);
+ }
}
- // ---------------------------------------------------------------------------
- // Parent-mode internals
- // ---------------------------------------------------------------------------
/**
- * In parent mode the constructor checks `window.EngridIframeQueue`
- * for declarative startup config, enqueues those items, and (if
- * `autoStart` is true) calls `process()` after DOMContentLoaded.
+ * Handle data attribute-based attribution positioning
*/
- setupParentMode() {
- this.logger.log("setupParentMode");
- const config = this.readWindowConfig();
- if (!config)
- return;
- if (Array.isArray(config.items) && config.items.length > 0) {
- this.enqueueAll(config.items);
+ handleDataAttributeAttribution(img, dataPosition) {
+ // Convert data attribute value to attribution class format
+ const attributionClass = `attribution-${dataPosition}`;
+ this.logger.log("Found data-background-position on image:", dataPosition, "->", attributionClass, img);
+ const parentDiv = img.closest(".en__component--column");
+ if (parentDiv) {
+ // Remove data attribute from image and add class to parent column
+ img.removeAttribute("data-background-position");
+ parentDiv.classList.add(attributionClass);
+ this.logger.log("Moved data-background-position from image to parent column as class:", attributionClass, parentDiv);
}
- const shouldAutoStart = typeof config.autoStart === "boolean"
- ? config.autoStart
- : this.queue.length > 0;
- if (!shouldAutoStart || this.queue.length === 0)
+ else {
+ this.logger.log("No parent .en__component--column found for image:", img);
+ }
+ }
+ setupMutationObserver() {
+ if (!this.pageBackground || !window.MutationObserver) {
+ if (!window.MutationObserver) {
+ this.logger.log("MutationObserver not supported in this browser");
+ }
return;
- const start = () => {
- this.process().catch((err) => {
- this.logger.danger(`Auto-started queue rejected: ${err}`);
+ }
+ try {
+ this.mutationObserver = new MutationObserver((mutations) => {
+ let shouldReprocess = false;
+ mutations.forEach((mutation) => {
+ // Check if nodes were added or attributes changed
+ if (mutation.type === "childList" || mutation.type === "attributes") {
+ shouldReprocess = true;
+ }
+ });
+ if (shouldReprocess) {
+ this.logger.log("DOM changes detected in background section, reprocessing attribution classes");
+ // Use a small delay to ensure all changes are complete
+ setTimeout(() => {
+ this.processAttributionPositioning();
+ }, 100);
+ }
});
- };
- if (document.readyState !== "loading") {
- start();
+ // Start observing the background section
+ this.mutationObserver.observe(this.pageBackground, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ attributeFilter: ["class"],
+ });
+ this.logger.log("MutationObserver set up for background section");
}
- else {
- document.addEventListener("DOMContentLoaded", start);
+ catch (error) {
+ this.logger.error("Error setting up MutationObserver:", error);
}
}
+ // Public method to manually trigger reprocessing
+ reprocessAttributionPositioning() {
+ this.logger.log("Manually reprocessing attribution positioning");
+ this.processAttributionPositioning();
+ }
/**
- * Reads `window.EngridIframeQueue` and returns merged options, or
- * null if no valid config is present.
+ * Clean up resources and observers
*/
- readWindowConfig() {
- const raw = window
- .EngridIframeQueue;
- if (!raw || typeof raw !== "object")
- return null;
- return Object.assign(Object.assign({}, IframeQueueOptionsDefaults), raw);
+ destroy() {
+ if (this.mutationObserver) {
+ this.mutationObserver.disconnect();
+ this.mutationObserver = null;
+ this.logger.log("MutationObserver disconnected");
+ }
}
- /** Process queued items strictly one at a time. */
- drain() {
- var _a;
- return iframe_queue_awaiter(this, void 0, void 0, function* () {
- while (this.queue.length > 0) {
- if (this._aborted) {
- this.logger.log("drain: aborted; stopping");
- return;
- }
- const item = this.queue.shift();
- try {
- yield this.processItem(item);
- }
- catch (err) {
- const error = err instanceof Error ? err : new Error(String(err));
- this.events.dispatchItemError(item, error);
- try {
- (_a = item.onError) === null || _a === void 0 ? void 0 : _a.call(item, error);
- }
- catch (cbErr) {
- this.logger.danger(`onError callback threw: ${cbErr}`);
- }
- this.events.dispatchChainError({
- message: error.message,
- failedItem: item,
- cause: error,
- });
- // Abort the rest of the chain.
- this.queue = [];
- throw error;
- }
- }
- });
+ setDataAttributes() {
+ if (this.hasVideoBackground()) {
+ return engrid_ENGrid.setBodyData("page-background", "video");
+ }
+ if (this.hasImageBackground()) {
+ return engrid_ENGrid.setBodyData("page-background", "image");
+ }
+ return engrid_ENGrid.setBodyData("page-background", "empty");
}
- /**
- * Process a single item: create the iframe, post populate, wait for
- * the matching Thank-You ping (or error/timeout). Resolves on success
- * and rejects on error/timeout.
- */
- processItem(item) {
- return new Promise((resolve, reject) => {
- var _a, _b;
- const url = this.prepareIframeUrl(item.url);
- const expectedPageId = ENGrid.getPageIdFromUrl(url);
- if (!expectedPageId) {
- reject(new Error(`IframeQueue: could not parse Page ID from URL "${item.url}".`));
- return;
+ hasVideoBackground() {
+ if (!this.pageBackground) {
+ return false;
+ }
+ return !!this.pageBackground.querySelector("video");
+ }
+ hasImageBackground() {
+ if (!this.pageBackground) {
+ return false;
+ }
+ return (!this.hasVideoBackground() && !!this.pageBackground.querySelector("img"));
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/neverbounce.js
+
+
+class NeverBounce {
+ constructor(apiKey, dateField = null, statusField = null, dateFormat) {
+ this.apiKey = apiKey;
+ this.dateField = dateField;
+ this.statusField = statusField;
+ this.dateFormat = dateFormat;
+ this.form = en_form_EnForm.getInstance();
+ this.emailField = null;
+ this.emailWrapper = document.querySelector(".en__field--emailAddress");
+ this.nbDate = null;
+ this.nbStatus = null;
+ this.logger = new logger_EngridLogger("NeverBounce", "#039bc4", "#dfdfdf", "π§");
+ this.shouldRun = true;
+ this.nbLoaded = false;
+ this.bypassEmails = [
+ "noaddress.ea",
+ ];
+ this.neverBounceTimeout = engrid_ENGrid.getOption("NeverBounceTimeout") || 10000;
+ this.neverBounceTimeoutFunc = null;
+ const searchParams = new URLSearchParams(window.location.search);
+ if (searchParams.has("bypassemailvalidation")) {
+ this.logger.log("Bypass Email Validation Enabled - not running NeverBounce");
+ return;
+ }
+ this.emailField = document.getElementById("en__field_supporter_emailAddress");
+ window._NBSettings = {
+ apiKey: this.apiKey,
+ autoFieldHookup: false,
+ inputLatency: 1500,
+ displayPoweredBy: false,
+ loadingMessage: "Validating...",
+ softRejectMessage: "Invalid email",
+ acceptedMessage: "Email validated!",
+ feedback: false,
+ // Set NB timeout 1 second than our timeout. Ensures NB response will always be before our timeout if there is not a server error.
+ timeout: Math.floor((this.neverBounceTimeout - 1000) / 1000),
+ };
+ engrid_ENGrid.loadJS("https://cdn.neverbounce.com/widget/dist/NeverBounce.js");
+ if (this.emailField) {
+ if (this.emailField.value) {
+ this.logger.log("E-mail Field Found");
+ this.shouldRun = false;
}
- this.events.dispatchItemStart(item);
- const container = (_a = item.container) !== null && _a !== void 0 ? _a : document.body;
- const iframe = this.createIframe(url, item.iframeStyle);
- const timeoutMs = (_b = item.timeout) !== null && _b !== void 0 ? _b : DEFAULT_TIMEOUT_MS;
- let settled = false;
- let timeoutId = null;
- const detachListeners = () => {
- if (timeoutId !== null) {
- window.clearTimeout(timeoutId);
- timeoutId = null;
- }
- window.removeEventListener("message", onMessage);
- iframe.removeEventListener("load", onIframeLoad);
- iframe.removeEventListener("error", onIframeError);
- };
- const removeIframe = () => {
- if (iframe.parentNode) {
- iframe.parentNode.removeChild(iframe);
- }
- };
- const succeed = () => {
+ this.emailField.addEventListener("change", (e) => {
var _a;
- if (settled)
- return;
- settled = true;
- detachListeners();
- removeIframe();
- this.events.dispatchItemComplete(item);
- try {
- (_a = item.onComplete) === null || _a === void 0 ? void 0 : _a.call(item);
+ if (!this.nbLoaded) {
+ this.shouldRun = true;
+ this.init();
+ if ((_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value) {
+ setTimeout(function () {
+ window._nb.fields
+ .get(document.querySelector("[data-nb-id]"))[0]
+ .forceUpdate();
+ }, 100);
+ }
}
- catch (cbErr) {
- this.logger.danger(`onComplete callback threw: ${cbErr}`);
+ });
+ window.setTimeout(() => {
+ if (this.emailField && this.emailField.value) {
+ this.logger.log("E-mail Filled Programatically");
+ this.shouldRun = false;
}
- resolve();
- };
- const fail = (error) => {
- if (settled)
+ this.init();
+ }, 1000);
+ }
+ this.form.onValidate.subscribe(this.validate.bind(this));
+ }
+ init() {
+ if (!this.shouldRun) {
+ this.logger.log("Should Not Run");
+ return;
+ }
+ if (this.nbLoaded) {
+ this.logger.log("Already Loaded");
+ return;
+ }
+ this.logger.log("Init Function");
+ if (this.dateField && document.getElementsByName(this.dateField).length)
+ this.nbDate = document.querySelector("[name='" + this.dateField + "']");
+ if (this.statusField && document.getElementsByName(this.statusField).length)
+ this.nbStatus = document.querySelector("[name='" + this.statusField + "']");
+ if (!this.emailField) {
+ this.logger.log("E-mail Field Not Found");
+ return;
+ }
+ this.wrap(this.emailField, document.createElement("div"));
+ const parentNode = this.emailField.parentNode;
+ parentNode.id = "nb-wrapper";
+ // Define HTML structure for a Custom NB Message and insert it after Email field
+ const nbCustomMessageHTML = document.createElement("div");
+ nbCustomMessageHTML.innerHTML =
+ 'Enter a valid email.
';
+ this.insertAfter(nbCustomMessageHTML, this.emailField);
+ const NBClass = this;
+ document.body.addEventListener("nb:registered", function (event) {
+ const field = document.querySelector('[data-nb-id="' + event.detail.id + '"]');
+ field.addEventListener("nb:loading", function (e) {
+ engrid_ENGrid.disableSubmit("Validating Your Email");
+ NBClass.setEmailStatus("loading");
+ NBClass.clearTimeout();
+ NBClass.neverBounceTimeoutFunc = setTimeout(() => {
+ NBClass.setEmailStatus("unknown");
+ if (NBClass.nbDate) {
+ NBClass.nbDate.value = engrid_ENGrid.formatDate(new Date(), NBClass.dateFormat);
+ }
+ if (NBClass.nbStatus) {
+ NBClass.nbStatus.value = "unknown";
+ }
+ engrid_ENGrid.enableSubmit();
+ window._nb.fields.unregisterListener(NBClass.emailField);
+ NBClass.nbLoaded = false;
+ NBClass.logger.log("NeverBounce Timeout Reached. Bypassing validation, setting unknown status and removing NB.");
+ }, NBClass.neverBounceTimeout);
+ });
+ // Never Bounce: Do work when input changes or when API responds with an error
+ field.addEventListener("nb:clear", function (e) {
+ if (!NBClass.nbLoaded)
return;
- settled = true;
- detachListeners();
- if (this.shouldKeepIframeOnError(item)) {
- this.markIframeFailed(iframe, error);
- this.logger.danger(`Item failed β iframe kept in DOM for inspection: ${error.message}`);
- }
- else {
- removeIframe();
- }
- reject(error);
- };
- const onMessage = (event) => {
- var _a;
- // Only accept messages from this specific iframe β origin
- // string matching is unreliable because EN may serve embedded
- // pages from different subdomains. `event.source` identity is
- // what matters here.
- if (event.source !== iframe.contentWindow)
+ NBClass.clearTimeout();
+ NBClass.setEmailStatus("clear");
+ engrid_ENGrid.enableSubmit();
+ if (NBClass.nbDate)
+ NBClass.nbDate.value = "";
+ if (NBClass.nbStatus)
+ NBClass.nbStatus.value = "";
+ });
+ // Never Bounce: Do work when results have an input that does not look like an email (i.e. missing @ or no .com/.net/etc...)
+ field.addEventListener("nb:soft-result", function (e) {
+ if (!NBClass.nbLoaded)
return;
- const data = event.data;
- if (!data || typeof data !== "object" || !data.type)
+ NBClass.clearTimeout();
+ NBClass.setEmailStatus("soft-result");
+ if (NBClass.nbDate)
+ NBClass.nbDate.value = "";
+ if (NBClass.nbStatus)
+ NBClass.nbStatus.value = "";
+ engrid_ENGrid.enableSubmit();
+ });
+ // Never Bounce: When results have been received
+ field.addEventListener("nb:result", function (e) {
+ if (!NBClass.nbLoaded)
return;
- if (data.type === MSG_THANK_YOU) {
- if (data.pageId !== expectedPageId) {
- this.logger.log(`Ignoring thank-you ping with mismatched pageId ` +
- `(expected ${expectedPageId}, got ${data.pageId})`);
- return;
- }
- this.logger.log(`Item complete: ${url} (pageId ${expectedPageId})`);
- succeed();
+ NBClass.clearTimeout();
+ if (e.detail.result.is(window._nb.settings.getAcceptedStatusCodes())) {
+ NBClass.setEmailStatus("valid");
+ if (NBClass.nbDate)
+ NBClass.nbDate.value = engrid_ENGrid.formatDate(new Date(), NBClass.dateFormat);
+ if (NBClass.nbStatus)
+ NBClass.nbStatus.value = (e).detail.result.response.result;
}
- else if (data.type === MSG_ERROR) {
- if (data.pageId !== expectedPageId)
- return;
- fail(new Error(`IframeQueue: embedded page reported error: ${(_a = data.message) !== null && _a !== void 0 ? _a : "unknown error"}`));
+ else {
+ NBClass.setEmailStatus("invalid");
+ if (NBClass.nbDate)
+ NBClass.nbDate.value = "";
+ if (NBClass.nbStatus)
+ NBClass.nbStatus.value = "";
}
- };
- const onIframeLoad = () => {
- var _a, _b;
- if (settled)
- return;
- const populate = {
- type: MSG_POPULATE,
- pageId: expectedPageId,
- fields: (_a = item.fields) !== null && _a !== void 0 ? _a : {},
- autoSubmit: item.autoSubmit !== false, // default true
- };
- this.logger.log(`Posting populate to iframe (pageId=${expectedPageId}, ` +
- `fieldCount=${Object.keys(populate.fields).length}, ` +
- `autoSubmit=${populate.autoSubmit})`);
- // Use "*" for the same reason origin matching is skipped on
- // inbound messages β EN may serve embedded pages from a
- // different subdomain than the host page.
- (_b = iframe.contentWindow) === null || _b === void 0 ? void 0 : _b.postMessage(populate, "*");
- };
- const onIframeError = () => {
- fail(new Error(`IframeQueue: iframe failed to load: ${url}`));
- };
- window.addEventListener("message", onMessage);
- iframe.addEventListener("load", onIframeLoad);
- iframe.addEventListener("error", onIframeError);
- timeoutId = window.setTimeout(() => {
- fail(new Error(`IframeQueue: timed out after ${timeoutMs}ms waiting for ` +
- `Thank-You-page ping from ${url}`));
- }, timeoutMs);
- this.logger.log(`Item start: ${url} (pageId ${expectedPageId}, timeout ${timeoutMs}ms)`);
- container.appendChild(iframe);
+ engrid_ENGrid.enableSubmit();
+ });
});
+ // Never Bounce: Register field with the widget and broadcast nb:registration event
+ window._nb.fields.registerListener(NBClass.emailField, true);
+ this.nbLoaded = true;
}
- /**
- * Normalise the URL for a queued iframe:
- * 1. Strip any `chain` query parameter defensively β the queue
- * replaces `?chain` with sequential processing.
- * 2. Inherit a small allowlist of loader / dev-mode params (see
- * {@link PROPAGATED_PARENT_PARAMS}) when they're not already set
- * on the item URL. Each key is resolved with the same precedence
- * `loader.ts#getOption` uses: parent URL param first, then
- * `window.EngridLoader[key]`.
- *
- * Item-specified params always take precedence over inherited ones.
- * Returns the original string unchanged if URL parsing fails.
- */
- prepareIframeUrl(rawUrl) {
- let url;
- try {
- url = new URL(rawUrl, window.location.href);
+ clearStatus() {
+ if (!this.emailField) {
+ this.logger.log("E-mail Field Not Found");
+ return;
}
- catch (_a) {
- return rawUrl;
+ this.emailField.classList.remove("rm-error");
+ // Search page for the NB Wrapper div and set as variable
+ const nb_email_field_wrapper = (document.getElementById("nb-wrapper"));
+ // Search page for the NB Feedback div and set as variable
+ const nb_email_feedback_field = (document.getElementById("nb-feedback"));
+ nb_email_field_wrapper.className = "";
+ nb_email_feedback_field.className = "en__field__error nb-hidden";
+ nb_email_feedback_field.innerHTML = "";
+ this.emailWrapper.classList.remove("en__field--validationFailed");
+ }
+ deleteENFieldError() {
+ const errorField = (document.querySelector(".en__field--emailAddress>div.en__field__error"));
+ if (errorField)
+ errorField.remove();
+ }
+ setEmailStatus(status) {
+ this.logger.log("Status:", status);
+ if (!this.emailField) {
+ this.logger.log("E-mail Field Not Found");
+ return;
}
- url.searchParams.delete("chain");
- const parentUrlParams = this.getParentSearchParams();
- const parentLoader = this.getParentEngridLoader();
- const inherited = [];
- for (const key of PROPAGATED_PARENT_PARAMS) {
- if (url.searchParams.has(key))
- continue;
- let value = null;
- let source = "";
- if (parentUrlParams) {
- const v = parentUrlParams.get(key);
- if (v !== null) {
- value = v;
- source = "url";
- }
- }
- if (value === null && parentLoader) {
- const v = parentLoader[key];
- if (typeof v === "string" && v !== "") {
- value = v;
- source = "EngridLoader";
- }
- }
- if (value !== null) {
- url.searchParams.set(key, value);
- inherited.push(`${key}=${value} (from parent ${source})`);
+ if (this.isBypassEmail()) {
+ this.logger.log("Bypass email detected. Skipping status update.");
+ return;
+ }
+ // Search page for the NB Wrapper div and set as variable
+ const nb_email_field_wrapper = (document.getElementById("nb-wrapper"));
+ // Search page for the NB Feedback div and set as variable
+ let nb_email_feedback_field = (document.getElementById("nb-feedback"));
+ // classes to add or remove based on neverbounce results
+ const nb_email_field_wrapper_success = "nb-success";
+ const nb_email_field_wrapper_error = "nb-error";
+ const nb_email_feedback_hidden = "nb-hidden";
+ const nb_email_feedback_loading = "nb-loading";
+ const nb_email_field_error = "rm-error";
+ if (!nb_email_feedback_field) {
+ const nbWrapperDiv = nb_email_field_wrapper.querySelector("div");
+ if (nbWrapperDiv)
+ nbWrapperDiv.innerHTML =
+ 'Enter a valid email.
';
+ nb_email_feedback_field = (document.getElementById("nb-feedback"));
+ }
+ if (status == "valid") {
+ this.clearStatus();
+ }
+ else {
+ nb_email_field_wrapper.classList.remove(nb_email_field_wrapper_success);
+ nb_email_field_wrapper.classList.add(nb_email_field_wrapper_error);
+ switch (status) {
+ case "required": // special case status that we added ourselves -- doesn't come from NB
+ this.deleteENFieldError();
+ nb_email_feedback_field.innerHTML = "A valid email is required";
+ nb_email_feedback_field.classList.remove(nb_email_feedback_loading);
+ nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
+ this.emailField.classList.add(nb_email_field_error);
+ break;
+ case "soft-result":
+ if (this.emailField.value) {
+ this.deleteENFieldError();
+ nb_email_feedback_field.innerHTML = "Invalid email";
+ nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
+ this.emailField.classList.add(nb_email_field_error);
+ }
+ else {
+ this.clearStatus();
+ }
+ break;
+ case "invalid":
+ this.deleteENFieldError();
+ nb_email_feedback_field.innerHTML = "Invalid email";
+ nb_email_feedback_field.classList.remove(nb_email_feedback_loading);
+ nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
+ this.emailField.classList.add(nb_email_field_error);
+ break;
+ case "loading":
+ case "clear":
+ default:
+ this.clearStatus();
+ break;
}
}
- if (inherited.length > 0) {
- this.logger.log(`Inherited parent params on iframe URL: ${inherited.join(", ")}`);
+ }
+ // Function to insert HTML after a DIV
+ insertAfter(el, referenceNode) {
+ var _a;
+ (_a = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(el, referenceNode.nextSibling);
+ }
+ // to Wrap HTML around a DIV
+ wrap(el, wrapper) {
+ var _a;
+ (_a = el.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, el);
+ wrapper.appendChild(el);
+ }
+ isBypassEmail() {
+ if (!this.emailField || !this.emailField.value)
+ return false;
+ const email = this.emailField.value.toLowerCase();
+ return this.bypassEmails.some((bypassEmail) => email.includes(bypassEmail.toLowerCase()));
+ }
+ validate() {
+ var _a;
+ if (!this.form.validate)
+ return;
+ const nbResult = engrid_ENGrid.getFieldValue("nb-result");
+ if (!this.emailField || !this.shouldRun || !this.nbLoaded || !nbResult) {
+ this.logger.log("validate(): Should Not Run. Returning true.");
+ return;
}
- return url.href;
- }
- /** Returns the parent page's URLSearchParams, or null on failure. */
- getParentSearchParams() {
- try {
- return new URL(window.location.href).searchParams;
+ if (this.isBypassEmail()) {
+ this.logger.log("Bypass email detected. Skipping validation.");
+ return;
}
- catch (_a) {
- return null;
+ if (this.nbStatus) {
+ this.nbStatus.value = nbResult;
+ }
+ if (!["catchall", "unknown", "valid"].includes(nbResult)) {
+ this.setEmailStatus("required");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ this.logger.log("NB-Result:", engrid_ENGrid.getFieldValue("nb-result"));
+ this.form.validate = false;
}
}
/**
- * Returns the parent page's `window.EngridLoader` object if set, or
- * null. Used by {@link prepareIframeUrl} as a fallback source for
- * loader/dev-mode param values when EN has stripped URL parameters
- * from the Thank You page.
+ * Clears the backup timeout function if it exists.
+ * @private
*/
- getParentEngridLoader() {
- const w = window;
- if (!w.EngridLoader || typeof w.EngridLoader !== "object")
- return null;
- return w.EngridLoader;
+ clearTimeout() {
+ if (this.neverBounceTimeoutFunc) {
+ clearTimeout(this.neverBounceTimeoutFunc);
+ this.neverBounceTimeoutFunc = null;
+ }
}
- /**
- * Decide whether to leave a failed iframe in the DOM (for
- * inspection) instead of removing it. True when the item explicitly
- * asks for it via `keepIframeOnError`, OR whenever ENgrid debug
- * mode is on (since debugging is when this is useful and we don't
- * want to make consumers opt in just to inspect failures).
- */
- shouldKeepIframeOnError(item) {
- if (item.keepIframeOnError)
- return true;
- try {
- return ENGrid.debug === true;
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/freshaddress.js
+// According to the FreshAddress documentation, you need to add the following code to your page:
+// jQuery library.
+//
+// FreshAddress client-side integration library
+//
+//
+// I know. jQuery. But it's not my fault. It's FreshAddress's fault.
+
+
+class FreshAddress {
+ constructor() {
+ var _a;
+ this.form = en_form_EnForm.getInstance();
+ this.emailField = null;
+ this.emailWrapper = document.querySelector(".en__field--emailAddress");
+ this.faDate = null;
+ this.faStatus = null;
+ this.faMessage = null;
+ this.logger = new logger_EngridLogger("FreshAddress", "#039bc4", "#dfdfdf", "π§");
+ this.shouldRun = true;
+ this.options = engrid_ENGrid.getOption("FreshAddress");
+ if (this.options === false ||
+ (!window.FreshAddress && !((_a = this.options) === null || _a === void 0 ? void 0 : _a.proxyUrl))) {
+ return;
}
- catch (_a) {
- return false;
+ this.emailField = document.getElementById("en__field_supporter_emailAddress");
+ if (this.emailField) {
+ this.createFields();
+ this.addEventListeners();
+ window.FreshAddressStatus = "idle";
+ if (this.emailField.value) {
+ this.logger.log("E-mail Field Found");
+ this.shouldRun = false;
+ }
+ window.setTimeout(() => {
+ if (this.emailField && this.emailField.value) {
+ this.logger.log("E-mail Filled Programatically");
+ this.shouldRun = false;
+ }
+ }, 1000);
+ }
+ else {
+ this.logger.log("E-mail Field Not Found");
}
}
- /**
- * Reposition and style a failed iframe so it's visible in the
- * viewport (overriding the visually-hidden default), and tag it
- * with a class + tooltip so the developer knows why it's there.
- * Right-click the iframe β Inspect frame to dive in.
- */
- markIframeFailed(iframe, error) {
- Object.assign(iframe.style, {
- position: "fixed",
- top: "10px",
- right: "10px",
- bottom: "auto",
- left: "auto",
- width: "min(600px, 90vw)",
- height: "min(500px, 80vh)",
- opacity: "1",
- zIndex: "99999",
- border: "3px solid #d33",
- background: "white",
- boxShadow: "0 4px 24px rgba(0, 0, 0, 0.25)",
- });
- iframe.classList.add("engrid-iframe--queue-failed");
- iframe.title = `Iframe Queue: failed item β ${error.message}`;
+ createFields() {
+ if (!this.options)
+ return;
+ this.options.dateField = this.options.dateField || "fa_date";
+ this.faDate = engrid_ENGrid.getField(this.options.dateField);
+ if (!this.faDate) {
+ this.logger.log("Date Field Not Found. Creating...");
+ engrid_ENGrid.createHiddenInput(this.options.dateField, "");
+ this.faDate = engrid_ENGrid.getField(this.options.dateField);
+ }
+ this.options.statusField = this.options.statusField || "fa_status";
+ this.faStatus = engrid_ENGrid.getField(this.options.statusField);
+ if (!this.faStatus) {
+ this.logger.log("Status Field Not Found. Creating...");
+ engrid_ENGrid.createHiddenInput(this.options.statusField, "");
+ this.faStatus = engrid_ENGrid.getField(this.options.statusField);
+ }
+ this.options.messageField = this.options.messageField || "fa_message";
+ this.faMessage = engrid_ENGrid.getField(this.options.messageField);
+ if (!this.faMessage) {
+ this.logger.log("Message Field Not Found. Creating...");
+ engrid_ENGrid.createHiddenInput(this.options.messageField, "");
+ this.faMessage = engrid_ENGrid.getField(this.options.messageField);
+ }
}
- /** Create a hidden iframe element for a queue item. */
- createIframe(url, styleOverride) {
- const iframe = document.createElement("iframe");
- iframe.setAttribute("src", url);
- iframe.setAttribute("frameborder", "0");
- iframe.setAttribute("scrolling", "no");
- iframe.setAttribute("aria-hidden", "true");
- iframe.setAttribute("title", "ENgrid Iframe Queue");
- iframe.classList.add("engrid-iframe", "engrid-iframe--queue");
- const style = Object.assign(Object.assign({}, DEFAULT_HIDDEN_STYLE), (styleOverride !== null && styleOverride !== void 0 ? styleOverride : {}));
- Object.assign(iframe.style, style);
- return iframe;
+ writeToFields(status, message) {
+ if (!this.options)
+ return;
+ this.faDate.value = engrid_ENGrid.formatDate(new Date(), this.options.dateFieldFormat || "yyyy-MM-dd");
+ this.faStatus.value = status;
+ this.faMessage.value = message;
+ this.emailWrapper.dataset.freshaddressSafetosendstatus =
+ status.toLowerCase();
}
- // ---------------------------------------------------------------------------
- // Embedded-mode internals
- // ---------------------------------------------------------------------------
- /**
- * In embedded mode we register a `message` listener that accepts
- * populate messages from `window.parent`, fills form fields, and
- * (optionally) submits. The Thank-You-page ping is sent by the iFrame
- * component (iframe.ts) β not here β so this method does not need to
- * concern itself with completion signalling.
- */
- setupEmbeddedMode() {
- this.logger.log("setupEmbeddedMode");
- window.addEventListener("message", (event) => {
- if (event.source !== window.parent)
- return;
- const data = event.data;
- if (!data || typeof data !== "object" || data.type !== MSG_POPULATE) {
+ addEventListeners() {
+ var _a;
+ if (!this.options)
+ return;
+ // Add event listeners to fields
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.addEventListener("change", () => {
+ var _a, _b;
+ if (!this.shouldRun ||
+ ((_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value.includes("@4sitestudios.com"))) {
+ engrid_ENGrid.removeError(this.emailWrapper);
+ this.writeToFields("Valid", "Skipped");
+ this.logger.log("Skipping E-mail Validation");
return;
}
- this.handlePopulate(data);
+ this.logger.log("Validating " + ((_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value));
+ if (this.options && this.options.proxyUrl) {
+ this.callProxy();
+ }
+ else {
+ this.callAPI();
+ }
});
+ // Add event listener to submit
+ this.form.onValidate.subscribe(this.validate.bind(this));
}
- /** Handle a populate message sent by an IframeQueue parent. */
- handlePopulate(data) {
- var _a, _b;
- const fields = (_a = data.fields) !== null && _a !== void 0 ? _a : {};
- const autoSubmit = data.autoSubmit !== false;
- this.logger.log(`Received populate (pageId=${data.pageId}, ` +
- `fieldCount=${Object.keys(fields).length}, autoSubmit=${autoSubmit})`);
- try {
- for (const [name, value] of Object.entries(fields)) {
- // Pass `dispatchEvents = true` so each field fires
- // `change` + `blur` after the value is set. Without that,
- // EN's form-validation state machine doesn't see the new
- // values and leaves `en__submit--disabled` on the submit
- // button, causing the auto-click below to no-op.
- ENGrid.setFieldValue(name, value, true, true);
- }
- if (autoSubmit) {
- // Defer slightly so any synchronous EN dependency parsing in
- // setFieldValue settles before the form is submitted.
- window.setTimeout(() => {
- // Belt-and-braces: clear EN's "submit disabled" state in
- // case its validators didn't re-evaluate (e.g. async
- // validators that hadn't completed when the events fired).
- this.forceEnableSubmitButton();
- this._form.submitForm();
- }, 0);
+ callAPI() {
+ var _a;
+ if (!this.options || !window.FreshAddress)
+ return;
+ if (!this.shouldRun)
+ return;
+ window.FreshAddressStatus = "validating";
+ const email = (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value;
+ const options = { emps: false, rtc_timeout: 1200 };
+ const ret = window.FreshAddress.validateEmail(email, options).then((response) => {
+ this.logger.log("Validate API Response", JSON.parse(JSON.stringify(response)));
+ return this.validateResponse(response);
+ });
+ }
+ validateResponse(data) {
+ var _a;
+ /* ERROR HANDLING: Let through in case of a service error. Enable form submission. */
+ if (data.isServiceError()) {
+ this.logger.log("Service Error");
+ this.writeToFields("Service Error", data.getErrorResponse());
+ return true;
+ }
+ /* CHECK RESULT: */
+ if (data.isValid()) {
+ // Set response message. No action required.
+ this.writeToFields("Valid", data.getComment());
+ engrid_ENGrid.removeError(this.emailWrapper);
+ if (data.hasSuggest()) {
+ // Valid, with Suggestion
+ engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
+ this.emailField.value = data.getSuggEmail();
}
}
- catch (err) {
- const error = err instanceof Error ? err : new Error(String(err));
- this.logger.danger(`handlePopulate failed: ${error.message}`);
- window.parent.postMessage({
- type: MSG_ERROR,
- pageId: (_b = data.pageId) !== null && _b !== void 0 ? _b : ENGrid.getPageID(),
- message: error.message,
- }, "*");
+ else if (data.isError()) {
+ // Error Condition 1 - the service should always respond with finding E/W/V
+ this.writeToFields("Invalid", data.getErrorResponse());
+ engrid_ENGrid.setError(this.emailWrapper, data.getErrorResponse());
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ if (data.hasSuggest()) {
+ // Error, with Suggestion
+ engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
+ this.emailField.value = data.getSuggEmail();
+ this.writeToFields("Error", data.getErrorResponse());
+ }
}
- }
- /**
- * Strip every "disabled" marker from the EN submit button so the
- * programmatic `submitForm()` click is honoured. Removes:
- * - the `disabled` DOM property/attribute on the button,
- * - the `en__submit--disabled` BEM modifier (EN's own class),
- * - the `en__submit--disabled` modifier on the `.en__submit`
- * wrapper (some templates style the wrapper instead),
- * - ENgrid's own loader markup if a previous `disableSubmit()`
- * call left it in place.
- *
- * Used only by embedded-mode populate flow when `autoSubmit` is on.
- */
- forceEnableSubmitButton() {
- const button = document.querySelector("form .en__submit button");
- if (button) {
- if (button.disabled)
- button.disabled = false;
- button.removeAttribute("disabled");
- button.classList.remove("en__submit--disabled");
+ else if (data.isWarning()) {
+ this.writeToFields("Invalid", data.getErrorResponse());
+ engrid_ENGrid.setError(this.emailWrapper, data.getErrorResponse());
+ if (data.hasSuggest()) {
+ // Warning, with Suggestion
+ engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
+ this.emailField.value = data.getSuggEmail();
+ this.writeToFields("Warning", data.getErrorResponse());
+ }
}
- const wrapper = document.querySelector(".en__submit");
- if (wrapper) {
- wrapper.classList.remove("en__submit--disabled");
+ else {
+ // Error Condition 2 - the service should always respond with finding E/W/V
+ this.writeToFields("API Error", "Unknown Error");
}
+ window.FreshAddressStatus = "idle";
+ engrid_ENGrid.enableSubmit();
}
- // ---------------------------------------------------------------------------
- // Helpers
- // ---------------------------------------------------------------------------
- /** True when this script is executing inside an iframe. */
- inIframe() {
- try {
- return window.self !== window.top;
+ validate() {
+ var _a;
+ engrid_ENGrid.removeError(this.emailWrapper);
+ if (!this.form.validate)
+ return;
+ if (!this.options) {
+ this.form.validate = true;
+ return;
}
- catch (_a) {
- return true;
+ if (!this.shouldRun) {
+ this.form.validate = true;
+ return;
}
- }
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/input-has-value-and-focus.js
-// Component that adds has-value and has-focus classes to form inputs
-
-class InputHasValueAndFocus {
- constructor() {
- this.logger = new logger_EngridLogger("InputHasValueAndFocus", "yellow", "#333", "π");
- this.formInputs = document.querySelectorAll(".en__field--text, .en__field--email:not(.en__field--checkbox), .en__field--telephone, .en__field--number, .en__field--textarea, .en__field--select, .en__field--checkbox");
- if (this.shouldRun()) {
- this.run();
+ if (window.FreshAddressStatus === "validating") {
+ this.logger.log("Waiting for API Response");
+ // Self resolving Promise that waits 1000ms
+ const wait = new Promise((resolve, reject) => {
+ setTimeout(() => {
+ var _a;
+ const status = this.faStatus.value;
+ if (status === "" || status === "Invalid") {
+ this.logger.log("Promise Rejected");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ reject(false);
+ return;
+ }
+ this.logger.log("Promise Resolved");
+ resolve(true);
+ }, 700);
+ });
+ this.form.validatePromise = wait;
+ return;
}
+ else if (this.faStatus.value === "Invalid") {
+ this.form.validate = false;
+ window.setTimeout(() => {
+ engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ }, 100);
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ engrid_ENGrid.enableSubmit();
+ return false;
+ }
+ this.form.validate = true;
+ return true;
}
- shouldRun() {
- return this.formInputs.length > 0;
- }
- run() {
- this.formInputs.forEach((el) => {
- const input = el.querySelector("input, textarea, select");
- if (input && input.value) {
- el.classList.add("has-value");
- }
- this.bindEvents(el);
- });
- }
- bindEvents(el) {
- const input = el.querySelector("input, textarea, select");
- if (!input) {
+ callProxy() {
+ var _a, _b;
+ if (!this.options || !this.shouldRun)
+ return;
+ window.FreshAddressStatus = "validating";
+ engrid_ENGrid.disableSubmit("Validating Email Address...");
+ // Before calling the API, do a basic check to see if the email is in a valid format.
+ // This is to prevent unnecessary API calls.
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(this.emailField.value)) {
+ this.logger.log("Invalid Email Format from Basic Check");
+ this.writeToFields("Invalid", "Invalid Email Format");
+ engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ engrid_ENGrid.enableSubmit();
return;
}
- input.addEventListener("focus", () => {
- this.log("Focus added", input);
- el.classList.add("has-focus");
- });
- input.addEventListener("blur", () => {
- this.log("Focus removed", input);
- el.classList.remove("has-focus");
- });
- input.addEventListener("input", () => {
- if (input.value) {
- this.log("Value added", input);
- el.classList.add("has-value");
- }
- else {
- this.log("Value removed", input);
- el.classList.remove("has-value");
+ fetch(this.options.proxyUrl, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ email: (_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value }),
+ signal: AbortSignal.timeout(5000),
+ })
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error(`HTTP error ${response.status}`);
}
- });
- }
- log(message, input) {
- this.logger.log(`${message} on ${input.name}: ${input.value}`);
- }
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/input-placeholders.js
-// Component that adds input placeholders
-// You can override the default placeholders by adding a Placeholders option to the EngridOptions on the client theme.
-// You can also add an EngridPageOptions override to the page, if you want to override the placeholders on a specific page. Example:
-//
-
-class InputPlaceholders {
- constructor() {
- this.defaultPlaceholders = {
- "input#en__field_supporter_firstName": "First Name",
- "input#en__field_supporter_lastName": "Last Name",
- "input#en__field_supporter_emailAddress": "Email Address",
- "input#en__field_supporter_phoneNumber": "Phone Number (Optional)",
- ".en__mandatory input#en__field_supporter_phoneNumber": "Phone Number",
- ".i-required input#en__field_supporter_phoneNumber": "Phone Number",
- "input#en__field_supporter_phoneNumber2": "000-000-0000 (Optional)",
- ".en__mandatory input#en__field_supporter_phoneNumber2": "000-000-0000",
- ".i-required input#en__field_supporter_phoneNumber2": "000-000-0000",
- "input#en__field_supporter_country": "Country",
- "input#en__field_supporter_address1": "Street Address",
- "input#en__field_supporter_address2": "Apt., Ste., Bldg.",
- "input#en__field_supporter_city": "City",
- "input#en__field_supporter_region": "Region",
- "input#en__field_supporter_postcode": "ZIP Code",
- ".en__field--donationAmt.en__field--withOther .en__field__input--other": "Other",
- "input#en__field_transaction_ccexpire": "MM / YY",
- "input#en__field_supporter_bankAccountNumber": "Bank Account Number",
- "input#en__field_supporter_bankRoutingNumber": "Bank Routing Number",
- "input#en__field_transaction_honname": "Honoree Name",
- "input#en__field_transaction_infname": "Recipient Name",
- "input#en__field_transaction_infemail": "Recipient Email Address",
- "input#en__field_transaction_infcountry": "Country",
- "input#en__field_transaction_infadd1": "Recipient Street Address",
- "input#en__field_transaction_infadd2": "Recipient Apt., Ste., Bldg.",
- "input#en__field_transaction_infcity": "Recipient City",
- "input#en__field_transaction_infpostcd": "Recipient Postal Code",
- "input#en__field_transaction_gftrsn": "Reason for your gift",
- "input#en__field_transaction_shipfname": "Shipping First Name",
- "input#en__field_transaction_shiplname": "Shipping Last Name",
- "input#en__field_transaction_shipemail": "Shipping Email Address",
- "input#en__field_transaction_shipcountry": "Shipping Country",
- "input#en__field_transaction_shipadd1": "Shipping Street Address",
- "input#en__field_transaction_shipadd2": "Shipping Apt., Ste., Bldg.",
- "input#en__field_transaction_shipcity": "Shipping City",
- "input#en__field_transaction_shipregion": "Shipping Region",
- "input#en__field_transaction_shippostcode": "Shipping Postal Code",
- "input#en__field_supporter_billingCountry": "Billing Country",
- "input#en__field_supporter_billingAddress1": "Billing Street Address",
- "input#en__field_supporter_billingAddress2": "Billing Apt., Ste., Bldg.",
- "input#en__field_supporter_billingCity": "Billing City",
- "input#en__field_supporter_billingRegion": "Billing Region",
- "input#en__field_supporter_billingPostcode": "Billing Postal Code",
- };
- if (this.shouldRun()) {
- // If there's a Placeholders option, merge it with the default placeholders
- const placeholders = engrid_ENGrid.getOption("Placeholders");
- if (placeholders) {
- this.defaultPlaceholders = Object.assign(Object.assign({}, this.defaultPlaceholders), placeholders);
+ return response.json();
+ })
+ .then((data) => {
+ this.logger.log("Proxy API Response", data);
+ this.validateProxyResponse(data);
+ })
+ .catch((error) => {
+ // 422 (Unprocessable Content) - This means the email is in an invalid format.
+ if (error.message.includes("422")) {
+ this.logger.log("Invalid Email Format");
+ this.writeToFields("Invalid", "Invalid Email Format");
+ engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ return;
}
- this.run();
- }
- }
- shouldRun() {
- return engrid_ENGrid.hasBodyData("add-input-placeholders");
- }
- run() {
- Object.keys(this.defaultPlaceholders).forEach((selector) => {
- if (selector in this.defaultPlaceholders)
- this.addPlaceholder(selector, this.defaultPlaceholders[selector]);
+ if (error.name === "AbortError") {
+ this.logger.log("Proxy API request timed out");
+ this.writeToFields("Request Timeout", "The request took too long.");
+ return;
+ }
+ this.logger.log("Proxy API Error", error);
+ this.writeToFields("Service Error", error.toString());
+ })
+ .finally(() => {
+ window.FreshAddressStatus = "idle";
+ engrid_ENGrid.enableSubmit();
});
}
- addPlaceholder(selector, placeholder) {
- const fieldEl = document.querySelector(selector);
- if (fieldEl) {
- fieldEl.placeholder = placeholder;
+ /*
+ * Validate a request proxied to AtData's Safe To Send API.
+ * https://docs.atdata.com/reference/safe-to-send
+ * https://docs.atdata.com/reference/email-status
+ * https://docs.atdata.com/reference/status-codes-safe-to-send
+ */
+ validateProxyResponse(data) {
+ var _a;
+ // If response is not in expected format, log error and let through.
+ if (!data.safe_to_send) {
+ this.logger.log("Invalid Proxy Response");
+ this.writeToFields("Service Error", "Invalid Proxy Response");
+ return true;
+ }
+ const res = data.safe_to_send;
+ engrid_ENGrid.removeError(this.emailWrapper);
+ this.writeToFields(res.status, res.status_code);
+ if (["invalid", "trap"].includes(res.status)) {
+ this.writeToFields("Invalid", res.status_code); // Must be "Invalid" to trigger validation error on submit
+ engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ if (res.email_corrections && res.email_corrections.length > 0) {
+ this.emailField.value = res.email_corrections[0];
+ engrid_ENGrid.setError(this.emailWrapper, `This email address is not valid. Did you mean ${res.email_corrections[0]}?`);
+ }
}
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/media-attribution.js
-/*
- Looks for specially crafted links and will transform its markup to display an attribution overlay on top of the image
- Depends on "_engrid-media-attribution.scss" for styling
-
- Example Image Input
-
-
-
-
- Example Video Input (Doesn't currently visually display)
- @TODO Video tags are processed but their is not visually displayed. Need to update "_engrid-media-attribution.scss"
-
-
- Example Image Output
- Jane Doe 1
-*/
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/progress-bar.js
-const tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
-class MediaAttribution {
+class ProgressBar {
constructor() {
- // Find all images with attribution but not with the "data-attribution-hide-overlay" attribute
- this.mediaWithAttribution = document.querySelectorAll("img[data-attribution-source]:not([data-attribution-hide-overlay]), video[data-attribution-source]:not([data-attribution-hide-overlay])");
- this.mediaWithAttribution.forEach((element) => {
- if (engrid_ENGrid.debug)
- console.log("The following image was found with data attribution fields on it. It's markup will be changed to add caption support.", element);
- // Creates the wapping element
- let figure = document.createElement("figure");
- figure.classList.add("media-with-attribution");
- // Moves the inside its element
- let mediaWithAttributionParent = element.parentNode;
- if (mediaWithAttributionParent) {
- mediaWithAttributionParent.insertBefore(figure, element);
- figure.appendChild(element);
- let mediaWithAttributionElement = element;
- // Append the element after the and conditionally add the Source's Link to it
- let attributionSource = mediaWithAttributionElement.dataset.attributionSource;
- if (attributionSource) {
- let attributionSourceLink = mediaWithAttributionElement.dataset.attributionSourceLink;
- if (attributionSourceLink) {
- mediaWithAttributionElement.insertAdjacentHTML("afterend", '' +
- attributionSource +
- " ");
- }
- else {
- mediaWithAttributionElement.insertAdjacentHTML("afterend", "" + attributionSource + " ");
- }
- const attributionSourceTooltip = "attributionSourceTooltip" in mediaWithAttributionElement.dataset
- ? mediaWithAttributionElement.dataset.attributionSourceTooltip
- : false;
- if (attributionSourceTooltip) {
- tippy(mediaWithAttributionElement.nextSibling, {
- content: attributionSourceTooltip,
- arrow: true,
- arrowType: "default",
- placement: "left",
- trigger: "click mouseenter focus",
- interactive: true,
- });
- }
- }
- }
- });
+ var _a, _b;
+ const progressIndicator = document.querySelector("span[data-engrid-progress-indicator]");
+ const pageCount = engrid_ENGrid.getPageCount();
+ const pageNumber = engrid_ENGrid.getPageNumber();
+ if (!progressIndicator || !pageCount || !pageNumber) {
+ return;
+ }
+ let maxValue = (_a = progressIndicator.getAttribute("max")) !== null && _a !== void 0 ? _a : 100;
+ if (typeof maxValue === "string")
+ maxValue = parseInt(maxValue);
+ let amountValue = (_b = progressIndicator.getAttribute("amount")) !== null && _b !== void 0 ? _b : 0;
+ if (typeof amountValue === "string")
+ amountValue = parseInt(amountValue);
+ const prevPercentage = pageNumber === 1
+ ? 0
+ : Math.ceil(((pageNumber - 1) / pageCount) * maxValue);
+ let percentage = pageNumber === 1 ? 0 : Math.ceil((pageNumber / pageCount) * maxValue);
+ const scalePrev = prevPercentage / 100;
+ let scale = percentage / 100;
+ if (amountValue) {
+ percentage =
+ Math.ceil(amountValue) > Math.ceil(maxValue) ? maxValue : amountValue;
+ scale = percentage / 100;
+ }
+ progressIndicator.innerHTML = `
+
+
+ ${percentage}%
+
`;
+ if (percentage !== prevPercentage) {
+ const progress = document.querySelector(".indicator__progress");
+ requestAnimationFrame(function () {
+ progress.style.transform = `scaleX(${scale})`;
+ });
+ }
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/live-variables.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/remember-me.js
-class LiveVariables {
+const remember_me_tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
+class RememberMe {
constructor(options) {
- var _a;
- this._amount = DonationAmount.getInstance();
- this._fees = ProcessingFees.getInstance();
- this._frequency = DonationFrequency.getInstance();
this._form = en_form_EnForm.getInstance();
- this.multiplier = 1 / 12;
- this.options = Object.assign(Object.assign({}, OptionsDefaults), options);
- this.submitLabel =
- ((_a = document.querySelector(".en__submit button")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "Donate";
- this._amount.onAmountChange.subscribe(() => this.changeSubmitButton());
- this._amount.onAmountChange.subscribe(() => this.changeLiveAmount());
- this._amount.onAmountChange.subscribe(() => this.changeLiveUpsellAmount());
- this._fees.onFeeChange.subscribe(() => this.changeLiveAmount());
- this._fees.onFeeChange.subscribe(() => this.changeLiveUpsellAmount());
- this._fees.onFeeChange.subscribe(() => this.changeSubmitButton());
- this._frequency.onFrequencyChange.subscribe(() => this.changeLiveFrequency());
- this._frequency.onFrequencyChange.subscribe(() => this.changeRecurrency());
- this._frequency.onFrequencyChange.subscribe(() => this.changeSubmitButton());
- this._form.onSubmit.subscribe(() => {
- if (engrid_ENGrid.getPageType() !== "SUPPORTERHUB")
- engrid_ENGrid.disableSubmit("Processing...");
- });
- this._form.onError.subscribe(() => engrid_ENGrid.enableSubmit());
- // Watch the monthly-upsell links
- document.addEventListener("click", (e) => {
- const element = e.target;
- if (element) {
- if (element.classList.contains("monthly-upsell")) {
- this.upsold(e);
+ this._events = RememberMeEvents.getInstance();
+ this.iframe = null;
+ this.remoteUrl = options.remoteUrl ? options.remoteUrl : null;
+ this.cookieName = options.cookieName
+ ? options.cookieName
+ : "engrid-autofill";
+ this.cookieExpirationDays = options.cookieExpirationDays
+ ? options.cookieExpirationDays
+ : 365;
+ this.rememberMeOptIn = options.checked ? options.checked : false;
+ this.fieldNames = options.fieldNames ? options.fieldNames : [];
+ this.fieldDonationAmountRadioName = options.fieldDonationAmountRadioName
+ ? options.fieldDonationAmountRadioName
+ : "transaction.donationAmt";
+ this.fieldDonationAmountOtherName = options.fieldDonationAmountOtherName
+ ? options.fieldDonationAmountOtherName
+ : "transaction.donationAmt.other";
+ this.fieldDonationRecurrPayRadioName =
+ options.fieldDonationRecurrPayRadioName
+ ? options.fieldDonationRecurrPayRadioName
+ : "transaction.recurrpay";
+ this.fieldDonationAmountOtherCheckboxID =
+ options.fieldDonationAmountOtherCheckboxID
+ ? options.fieldDonationAmountOtherCheckboxID
+ : "#en__field_transaction_donationAmt4";
+ this.fieldOptInSelectorTarget = options.fieldOptInSelectorTarget
+ ? options.fieldOptInSelectorTarget
+ : ".en__field--emailAddress.en__field";
+ this.fieldOptInSelectorTargetLocation =
+ options.fieldOptInSelectorTargetLocation
+ ? options.fieldOptInSelectorTargetLocation
+ : "after";
+ this.fieldClearSelectorTarget = options.fieldClearSelectorTarget
+ ? options.fieldClearSelectorTarget
+ : 'label[for="en__field_supporter_firstName"]';
+ this.fieldClearSelectorTargetLocation =
+ options.fieldClearSelectorTargetLocation
+ ? options.fieldClearSelectorTargetLocation
+ : "before";
+ this.fieldData = {};
+ if (this.useRemote()) {
+ this.createIframe(() => {
+ if (this.iframe && this.iframe.contentWindow) {
+ this.iframe.contentWindow.postMessage(JSON.stringify({ key: this.cookieName, operation: "read" }), "*");
+ this._form.onSubmit.subscribe(() => {
+ if (this.rememberMeOptIn) {
+ this.readFields();
+ this.saveCookieToRemote();
+ }
+ });
}
- else if (element.classList.contains("form-submit")) {
- e.preventDefault();
- this._form.submitForm();
+ }, (event) => {
+ let data;
+ if (event.data &&
+ typeof event.data === "string" &&
+ this.isJson(event.data)) {
+ data = JSON.parse(event.data);
}
- }
- });
- }
- getAmountTxt(amount = 0) {
- var _a, _b, _c, _d;
- const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
- const dec_separator = (_b = this.options.DecimalSeparator) !== null && _b !== void 0 ? _b : ".";
- const thousands_separator = (_c = this.options.ThousandsSeparator) !== null && _c !== void 0 ? _c : "";
- const dec_places = amount % 1 == 0 ? 0 : (_d = this.options.DecimalPlaces) !== null && _d !== void 0 ? _d : 2;
- const amountTxt = engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
- return amount > 0
- ? (`${symbol} ${amountTxt} `)
- : "";
- }
- getUpsellAmountTxt(amount = 0) {
- var _a, _b, _c, _d;
- const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
- const dec_separator = (_b = this.options.DecimalSeparator) !== null && _b !== void 0 ? _b : ".";
- const thousands_separator = (_c = this.options.ThousandsSeparator) !== null && _c !== void 0 ? _c : "";
- const dec_places = amount % 1 == 0 ? 0 : (_d = this.options.DecimalPlaces) !== null && _d !== void 0 ? _d : 2;
- const amountTxt = engrid_ENGrid.formatNumber(Math.ceil(amount / 5) * 5, dec_places, dec_separator, thousands_separator);
- return amount > 0 ? symbol + amountTxt : "";
- }
- getUpsellAmountRaw(amount = 0) {
- const amountRaw = Math.ceil(amount / 5) * 5;
- return amount > 0 ? amountRaw.toString() : "";
- }
- changeSubmitButton() {
- const submit = document.querySelector(".en__submit button");
- const amount = this.getAmountTxt(this._amount.amount + this._fees.fee);
- const frequency = this._frequency.frequency == "onetime"
- ? ""
- : this._frequency.frequency == "annual"
- ? "annually"
- : this._frequency.frequency;
- let label = this.submitLabel;
- if (amount) {
- label = label.replace("$AMOUNT", amount);
- label = label.replace("$FREQUENCY", `${frequency} `);
+ if (data &&
+ data.key &&
+ data.value !== undefined &&
+ data.key === this.cookieName) {
+ this.updateFieldData(data.value);
+ this.writeFields();
+ let hasFieldData = Object.keys(this.fieldData).length > 0;
+ if (!hasFieldData) {
+ this.insertRememberMeOptin();
+ }
+ else {
+ this.insertClearRememberMeLink();
+ }
+ }
+ });
}
else {
- label = label.replace("$AMOUNT", "");
- label = label.replace("$FREQUENCY", "");
- }
- if (submit && label) {
- submit.innerHTML = label;
- }
- }
- changeLiveAmount() {
- const value = this._amount.amount + this._fees.fee;
- const live_amount = document.querySelectorAll(".live-giving-amount");
- live_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(value)));
- }
- changeLiveUpsellAmount() {
- const value = (this._amount.amount + this._fees.fee) * this.multiplier;
- const live_upsell_amount = document.querySelectorAll(".live-giving-upsell-amount");
- live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getUpsellAmountTxt(value)));
- const live_upsell_amount_raw = document.querySelectorAll(".live-giving-upsell-amount-raw");
- live_upsell_amount_raw.forEach((elem) => (elem.innerHTML = this.getUpsellAmountRaw(value)));
- }
- changeLiveFrequency() {
- const live_frequency = document.querySelectorAll(".live-giving-frequency");
- live_frequency.forEach((elem) => (elem.innerHTML =
- this._frequency.frequency == "onetime"
- ? ""
- : this._frequency.frequency));
- }
- changeRecurrency() {
- const recurrpay = document.querySelector("[name='transaction.recurrpay']");
- if (recurrpay && recurrpay.type != "radio") {
- recurrpay.value = this._frequency.frequency == "onetime" ? "N" : "Y";
- this._frequency.recurring = recurrpay.value;
- if (engrid_ENGrid.getOption("Debug"))
- console.log("Recurpay Changed!");
- // Trigger the onChange event for the field
- const event = new Event("change", { bubbles: true });
- recurrpay.dispatchEvent(event);
- }
- }
- // Watch for a clicks on monthly-upsell link
- upsold(e) {
- // Find and select monthly giving
- const enFieldRecurrpay = document.querySelector(".en__field--recurrpay input[value='Y']");
- if (enFieldRecurrpay) {
- enFieldRecurrpay.checked = true;
- }
- // Find the hidden radio select that needs to be selected when entering an "Other" amount
- const enFieldOtherAmountRadio = document.querySelector(".en__field--donationAmt input[value='other']");
- if (enFieldOtherAmountRadio) {
- enFieldOtherAmountRadio.checked = true;
- }
- // Enter the other amount and remove the "en__field__item--hidden" class from the input's parent
- const enFieldOtherAmount = document.querySelector("input[name='transaction.donationAmt.other']");
- if (enFieldOtherAmount) {
- enFieldOtherAmount.value = this.getUpsellAmountRaw(this._amount.amount * this.multiplier);
- this._amount.load();
- this._frequency.load();
- if (enFieldOtherAmount.parentElement) {
- enFieldOtherAmount.parentElement.classList.remove("en__field__item--hidden");
+ this.readCookie();
+ let hasFieldData = Object.keys(this.fieldData).length > 0;
+ if (!hasFieldData) {
+ this.insertRememberMeOptin();
+ this.rememberMeOptIn = false;
}
- }
- const target = e.target;
- if (target && target.classList.contains("form-submit")) {
- e.preventDefault();
- // Form submit
- this._form.submitForm();
+ else {
+ this.insertClearRememberMeLink();
+ this.rememberMeOptIn = true;
+ }
+ this.writeFields();
+ this._form.onSubmit.subscribe(() => {
+ if (this.rememberMeOptIn) {
+ this.readFields();
+ this.saveCookie();
+ }
+ });
}
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/upsell-lightbox.js
-
-
-class UpsellLightbox {
- constructor() {
- this.overlay = document.createElement("div");
- this._form = en_form_EnForm.getInstance();
- this._amount = DonationAmount.getInstance();
- this._fees = ProcessingFees.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this._dataLayer = DataLayer.getInstance();
- this._suggestAmount = 0;
- this.logger = new logger_EngridLogger("UpsellLightbox", "black", "pink", "πͺ");
- let options = "EngridUpsell" in window ? window.EngridUpsell : {};
- this.options = Object.assign(Object.assign({}, UpsellOptionsDefaults), options);
- //Disable for "applepay" via Vantiv payment method. Adding it to the array like this so it persists
- //even if the client provides custom options.
- this.options.disablePaymentMethods.push("applepay");
- if (!this.shouldRun()) {
- this.logger.log("Upsell script should NOT run");
- // If we're not on a Donation Page, get out
- return;
+ updateFieldData(jsonData) {
+ if (jsonData) {
+ let data = JSON.parse(jsonData);
+ for (let i = 0; i < this.fieldNames.length; i++) {
+ if (data[this.fieldNames[i]] !== undefined) {
+ this.fieldData[this.fieldNames[i]] = decodeURIComponent(data[this.fieldNames[i]]);
+ }
+ }
}
- this.overlay.id = "enModal";
- this.overlay.classList.add("is-hidden");
- this.overlay.classList.add("image-" + this.options.imagePosition);
- this.renderLightbox();
- this._form.onSubmit.subscribe(() => this.open());
}
- renderLightbox() {
- const title = this.options.title
- .replace("{new-amount}", " ")
- .replace("{old-amount}", " ")
- .replace("{old-frequency}", " ");
- const paragraph = this.options.paragraph
- .replace("{new-amount}", " ")
- .replace("{old-amount}", " ")
- .replace("{old-frequency}", " ");
- const yes = this.options.yesLabel
- .replace("{new-amount}", " ")
- .replace("{old-amount}", " ")
- .replace("{old-frequency}", " ");
- const no = this.options.noLabel
- .replace("{new-amount}", " ")
- .replace("{old-amount}", " ")
- .replace("{old-frequency}", " ");
- const markup = `
-
-
-
-
- ${this.options.canClose ? `
` : ``}
-
- ${title}
-
- ${this.options.otherAmount
- ? `
-
-
-
- ${this.options.otherLabel}
-
-
-
-
- Minimum ${this.getAmountTxt(this.options.minAmount)}
-
-
- `
- : ``}
-
-
- ${paragraph}
-
-
-
-
-
-
-
- `;
- this.overlay.innerHTML = markup;
- const closeButton = this.overlay.querySelector("#goMonthlyClose");
- const yesButton = this.overlay.querySelector("#upsellYesButton a");
- const noButton = this.overlay.querySelector("#upsellNoButton button");
- yesButton.addEventListener("click", this.continue.bind(this));
- noButton.addEventListener("click", this.continue.bind(this));
- if (closeButton)
- closeButton.addEventListener("click", this.close.bind(this));
- this.overlay.addEventListener("click", (e) => {
- if (e.target instanceof Element &&
- e.target.id == this.overlay.id &&
- this.options.canClose) {
- this.close(e);
+ insertClearRememberMeLink() {
+ let clearRememberMeField = document.getElementById("clear-autofill-data");
+ if (!clearRememberMeField) {
+ const clearAutofillLabel = "clear autofill";
+ clearRememberMeField = document.createElement("a");
+ clearRememberMeField.setAttribute("id", "clear-autofill-data");
+ clearRememberMeField.classList.add("label-tooltip");
+ clearRememberMeField.setAttribute("style", "cursor: pointer;");
+ clearRememberMeField.innerHTML = `(${clearAutofillLabel})`;
+ const targetField = this.getElementByFirstSelector(this.fieldClearSelectorTarget);
+ if (targetField) {
+ if (this.fieldClearSelectorTargetLocation === "after") {
+ targetField.appendChild(clearRememberMeField);
+ }
+ else {
+ targetField.prepend(clearRememberMeField);
+ }
+ }
+ }
+ clearRememberMeField.addEventListener("click", (e) => {
+ e.preventDefault();
+ this.clearFields(["supporter.country" /*, 'supporter.emailAddress'*/]);
+ if (this.useRemote()) {
+ this.clearCookieOnRemote();
}
- });
- document.addEventListener("keyup", (e) => {
- if (e.key === "Escape" && closeButton) {
- closeButton.click();
+ else {
+ this.clearCookie();
+ }
+ let clearAutofillLink = document.getElementById("clear-autofill-data");
+ if (clearAutofillLink) {
+ clearAutofillLink.style.display = "none";
}
+ this.rememberMeOptIn = false;
+ this._events.dispatchClear();
+ window.dispatchEvent(new CustomEvent("RememberMe_Cleared"));
});
- document.body.appendChild(this.overlay);
- const otherField = document.querySelector("#secondOtherField");
- if (otherField) {
- otherField.addEventListener("keyup", this.popupOtherField.bind(this));
- }
- this.logger.log("Upsell script rendered");
- }
- // Should we run the script?
- shouldRun() {
- // if it's a first page of a Donation page
- return (
- // !hideModal &&
- !this.shouldSkip() &&
- "EngridUpsell" in window &&
- !!window.pageJson &&
- window.pageJson.pageNumber == 1 &&
- ["donation", "premiumgift"].includes(window.pageJson.pageType));
+ this._events.dispatchLoad(true);
+ window.dispatchEvent(new CustomEvent("RememberMe_Loaded", { detail: { withData: true } }));
}
- shouldSkip() {
- if ("EngridUpsell" in window && window.EngridUpsell.skipUpsell) {
- return true;
+ getElementByFirstSelector(selectorsString) {
+ // iterate through the selectors until we find one that exists
+ let targetField = null;
+ const selectorTargets = selectorsString.split(",");
+ for (let i = 0; i < selectorTargets.length; i++) {
+ targetField = document.querySelector(selectorTargets[i]);
+ if (targetField) {
+ break;
+ }
}
- return this.options.skipUpsell;
+ return targetField;
}
- popupOtherField() {
- var _a, _b;
- const value = parseFloat((_b = (_a = this.overlay.querySelector("#secondOtherField")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
- const live_upsell_amount = document.querySelectorAll("#upsellYesButton .upsell_suggestion");
- const upsellAmount = this.getUpsellAmount();
- if (!isNaN(value) && value > 0) {
- this.checkOtherAmount(value);
+ insertRememberMeOptin() {
+ let rememberMeOptInField = document.getElementById("remember-me-opt-in");
+ if (!rememberMeOptInField) {
+ const rememberMeLabel = "Remember Me";
+ const rememberMeInfo = `
+ Check βRemember meβ to complete forms on this device faster.
+ While your financial information wonβt be stored, you should only check this box from a personal device.
+ Click βClear autofillβ to remove the information from your device at any time.
+ `;
+ const rememberMeOptInFieldChecked = this.rememberMeOptIn ? "checked" : "";
+ const rememberMeOptInField = document.createElement("div");
+ rememberMeOptInField.classList.add("en__field", "en__field--checkbox", "en__field--question", "rememberme-wrapper");
+ rememberMeOptInField.setAttribute("id", "remember-me-opt-in");
+ rememberMeOptInField.setAttribute("style", "overflow-x: hidden;");
+ rememberMeOptInField.innerHTML = `
+
+
+
+
+
+ ${rememberMeLabel}
+
+
+
+
+
+
+
+ `;
+ const targetField = this.getElementByFirstSelector(this.fieldOptInSelectorTarget);
+ if (targetField && targetField.parentNode) {
+ targetField.parentNode.insertBefore(rememberMeOptInField, this.fieldOptInSelectorTargetLocation == "before"
+ ? targetField
+ : targetField.nextSibling);
+ const rememberMeCheckbox = document.getElementById("remember-me-checkbox");
+ if (rememberMeCheckbox) {
+ rememberMeCheckbox.addEventListener("change", () => {
+ if (rememberMeCheckbox.checked) {
+ this.rememberMeOptIn = true;
+ }
+ else {
+ this.rememberMeOptIn = false;
+ }
+ });
+ }
+ remember_me_tippy("#rememberme-learn-more-toggle", { content: rememberMeInfo });
+ }
}
- else {
- this.checkOtherAmount(upsellAmount);
+ else if (this.rememberMeOptIn) {
+ rememberMeOptInField.checked = true;
}
- live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(upsellAmount + this._fees.calculateFees(upsellAmount))));
+ this._events.dispatchLoad(false);
+ window.dispatchEvent(new CustomEvent("RememberMe_Loaded", { detail: { withData: false } }));
}
- liveAmounts() {
- const live_upsell_amount = document.querySelectorAll(".upsell_suggestion");
- const live_amount = document.querySelectorAll(".upsell_amount");
- const upsellAmount = this.getUpsellAmount();
- const suggestedAmount = upsellAmount + this._fees.calculateFees(upsellAmount);
- live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(suggestedAmount)));
- live_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(this._amount.amount + this._fees.fee)));
+ useRemote() {
+ return (!!this.remoteUrl &&
+ typeof window.postMessage === "function" &&
+ window.JSON &&
+ window.localStorage);
}
- liveFrequency() {
- const live_upsell_frequency = document.querySelectorAll(".upsell_frequency");
- live_upsell_frequency.forEach((elem) => (elem.innerHTML = this.getFrequencyTxt()));
+ createIframe(iframeLoaded, messageReceived) {
+ if (this.remoteUrl) {
+ let iframe = document.createElement("iframe");
+ iframe.style.cssText =
+ "position:absolute;width:1px;height:1px;left:-9999px;";
+ iframe.src = this.remoteUrl;
+ iframe.setAttribute("sandbox", "allow-same-origin allow-scripts");
+ iframe.setAttribute("title", "Remember Me iframe");
+ this.iframe = iframe;
+ document.body.appendChild(this.iframe);
+ this.iframe.addEventListener("load", () => iframeLoaded(), false);
+ window.addEventListener("message", (event) => {
+ var _a;
+ if (((_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) === event.source) {
+ messageReceived(event);
+ }
+ }, false);
+ }
}
- // Return the Suggested Upsell Amount
- getUpsellAmount() {
- var _a, _b;
- const amount = this._amount.amount;
- const otherAmount = parseFloat((_b = (_a = this.overlay.querySelector("#secondOtherField")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
- if (otherAmount > 0) {
- return otherAmount > this.options.minAmount
- ? otherAmount
- : this.options.minAmount;
+ clearCookie() {
+ this.fieldData = {};
+ this.saveCookie();
+ }
+ clearCookieOnRemote() {
+ this.fieldData = {};
+ this.saveCookieToRemote();
+ }
+ saveCookieToRemote() {
+ if (this.iframe && this.iframe.contentWindow) {
+ this.iframe.contentWindow.postMessage(JSON.stringify({
+ key: this.cookieName,
+ value: this.fieldData,
+ operation: "write",
+ expires: this.cookieExpirationDays,
+ }), "*");
}
- let upsellAmount = 0;
- for (let i = 0; i < this.options.amountRange.length; i++) {
- let val = this.options.amountRange[i];
- if (upsellAmount == 0 && amount <= val.max) {
- upsellAmount = val.suggestion;
- if (upsellAmount === 0)
- return 0;
- if (typeof upsellAmount !== "number") {
- const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
- upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
+ }
+ readCookie() {
+ this.updateFieldData(get(this.cookieName) || "");
+ }
+ saveCookie() {
+ set(this.cookieName, JSON.stringify(this.fieldData), {
+ expires: this.cookieExpirationDays,
+ });
+ }
+ readFields() {
+ for (let i = 0; i < this.fieldNames.length; i++) {
+ let fieldSelector = "[name='" + this.fieldNames[i] + "']";
+ let field = document.querySelector(fieldSelector);
+ if (field) {
+ if (field.tagName === "INPUT") {
+ let type = field.getAttribute("type");
+ if (type === "radio" || type === "checkbox") {
+ field = document.querySelector(fieldSelector + ":checked");
+ }
+ this.fieldData[this.fieldNames[i]] = encodeURIComponent(field.value);
+ }
+ else if (field.tagName === "SELECT") {
+ this.fieldData[this.fieldNames[i]] = encodeURIComponent(field.value);
}
- break;
}
}
- return upsellAmount > this.options.minAmount
- ? upsellAmount
- : this.options.minAmount;
}
- shouldOpen() {
- const upsellAmount = this.getUpsellAmount();
- const paymenttype = engrid_ENGrid.getFieldValue("transaction.paymenttype") || "";
- this._suggestAmount = upsellAmount;
- // If frequency is not onetime or
- // the modal is already opened or
- // there's no suggestion for this donation amount,
- // we should not open
- if (this.freqAllowed() &&
- !this.shouldSkip() &&
- !this.options.disablePaymentMethods.includes(paymenttype.toLowerCase()) &&
- !this.overlay.classList.contains("is-submitting") &&
- upsellAmount > 0) {
- this.logger.log("Upsell Frequency " + this._frequency.frequency);
- this.logger.log("Upsell Amount " + this._amount.amount);
- this.logger.log("Upsell Suggested Amount " + upsellAmount);
- return true;
+ setFieldValue(field, value, overwrite = false) {
+ value = decodeURIComponent(value || "");
+ if (field && value !== undefined) {
+ if ("type" in field) {
+ switch (field.type) {
+ case "select-one":
+ case "select-multiple": {
+ const selectField = field;
+ for (const option of Array.from(selectField.options)) {
+ if (option.value === value) {
+ if ((selectField.value && overwrite) || !selectField.value) {
+ option.selected = true;
+ selectField.dispatchEvent(new Event("change", { bubbles: true }));
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case "checkbox":
+ case "radio": {
+ const inputField = field;
+ if (inputField.value === value) {
+ inputField.checked = true;
+ inputField.dispatchEvent(new Event("change", { bubbles: true }));
+ }
+ break;
+ }
+ case "textarea":
+ case "text":
+ default:
+ if ((field.value && overwrite) || !field.value) {
+ field.value = value;
+ field.dispatchEvent(new Event("change", { bubbles: true }));
+ field.dispatchEvent(new Event("blur", { bubbles: true }));
+ }
+ }
+ }
}
- return false;
- }
- // Return true if the current frequency is allowed by the options
- freqAllowed() {
- const freq = this._frequency.frequency;
- const allowed = [];
- if (this.options.oneTime)
- allowed.push("onetime");
- if (this.options.annual)
- allowed.push("annual");
- return allowed.includes(freq);
}
- open() {
- this.logger.log("Upsell script opened");
- if (!this.shouldOpen()) {
- // In the circumstance when the form fails to validate via server-side validation, the page will reload
- // When that happens, we should place the original amount saved in sessionStorage into the upsell original amount field
- let original = window.sessionStorage.getItem("original");
- if (original &&
- document.querySelectorAll(".en__errorList .en__error").length > 0) {
- this.setOriginalAmount(original);
+ clearFields(skipFields) {
+ for (let key in this.fieldData) {
+ if (skipFields.includes(key)) {
+ delete this.fieldData[key];
+ }
+ else if (this.fieldData[key] === "") {
+ delete this.fieldData[key];
+ }
+ else {
+ this.fieldData[key] = "";
}
- // Returning true will give the "go ahead" to submit the form
- this._form.submit = true;
- return true;
}
- this.liveAmounts();
- this.liveFrequency();
- this.overlay.classList.remove("is-hidden");
- this._form.submit = false;
- engrid_ENGrid.setBodyData("has-lightbox", "");
- return false;
+ this.writeFields(true);
}
- // Set the original amount into a hidden field using the upsellOriginalGiftAmountFieldName, if provided
- setOriginalAmount(original) {
- if (this.options.upsellOriginalGiftAmountFieldName) {
- let enFieldUpsellOriginalAmount = document.querySelector(".en__field__input.en__field__input--hidden[name='" +
- this.options.upsellOriginalGiftAmountFieldName +
- "']");
- if (!enFieldUpsellOriginalAmount) {
- let pageform = document.querySelector("form.en__component--page");
- if (pageform) {
- let input = document.createElement("input");
- input.setAttribute("type", "hidden");
- input.setAttribute("name", this.options.upsellOriginalGiftAmountFieldName);
- input.classList.add("en__field__input", "en__field__input--hidden");
- pageform.appendChild(input);
- enFieldUpsellOriginalAmount = document.querySelector('.en__field__input.en__field__input--hidden[name="' +
- this.options.upsellOriginalGiftAmountFieldName +
- '"]');
+ /**
+ * Writes the values from the fieldData object to the corresponding HTML input fields.
+ *
+ * This function iterates over the fieldNames array and for each field name, it selects the corresponding HTML input field.
+ * If the field is found and its tag name is "INPUT", it checks if the field name matches certain conditions (like being a donation recurring payment radio button or a donation amount radio button).
+ * Depending on these conditions, it either clicks the field or sets its value using the setFieldValue function.
+ * If the field tag name is "SELECT", it sets its value using the setFieldValue function.
+ *
+ * @param overwrite - A boolean indicating whether to overwrite the existing value of the fields. Defaults to false.
+ */
+ writeFields(overwrite = false) {
+ for (let i = 0; i < this.fieldNames.length; i++) {
+ let fieldSelector = "[name='" + this.fieldNames[i] + "']";
+ let field = document.querySelector(fieldSelector);
+ if (field) {
+ if (field.tagName === "INPUT") {
+ if (this.fieldNames[i] === this.fieldDonationRecurrPayRadioName) {
+ if (this.fieldData[this.fieldNames[i]] === "Y") {
+ field.click();
+ }
+ }
+ else if (this.fieldDonationAmountRadioName === this.fieldNames[i]) {
+ field = document.querySelector(fieldSelector +
+ "[value='" +
+ this.fieldData[this.fieldNames[i]] +
+ "']");
+ if (field) {
+ field.click();
+ }
+ else {
+ field = document.querySelector("input[name='" + this.fieldDonationAmountOtherName + "']");
+ this.setFieldValue(field, this.fieldData[this.fieldNames[i]], true);
+ }
+ }
+ else {
+ this.setFieldValue(field, this.fieldData[this.fieldNames[i]], overwrite);
+ }
+ }
+ else if (field.tagName === "SELECT") {
+ this.setFieldValue(field, this.fieldData[this.fieldNames[i]], true);
}
- }
- if (enFieldUpsellOriginalAmount) {
- // save it to a session variable just in case this page reloaded due to server-side validation error
- window.sessionStorage.setItem("original", original);
- enFieldUpsellOriginalAmount.setAttribute("value", original);
}
}
}
- // Proceed to the next page (upsold or not)
- continue(e) {
- var _a;
- e.preventDefault();
- if (e.target instanceof Element &&
- ((_a = document.querySelector("#upsellYesButton")) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
- this.logger.success("Upsold");
- this.setOriginalAmount(this._amount.amount.toString());
- const upsoldAmount = this.getUpsellAmount();
- const originalAmount = this._amount.amount;
- this._frequency.setFrequency("monthly");
- this._amount.setAmount(upsoldAmount);
- this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL", {
- eventValue: true,
- originalAmount: originalAmount,
- upsoldAmount: upsoldAmount,
- frequency: "monthly",
- });
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL", true);
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT", originalAmount);
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "MONTHLY");
- this.renderConversionField("upsellSuccess", "onetime", originalAmount, "monthly", this._suggestAmount, "monthly", upsoldAmount);
+ isJson(str) {
+ try {
+ JSON.parse(str);
}
- else {
- this.setOriginalAmount("");
- window.sessionStorage.removeItem("original");
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL", false);
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "ONE-TIME");
- this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._suggestAmount, this._frequency.frequency, this._amount.amount);
+ catch (e) {
+ return false;
}
- this._form.submitForm();
+ return true;
}
- // Close the lightbox
- close(e) {
- e.preventDefault();
- this.overlay.classList.add("is-hidden");
- engrid_ENGrid.setBodyData("has-lightbox", false);
- if (this.options.submitOnClose) {
- this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._suggestAmount, this._frequency.frequency, this._amount.amount);
- this._form.submitForm();
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/show-if-amount.js
+
+
+class ShowIfAmount {
+ constructor() {
+ this._amount = DonationAmount.getInstance();
+ this.logger = new logger_EngridLogger("ShowIfAmount", "yellow", "black", "π");
+ this._elements = document.querySelectorAll('[class*="showifamount"]');
+ if (this._elements.length > 0) {
+ this._amount.onAmountChange.subscribe(() => this.init());
+ this.init();
+ return;
}
- else {
- this._form.dispatchError();
+ this.logger.log("Show If Amount: NO ELEMENTS FOUND");
+ }
+ init() {
+ //If we are on a thank you page, use the window.pageJson.amount
+ const amount = engrid_ENGrid.getGiftProcess()
+ ? window.pageJson.amount
+ : this._amount.amount;
+ this._elements.forEach((element) => {
+ this.lessthan(amount, element);
+ this.lessthanorequalto(amount, element);
+ this.equalto(amount, element);
+ this.greaterthanorequalto(amount, element);
+ this.greaterthan(amount, element);
+ this.between(amount, element);
+ });
+ }
+ getClassNameByOperand(classList, operand) {
+ let myClass = null;
+ classList.forEach((className) => {
+ if (className.includes(`showifamount-${operand}-`)) {
+ myClass = className;
+ }
+ });
+ return myClass;
+ }
+ lessthan(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "lessthan");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount < Number(amountCheck)) {
+ this.logger.log("(lessthan):", element);
+ element.classList.add("engrid-open");
+ }
+ else {
+ element.classList.remove("engrid-open");
+ }
}
}
- getAmountTxt(amount = 0) {
- var _a, _b, _c, _d;
- const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
- const dec_separator = (_b = engrid_ENGrid.getOption("DecimalSeparator")) !== null && _b !== void 0 ? _b : ".";
- const thousands_separator = (_c = engrid_ENGrid.getOption("ThousandsSeparator")) !== null && _c !== void 0 ? _c : "";
- const dec_places = amount % 1 == 0 ? 0 : (_d = engrid_ENGrid.getOption("DecimalPlaces")) !== null && _d !== void 0 ? _d : 2;
- const amountTxt = engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
- return amount > 0 ? symbol + amountTxt : "";
+ lessthanorequalto(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "lessthanorequalto");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount <= Number(amountCheck)) {
+ this.logger.log("(lessthanorequalto):", element);
+ element.classList.add("engrid-open");
+ }
+ else {
+ element.classList.remove("engrid-open");
+ }
+ }
}
- getFrequencyTxt() {
- const freqTxt = {
- onetime: "one-time",
- monthly: "monthly",
- annual: "annual",
- };
- const frequency = this._frequency.frequency;
- return frequency in freqTxt ? freqTxt[frequency] : frequency;
+ equalto(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "equalto");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount == Number(amountCheck)) {
+ this.logger.log("(equalto):", element);
+ element.classList.add("engrid-open");
+ }
+ else {
+ element.classList.remove("engrid-open");
+ }
+ }
+ }
+ greaterthanorequalto(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "greaterthanorequalto");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount >= Number(amountCheck)) {
+ this.logger.log("(greaterthanorequalto):", element);
+ element.classList.add("engrid-open");
+ }
+ else {
+ element.classList.remove("engrid-open");
+ }
+ }
}
- checkOtherAmount(value) {
- const otherInput = document.querySelector(".upsellOtherAmountInput");
- if (otherInput) {
- if (value >= this.options.minAmount) {
- otherInput.classList.remove("is-invalid");
+ greaterthan(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "greaterthan");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount > Number(amountCheck)) {
+ this.logger.log("(greaterthan):", element);
+ element.classList.add("engrid-open");
}
else {
- otherInput.classList.add("is-invalid");
+ element.classList.remove("engrid-open");
}
}
}
- renderConversionField(event, // The event that triggered the conversion
- freq, // The frequency of the donation (onetime, monthly, annual)
- amt, // The original amount of the donation (before the upsell)
- sugFreq, // The suggested frequency of the upsell (monthly)
- sugAmt, // The suggested amount of the upsell
- subFreq, // The submitted frequency of the upsell (onetime, monthly, annual)
- subAmt // The submitted amount of the upsell
- ) {
- if (this.options.conversionField === "")
- return;
- const conversionField = document.querySelector("input[name='" + this.options.conversionField + "']") ||
- engrid_ENGrid.createHiddenInput(this.options.conversionField);
- if (!conversionField) {
- this.logger.error("Could not find or create the conversion field");
- return;
+ between(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "between");
+ if (showifamountClass) {
+ let amountCheckMin = showifamountClass.split("-").slice(-2, -1)[0];
+ let amountCheckMax = showifamountClass.split("-").slice(-1)[0];
+ if (amount > Number(amountCheckMin) && amount < Number(amountCheckMax)) {
+ this.logger.log("(between):", element);
+ element.classList.add("engrid-open");
+ }
+ else {
+ element.classList.remove("engrid-open");
+ }
}
- const conversionValue = `event:${event},freq:${freq},amt:${amt},sugFreq:${sugFreq},sugAmt:${sugAmt},subFreq:${subFreq},subAmt:${subAmt}`;
- conversionField.value = conversionValue;
- this.logger.log(`Conversion Field ${event}`, conversionValue);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/upsell-checkbox.js
-// This component will add a checkbox to the donation form that will allow the user to upgrade their donation to a monthly donation.
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/other-amount.js
+// This class automatically select other radio input when an amount is entered into it.
-class UpsellCheckbox {
+class OtherAmount {
constructor() {
- this.checkboxOptions = false;
- this.checkboxOptionsDefaults = {
- label: "Make my gift a monthly gift of {new-amount}/mo ",
- location: "before .en__component .en__submit",
- cssClass: "",
- };
+ this.logger = new logger_EngridLogger("OtherAmount", "green", "black", "π°");
this._amount = DonationAmount.getInstance();
- this._fees = ProcessingFees.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this._dataLayer = DataLayer.getInstance();
- this.checkboxContainer = null;
- this.oldAmount = 0;
- this.oldFrequency = "one-time";
- this.resetCheckbox = false;
- this.logger = new logger_EngridLogger("UpsellCheckbox", "black", "LemonChiffon", "β
");
- let options = "EngridUpsell" in window ? window.EngridUpsell : {};
- this.options = Object.assign(Object.assign({}, UpsellOptionsDefaults), options);
- if (this.options.upsellCheckbox === false) {
- this.logger.log("Skipped");
- return;
- }
- // To avoid using both UpsellLightbox and UpsellCheckbox at the same time, set window.EngridUpsell.skipUpsell to true if there's an upsellCheckbox
- if ("upsellCheckbox" in options && options.upsellCheckbox !== false) {
- window.EngridUpsell.skipUpsell = true; // Skip the upsell lightbox
- }
- this.checkboxOptions = Object.assign(Object.assign({}, this.checkboxOptionsDefaults), this.options.upsellCheckbox);
- if (!this.shouldRun()) {
- this.logger.log("should NOT run");
- // If we're not on a Donation Page, get out
- return;
+ "focusin input".split(" ").forEach((e) => {
+ var _a;
+ // We're attaching this event to the body because sometimes the other amount input is not in the DOM yet and comes via AJAX.
+ (_a = document.querySelector("body")) === null || _a === void 0 ? void 0 : _a.addEventListener(e, (event) => {
+ const target = event.target;
+ if (target.classList.contains("en__field__input--other")) {
+ this.logger.log("Other Amount Field Focused");
+ this.setRadioInput();
+ }
+ });
+ });
+ const otherAmountField = document.querySelector("[name='transaction.donationAmt.other'");
+ if (otherAmountField) {
+ otherAmountField.setAttribute("inputmode", "decimal");
+ // ADD THE MISSING LABEL FOR IMPROVED ACCESSABILITY
+ otherAmountField.setAttribute("aria-label", "Enter your custom donation amount");
+ otherAmountField.setAttribute("autocomplete", "off");
+ otherAmountField.setAttribute("data-lpignore", "true");
+ otherAmountField.addEventListener("change", (e) => {
+ const target = e.target;
+ const amount = target.value;
+ const cleanAmount = engrid_ENGrid.cleanAmount(amount);
+ if (amount !== cleanAmount.toString()) {
+ this.logger.log(`Other Amount Field Changed: ${amount} => ${cleanAmount}`);
+ if ("dataLayer" in window) {
+ window.dataLayer.push({
+ event: "otherAmountTransformed",
+ otherAmountTransformation: `${amount} => ${cleanAmount}`,
+ });
+ }
+ target.value =
+ cleanAmount % 1 != 0
+ ? cleanAmount.toFixed(2)
+ : cleanAmount.toString();
+ }
+ });
+ // On blur, if the amount is 0, select the previous amount
+ otherAmountField.addEventListener("blur", (e) => {
+ const target = e.target;
+ const amount = target.value;
+ const cleanAmount = engrid_ENGrid.cleanAmount(amount);
+ if (cleanAmount === 0) {
+ this.logger.log("Other Amount Field Blurred with 0 amount");
+ // Get Live Amount
+ const liveAmount = this._amount.amount;
+ if (liveAmount > 0) {
+ this._amount.setAmount(liveAmount, false);
+ }
+ }
+ });
}
- this.renderCheckbox();
- this.updateLiveData();
- this._frequency.onFrequencyChange.subscribe(() => this.updateLiveData());
- this._frequency.onFrequencyChange.subscribe(() => this.resetUpsellCheckbox());
- this._amount.onAmountChange.subscribe(() => this.updateLiveData());
- this._amount.onAmountChange.subscribe(() => this.resetUpsellCheckbox());
- this._fees.onFeeChange.subscribe(() => this.updateLiveData());
- }
- updateLiveData() {
- this.liveAmounts();
- this.liveFrequency();
}
- resetUpsellCheckbox() {
- var _a, _b;
- // Only reset the upsell checkbox if it has been checked
- if (!this.resetCheckbox)
- return;
- this.logger.log("Reset");
- // Uncheck the upsell checkbox
- const checkbox = (_a = this.checkboxContainer) === null || _a === void 0 ? void 0 : _a.querySelector("#upsellCheckbox");
- if (checkbox) {
- checkbox.checked = false;
+ setRadioInput() {
+ const target = document.querySelector(".en__field--donationAmt .en__field__input--other");
+ if (target && target.parentNode && target.parentNode.parentNode) {
+ const targetWrapper = target.parentNode;
+ targetWrapper.classList.remove("en__field__item--hidden");
+ if (targetWrapper.parentNode) {
+ const lastRadioInput = targetWrapper.parentNode.querySelector(".en__field__item:nth-last-child(2) input");
+ lastRadioInput.checked = !0;
+ }
}
- // Hide the upsell checkbox
- (_b = this.checkboxContainer) === null || _b === void 0 ? void 0 : _b.classList.add("recurring-frequency-y-hide");
- this.oldAmount = 0;
- this.oldFrequency = "one-time";
- this.resetCheckbox = false;
}
- renderCheckbox() {
- if (this.checkboxOptions === false)
- return;
- const label = this.checkboxOptions.label
- .replace("{new-amount}", " ")
- .replace("{old-amount}", " ")
- .replace("{old-frequency}", " ");
- const formBlock = document.createElement("div");
- formBlock.classList.add("en__component", "en__component--formblock", "recurring-frequency-y-hide", "engrid-upsell-checkbox");
- if (this.checkboxOptions.cssClass)
- formBlock.classList.add(this.checkboxOptions.cssClass);
- formBlock.innerHTML = `
- `;
- const checkbox = formBlock.querySelector("#upsellCheckbox");
- if (checkbox)
- checkbox.addEventListener("change", this.toggleCheck.bind(this));
- const position = this.checkboxOptions.location.split(" ")[0];
- // Location is everything after the first space
- const location = this.checkboxOptions.location
- .split(" ")
- .slice(1)
- .join(" ")
- .trim();
- const target = document.querySelector(location);
- this.checkboxContainer = formBlock;
- if (target) {
- if (position === "before") {
- this.logger.log("rendered before");
- target.before(formBlock);
- }
- else {
- this.logger.log("rendered after");
- target.after(formBlock);
- }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/logger.js
+
+/**
+ * A better logger. It only works if debug is enabled.
+ */
+class logger_EngridLogger {
+ constructor(prefix, color, background, emoji) {
+ this.prefix = "";
+ this.color = "black";
+ this.background = "white";
+ this.emoji = "";
+ if (emoji) {
+ this.emoji = emoji;
}
else {
- this.logger.error("could not render - target not found");
+ switch (color) {
+ case "red":
+ this.emoji = "π΄";
+ break;
+ case "green":
+ this.emoji = "π’";
+ break;
+ case "blue":
+ this.emoji = "π΅";
+ break;
+ case "yellow":
+ this.emoji = "π‘";
+ this.background = "black";
+ break;
+ case "purple":
+ this.emoji = "π£";
+ break;
+ case "black":
+ default:
+ this.emoji = "β«";
+ break;
+ }
}
- }
- // Should we run the script?
- shouldRun() {
- // if it's a first page of a Donation page
- return engrid_ENGrid.getPageNumber() === 1 && engrid_ENGrid.getPageType() === "DONATION";
- }
- showCheckbox() {
- if (this.checkboxContainer)
- this.checkboxContainer.classList.remove("hide");
- }
- hideCheckbox() {
- if (this.checkboxContainer)
- this.checkboxContainer.classList.add("hide");
- }
- liveAmounts() {
- // Only update live data if the current frequency is one-time
- if (this._frequency.frequency !== "onetime")
- return;
- const live_upsell_amount = document.querySelectorAll(".upsell_suggestion");
- const live_amount = document.querySelectorAll(".upsell_amount");
- const upsellAmount = this.getUpsellAmount();
- const suggestedAmount = upsellAmount + this._fees.calculateFees(upsellAmount);
- if (suggestedAmount > 0) {
- this.showCheckbox();
+ if (prefix) {
+ this.prefix = `[ENgrid ${prefix}]`;
}
- else {
- this.hideCheckbox();
+ if (color) {
+ this.color = color;
+ }
+ if (background) {
+ this.background = background;
}
- live_upsell_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(suggestedAmount)));
- live_amount.forEach((elem) => (elem.innerHTML = this.getAmountTxt(this._amount.amount + this._fees.fee)));
- }
- liveFrequency() {
- const live_upsell_frequency = document.querySelectorAll(".upsell_frequency");
- live_upsell_frequency.forEach((elem) => (elem.innerHTML = this.getFrequencyTxt()));
}
- // Return the Suggested Upsell Amount
- getUpsellAmount() {
- const amount = this._amount.amount;
- let upsellAmount = 0;
- for (let i = 0; i < this.options.amountRange.length; i++) {
- let val = this.options.amountRange[i];
- if (upsellAmount == 0 && amount <= val.max) {
- upsellAmount = val.suggestion;
- if (upsellAmount === 0)
- return 0;
- if (typeof upsellAmount !== "number") {
- const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
- upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
- }
- break;
- }
+ get log() {
+ if (!engrid_ENGrid.debug && engrid_ENGrid.getUrlParameter("debug") !== "log") {
+ return () => { };
}
- return upsellAmount > this.options.minAmount
- ? upsellAmount
- : this.options.minAmount;
+ return console.log.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
}
- // Proceed to the next page (upsold or not)
- toggleCheck(e) {
- var _a, _b;
- e.preventDefault();
- if (e.target.checked) {
- this.logger.success("Upsold");
- const upsoldAmount = this.getUpsellAmount();
- const originalAmount = this._amount.amount;
- this.oldAmount = originalAmount;
- this.oldFrequency = this._frequency.frequency;
- // If we're checking the upsell checkbox, remove the class that hides it on different frequencies
- (_a = this.checkboxContainer) === null || _a === void 0 ? void 0 : _a.classList.remove("recurring-frequency-y-hide");
- this._frequency.setFrequency("monthly");
- this._amount.setAmount(upsoldAmount);
- this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL_CHECKBOX", {
- eventValue: true,
- originalAmount: originalAmount,
- upsoldAmount: upsoldAmount,
- frequency: "monthly",
- });
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX", true);
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT", originalAmount);
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "MONTHLY");
- this.renderConversionField("upsellSuccess", "onetime", originalAmount, "monthly", upsoldAmount, "monthly", upsoldAmount);
- // Set the resetCheckbox flag to true so it will reset if the user changes the amount or frequency
- window.setTimeout(() => {
- this.resetCheckbox = true;
- }, 500);
+ get success() {
+ if (!engrid_ENGrid.debug) {
+ return () => { };
}
- else {
- this.resetCheckbox = false;
- this.logger.success("Not Upsold");
- this._amount.setAmount(this.oldAmount);
- this._frequency.setFrequency(this.oldFrequency);
- (_b = this.checkboxContainer) === null || _b === void 0 ? void 0 : _b.classList.add("recurring-frequency-y-hide");
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX", false);
- this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "ONE-TIME");
- this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._amount.amount, this._frequency.frequency, this._amount.amount);
+ return console.log.bind(window.console, "%c β
" + this.prefix + " %s", `color: green; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+ get danger() {
+ if (!engrid_ENGrid.debug) {
+ return () => { };
}
+ return console.log.bind(window.console, "%c βοΈ " + this.prefix + " %s", `color: red; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
}
- getAmountTxt(amount = 0) {
- var _a, _b, _c, _d;
- const symbol = (_a = engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
- const dec_separator = (_b = engrid_ENGrid.getOption("DecimalSeparator")) !== null && _b !== void 0 ? _b : ".";
- const thousands_separator = (_c = engrid_ENGrid.getOption("ThousandsSeparator")) !== null && _c !== void 0 ? _c : "";
- const dec_places = amount % 1 == 0 ? 0 : (_d = engrid_ENGrid.getOption("DecimalPlaces")) !== null && _d !== void 0 ? _d : 2;
- const amountTxt = engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
- return amount > 0 ? symbol + amountTxt : "";
+ get warn() {
+ if (!engrid_ENGrid.debug) {
+ return () => { };
+ }
+ return console.warn.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
}
- getFrequencyTxt() {
- const freqTxt = {
- onetime: "one-time",
- monthly: "monthly",
- annual: "annual",
- };
- const frequency = this._frequency.frequency;
- return frequency in freqTxt ? freqTxt[frequency] : frequency;
+ get dir() {
+ if (!engrid_ENGrid.debug) {
+ return () => { };
+ }
+ return console.dir.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
}
- renderConversionField(event, // The event that triggered the conversion
- freq, // The frequency of the donation (onetime, monthly, annual)
- amt, // The original amount of the donation (before the upsell)
- sugFreq, // The suggested frequency of the upsell (monthly)
- sugAmt, // The suggested amount of the upsell
- subFreq, // The submitted frequency of the upsell (onetime, monthly, annual)
- subAmt // The submitted amount of the upsell
- ) {
- if (this.options.conversionField === "")
- return;
- const conversionField = document.querySelector("input[name='" + this.options.conversionField + "']") ||
- engrid_ENGrid.createHiddenInput(this.options.conversionField);
- if (!conversionField) {
- this.logger.error("Could not find or create the conversion field");
- return;
+ get error() {
+ if (!engrid_ENGrid.debug) {
+ return () => { };
}
- const conversionValue = `event:${event},freq:${freq},amt:${amt},sugFreq:${sugFreq},sugAmt:${sugAmt},subFreq:${subFreq},subAmt:${subAmt}`;
- conversionField.value = conversionValue;
- this.logger.log(`Conversion Field ${event}`, conversionValue);
+ return console.error.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/show-hide-radio-checkboxes.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/min-max-amount.js
+// This script adds an erros message to the page if the amount is greater than the max amount or less than the min amount.
-class ShowHideRadioCheckboxes {
- // Create default data attributes on all fields
- createDataAttributes() {
- this.elements.forEach((item) => {
- if (item instanceof HTMLInputElement) {
- let inputValue = item.value.replace(/\W/g, "");
- document
- .querySelectorAll("." + this.classes + inputValue)
- .forEach((el) => {
- // Consider toggling "hide" class so these fields can be displayed when in a debug state
- if (el instanceof HTMLElement) {
- const fields = el.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");
- if (fields.length > 0) {
- fields.forEach((field) => {
- if (field instanceof HTMLInputElement ||
- field instanceof HTMLSelectElement) {
- if (!field.hasAttribute("data-original-value")) {
- field.setAttribute("data-original-value", field.value);
- }
- if (!field.hasAttribute("data-value")) {
- field.setAttribute("data-value", field.value);
- }
- }
- });
- }
- }
- });
- }
- });
- }
- // Hide All Divs
- hideAll() {
- this.elements.forEach((item, index) => {
- if (item instanceof HTMLInputElement)
- this.hide(item);
- });
+class MinMaxAmount {
+ constructor() {
+ var _a, _b;
+ this._form = en_form_EnForm.getInstance();
+ this._amount = DonationAmount.getInstance();
+ this._frequency = DonationFrequency.getInstance();
+ this.minAmount = (_a = engrid_ENGrid.getOption("MinAmount")) !== null && _a !== void 0 ? _a : 1;
+ this.maxAmount = (_b = engrid_ENGrid.getOption("MaxAmount")) !== null && _b !== void 0 ? _b : 100000;
+ this.minAmountMessage = engrid_ENGrid.getOption("MinAmountMessage");
+ this.maxAmountMessage = engrid_ENGrid.getOption("MaxAmountMessage");
+ this.enAmountValidator = null;
+ this.logger = new logger_EngridLogger("MinMaxAmount", "white", "purple", "π’");
+ if (!this.shouldRun()) {
+ // If we're not on a Donation Page, get out
+ return;
+ }
+ this.setValidationConfigFromEN();
+ this._amount.onAmountChange.subscribe((s) => window.setTimeout(this.liveValidate.bind(this), 1000) // Wait 1 second for the amount to be updated
+ );
+ this._form.onValidate.subscribe(this.enOnValidate.bind(this));
}
- // Hide Single Element Div
- hide(item) {
- let inputValue = item.value.replace(/\W/g, "");
- document.querySelectorAll("." + this.classes + inputValue).forEach((el) => {
- // Consider toggling "hide" class so these fields can be displayed when in a debug state
- if (el instanceof HTMLElement) {
- this.toggleValue(el, "hide");
- el.style.display = "none";
- this.logger.log("Hiding", el);
- const input = el.querySelector("input");
- if (input instanceof HTMLInputElement) {
- input.setAttribute("aria-required", "false");
- this.logger.log("aria-required set to FALSE", input);
- }
- }
- });
+ // Should we run the script?
+ shouldRun() {
+ return engrid_ENGrid.getPageType() === "DONATION";
}
- // Show Single Element Div
- show(item) {
- let inputValue = item.value.replace(/\W/g, "");
- document.querySelectorAll("." + this.classes + inputValue).forEach((el) => {
- // Consider toggling "hide" class so these fields can be displayed when in a debug state
- if (el instanceof HTMLElement) {
- this.toggleValue(el, "show");
- el.style.display = "";
- this.logger.log("Showing", el);
- const input = el.querySelector("input");
- if (input instanceof HTMLInputElement) {
- input.setAttribute("aria-required", "true");
- this.logger.log("aria-required set to TRUE", input);
- }
+ // Don't submit the form if the amount is not valid
+ enOnValidate() {
+ if (!this._form.validate)
+ return;
+ const otherAmount = document.querySelector("[name='transaction.donationAmt.other']");
+ if (this._amount.amount < this.minAmount) {
+ this.logger.log("Amount is less than min amount: " + this.minAmount);
+ if (otherAmount) {
+ otherAmount.focus();
}
- });
- if (item.type == "checkbox" && !item.checked) {
- this.hide(item);
+ this._form.validate = false;
+ }
+ else if (this._amount.amount > this.maxAmount) {
+ this.logger.log("Amount is greater than max amount: " + this.maxAmount);
+ if (otherAmount) {
+ otherAmount.focus();
+ }
+ this._form.validate = false;
}
+ window.setTimeout(this.liveValidate.bind(this), 300);
}
- // Take the field values and add to a data attribute on the field
- toggleValue(item, type) {
- if (type == "hide" && !engrid_ENGrid.isVisible(item))
+ // Disable Submit Button if the amount is not valid
+ liveValidate() {
+ const amount = engrid_ENGrid.cleanAmount(this._amount.amount.toString());
+ const activeElement = document.activeElement;
+ if (activeElement &&
+ activeElement.tagName === "INPUT" &&
+ "name" in activeElement &&
+ activeElement.name === "transaction.donationAmt.other" &&
+ amount === 0) {
+ // Don't validate if the other amount has focus and the amount is 0
return;
- this.logger.log(`toggleValue: ${type}`);
- const fields = item.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");
- if (fields.length > 0) {
- fields.forEach((field) => {
- var _a;
- if (field instanceof HTMLInputElement ||
- field instanceof HTMLSelectElement) {
- if (field.name) {
- const fieldValue = engrid_ENGrid.getFieldValue(field.name);
- const originalValue = field.getAttribute("data-original-value");
- const dataValue = (_a = field.getAttribute("data-value")) !== null && _a !== void 0 ? _a : "";
- if (type === "hide") {
- field.setAttribute("data-value", fieldValue);
- engrid_ENGrid.setFieldValue(field.name, originalValue);
- }
- else {
- engrid_ENGrid.setFieldValue(field.name, dataValue);
- }
- }
- }
- });
}
- }
- getSessionState() {
- var _a;
- try {
- const plainState = (_a = window.sessionStorage.getItem(`engrid_ShowHideRadioCheckboxesState`)) !== null && _a !== void 0 ? _a : "";
- return JSON.parse(plainState);
+ this.logger.log(`Amount: ${amount}`);
+ if (amount < this.minAmount) {
+ this.logger.log("Amount is less than min amount: " + this.minAmount);
+ engrid_ENGrid.setError(".en__field--withOther", this.minAmountMessage || "Invalid Amount");
}
- catch (err) {
- return [];
+ else if (amount > this.maxAmount) {
+ this.logger.log("Amount is greater than max amount: " + this.maxAmount);
+ engrid_ENGrid.setError(".en__field--withOther", this.maxAmountMessage || "Invalid Amount");
+ }
+ else {
+ engrid_ENGrid.removeError(".en__field--withOther");
}
}
- storeSessionState() {
- const state = this.getSessionState();
- [...this.elements].forEach((element) => {
- var _a, _b;
- if (!(element instanceof HTMLInputElement))
- return;
- if (element.type == "radio" && element.checked) {
- //remove other items that have the same "class" property
- state.forEach((item, index) => {
- if (item.class == this.classes) {
- state.splice(index, 1);
- }
- });
- //add the current item, with the currently active value
- state.push({
- page: engrid_ENGrid.getPageID(),
- class: this.classes,
- value: element.value,
- });
- this.logger.log("storing radio state", state[state.length - 1]);
- }
- if (element.type == "checkbox") {
- //remove other items that have the same "class" property
- state.forEach((item, index) => {
- if (item.class == this.classes) {
- state.splice(index, 1);
- }
- });
- //add the current item, with the first checked value or "N" if none are checked
- state.push({
- page: engrid_ENGrid.getPageID(),
- class: this.classes,
- value: (_b = (_a = [...this.elements].find((el) => el.checked)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "N", // First checked value or "N" if none
- });
- this.logger.log("storing checkbox state", state[state.length - 1]);
- }
+ setValidationConfigFromEN() {
+ if (!engrid_ENGrid.getOption("UseAmountValidatorFromEN") ||
+ !window.EngagingNetworks.validators) {
+ this.logger.log("Not setting validation config from EN.");
+ return;
+ }
+ // Find the amount validator for the donation amount field
+ // It should be of type "AMNT" or "FAMNT" and have
+ // a componentId that matches the donation amount field.
+ this.enAmountValidator = window.EngagingNetworks.validators.find((validator) => {
+ var _a;
+ return ((validator.type === "FAMNT" || validator.type === "AMNT") &&
+ ((_a = document
+ .querySelector(".en__field--" + validator.componentId)) === null || _a === void 0 ? void 0 : _a.classList.contains("en__field--donationAmt")));
});
- window.sessionStorage.setItem(`engrid_ShowHideRadioCheckboxesState`, JSON.stringify(state));
- }
- constructor(elements, classes) {
- this.logger = new logger_EngridLogger("ShowHideRadioCheckboxes", "black", "lightblue", "π");
- this.elements = document.getElementsByName(elements);
- this.classes = classes;
- this.createDataAttributes();
- this.hideAll();
- this.storeSessionState();
- for (let i = 0; i < this.elements.length; i++) {
- let element = this.elements[i];
- if (element.checked) {
- this.show(element);
- }
- element.addEventListener("change", (e) => {
- this.hideAll();
- this.show(element);
- this.storeSessionState();
+ if (!this.enAmountValidator || !this.enAmountValidator.format) {
+ return;
+ }
+ this.logger.log(`Detected an amount validator for donation amount on the page:`, this.enAmountValidator);
+ // Static amount validator
+ if (this.enAmountValidator.type === "AMNT") {
+ this.minAmount = Number(this.enAmountValidator.format.split("~")[0]);
+ this.maxAmount = Number(this.enAmountValidator.format.split("~")[1]);
+ this.minAmountMessage = this.enAmountValidator.errorMessage;
+ this.maxAmountMessage = this.enAmountValidator.errorMessage;
+ this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`);
+ }
+ // Frequency-based amount validator
+ if (this.enAmountValidator.type === "FAMNT") {
+ this._frequency.onFrequencyChange.subscribe((freq) => {
+ if (!this.enAmountValidator || !this.enAmountValidator.format)
+ return;
+ // In the validator, "onetime" is written as "SINGLE"
+ // Validator format for FAMNT is like SINGLE:10~100000|MONTHLY:5~100000|QUARTERLY:25~100000|ANNUAL:25~100000
+ const frequency = freq === "onetime" ? "SINGLE" : freq.toUpperCase();
+ const validationRange = this.enAmountValidator.format
+ .split("|")
+ .find((range) => range.startsWith(frequency));
+ if (!validationRange) {
+ this.logger.log(`No validation range found for frequency: ${frequency}`);
+ return;
+ }
+ const amounts = validationRange.split(":")[1].split("~");
+ this.minAmount = Number(amounts[0]);
+ this.maxAmount = Number(amounts[1]);
+ this.minAmountMessage = this.enAmountValidator.errorMessage;
+ this.maxAmountMessage = this.enAmountValidator.errorMessage;
+ this.logger.log(`Frequency changed to ${frequency}, updating min and max amounts`, validationRange);
+ this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`);
});
}
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/cookie.js
-/**
-Example:
-import * as cookie from "./cookie";
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/ticker.js
-cookie.set('name', 'value');
-cookie.get('name'); // => 'value'
-cookie.remove('name');
-cookie.set('name', 'value', { expires: 7 }); // 7 Days cookie
-cookie.set('name', 'value', { expires: 7, path: '' }); // Set Path
-cookie.remove('name', { path: '' });
- */
-function stringifyAttribute(name, value) {
- if (!value) {
- return "";
+class Ticker {
+ constructor() {
+ this.shuffleSeed = __webpack_require__(3184);
+ this.items = [];
+ this.tickerElement = document.querySelector(".engrid-ticker");
+ this.logger = new logger_EngridLogger("Ticker", "black", "beige", "π");
+ if (!this.shouldRun()) {
+ this.logger.log("Not running");
+ // If we don't find a ticker, get out
+ return;
+ }
+ const tickerList = document.querySelectorAll(".engrid-ticker li");
+ if (tickerList.length > 0) {
+ for (let i = 0; i < tickerList.length; i++) {
+ this.items.push(tickerList[i].innerText);
+ }
+ }
+ this.render();
+ return;
}
- let stringified = "; " + name;
- if (value === true) {
- return stringified; // boolean attributes shouldn't have a value
+ // Should we run the script?
+ shouldRun() {
+ return this.tickerElement !== null;
}
- return stringified + "=" + value;
-}
-function stringifyAttributes(attributes) {
- if (typeof attributes.expires === "number") {
- let expires = new Date();
- expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e5);
- attributes.expires = expires;
+ getSeed() {
+ return new Date().getDate() + engrid_ENGrid.getPageID();
}
- return (stringifyAttribute("Expires", attributes.expires ? attributes.expires.toUTCString() : "") +
- stringifyAttribute("Domain", attributes.domain) +
- stringifyAttribute("Path", attributes.path) +
- stringifyAttribute("Secure", attributes.secure) +
- stringifyAttribute("SameSite", attributes.sameSite));
-}
-function encode(name, value, attributes) {
- return (encodeURIComponent(name)
- .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent) // allowed special characters
- .replace(/\(/g, "%28")
- .replace(/\)/g, "%29") + // replace opening and closing parens
- "=" +
- encodeURIComponent(value)
- // allowed special characters
- .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent) +
- stringifyAttributes(attributes));
-}
-function parse(cookieString) {
- let result = {};
- let cookies = cookieString ? cookieString.split("; ") : [];
- let rdecode = /(%[\dA-F]{2})+/gi;
- for (let i = 0; i < cookies.length; i++) {
- let parts = cookies[i].split("=");
- let cookie = parts.slice(1).join("=");
- if (cookie.charAt(0) === '"') {
- cookie = cookie.slice(1, -1);
- }
- try {
- let name = parts[0].replace(rdecode, decodeURIComponent);
- result[name] = cookie.replace(rdecode, decodeURIComponent);
+ // Get Items
+ getItems() {
+ const total = this.tickerElement.getAttribute("data-total") || "50";
+ this.logger.log("Getting " + total + " items");
+ const seed = this.getSeed();
+ const items = this.shuffleSeed.shuffle(this.items, seed);
+ const now = new Date();
+ const hour = now.getHours();
+ const minute = now.getMinutes();
+ let pointer = Math.round((hour * 60 + minute) / 5);
+ if (pointer >= items.length) {
+ pointer = 0;
}
- catch (e) {
- // ignore cookies with invalid name/value encoding
+ const ret = items.slice(pointer, pointer + total).reverse();
+ return ret;
+ }
+ // Render
+ render() {
+ var _a, _b, _c;
+ this.logger.log("Rendering");
+ const items = this.getItems();
+ let ticker = document.createElement("div");
+ ticker.classList.add("en__component");
+ ticker.classList.add("en__component--ticker");
+ let str = ``;
+ for (let i = 0; i < items.length; i++) {
+ str += '
' + items[i] + "
";
}
+ str = '
' + str + "
";
+ ticker.innerHTML = str;
+ (_b = (_a = this.tickerElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(ticker, this.tickerElement);
+ (_c = this.tickerElement) === null || _c === void 0 ? void 0 : _c.remove();
+ const tickerWidth = document.querySelector(".ticker").offsetWidth.toString();
+ ticker.style.setProperty("--ticker-size", tickerWidth);
+ this.logger.log("Ticker Size: " + ticker.style.getPropertyValue("--ticker-size"));
+ this.logger.log("Ticker Width: " + tickerWidth);
}
- return result;
-}
-function getAll() {
- return parse(document.cookie);
-}
-function get(name) {
- return getAll()[name];
-}
-function set(name, value, attributes) {
- document.cookie = encode(name, value, Object.assign({ path: "/" }, attributes));
-}
-function remove(name, attributes) {
- set(name, "", Object.assign(Object.assign({}, attributes), { expires: -1 }));
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/translate-fields.js
-// Component to translate fields based on the country selected
-// It will also adapt the state field to the country selected
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-layer.js
+// DataLayer: singleton helper for pushing structured analytics events/vars to window.dataLayer.
+// On load it emits one aggregated event `pageJsonVariablesReady` with:
+// EN_PAGEJSON_* (normalized pageJson), EN_URLPARAM_*, EN_RECURRING_FREQUENCIES (donation pages),
+// and EN_SUBMISSION_SUCCESS_{PAGETYPE} when on the final page.
+// User actions emit: EN_FORM_VALUE_UPDATED (field changes) and submission optβin/out events.
+// Queued endβofβgift events/variables (via addEndOfGiftProcessEvent / addEndOfGiftProcessVariable)
+// are replayed after a successful gift process load.
+// Sensitive payment/bank fields are excluded; selected PII fields are Base64 βhashedβ (btoa β not cryptographic).
+// Replace with a real hash (e.g., SHAβ256) if required.
+var data_layer_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
-class TranslateFields {
+class DataLayer {
constructor() {
- this.countryToStateFields = {
- "supporter.country": "supporter.region",
- "transaction.shipcountry": "transaction.shipregion",
- "supporter.billingCountry": "supporter.billingRegion",
- "transaction.infcountry": "transaction.infreg",
- };
- this.countriesSelect = document.querySelectorAll('select[name="supporter.country"], select[name="transaction.shipcountry"], select[name="supporter.billingCountry"], select[name="transaction.infcountry"]');
- let options = "EngridTranslate" in window ? window.EngridTranslate : {};
- this.options = TranslateOptionsDefaults;
- // Don't run this for US-only forms.
- if (document.querySelector(".en__component--formblock.us-only-form .en__field--country")) {
- return;
+ this.logger = new logger_EngridLogger("DataLayer", "#f1e5bc", "#009cdc", "π");
+ this.dataLayer = window.dataLayer || [];
+ this._form = en_form_EnForm.getInstance();
+ this.encoder = new TextEncoder();
+ this.endOfGiftProcessStorageKey = "ENGRID_END_OF_GIFT_PROCESS_EVENTS";
+ // pageJson entries related to the gift process
+ this.giftFields = [
+ "amount",
+ "currency",
+ "donationLogId",
+ "feeCover",
+ "giftProcess",
+ "paymentType",
+ "receiptNumber",
+ "recurring",
+ "transactionId",
+ "transactionType",
+ ];
+ this.excludedFields = [
+ // Credit Card
+ "transaction.ccnumber",
+ "transaction.ccexpire.delimiter",
+ "transaction.ccexpire",
+ "transaction.ccvv",
+ "supporter.creditCardHolderName",
+ // Bank Account
+ "supporter.bankAccountNumber",
+ "supporter.bankAccountType",
+ "transaction.bankname",
+ "supporter.bankRoutingNumber",
+ ];
+ this.hashedFields = [
+ // Supporter Address, Phone Numbers, and Address
+ "supporter.emailAddress",
+ "supporter.phoneNumber",
+ "supporter.phoneNumber2",
+ "supporter.address1",
+ "supporter.address2",
+ "supporter.address3",
+ // In Honor/Memory Inform Email and Address
+ "transaction.infemail",
+ "transaction.infadd1",
+ "transaction.infadd2",
+ "transaction.infadd3",
+ // Billing Address
+ "supporter.billingAddress1",
+ "supporter.billingAddress2",
+ "supporter.billingAddress3",
+ ];
+ this.retainedEmailField = "supporter.emailAddress";
+ this.retainedAddressFields = [
+ "supporter.address1",
+ "supporter.address2",
+ "supporter.address3",
+ ];
+ this.retainedPhoneFields = [
+ "supporter.phoneNumber2",
+ "supporter.phoneNumber",
+ ];
+ if (engrid_ENGrid.getOption("RememberMe")) {
+ RememberMeEvents.getInstance().onLoad.subscribe((hasData) => {
+ this.logger.log("Remember me - onLoad", hasData);
+ this.onLoad();
+ });
}
- if (options) {
- for (let key in options) {
- this.options[key] = this.options[key]
- ? [...this.options[key], ...options[key]]
- : options[key];
- }
+ else {
+ this.onLoad();
}
- //Storing these values on load so we can set them back after the translation/swap.
- let countryAndStateValuesOnLoad = {};
- if (this.countriesSelect && this.countriesSelect.length > 0) {
- this.countriesSelect.forEach((select) => {
- select.addEventListener("change", this.translateFields.bind(this, select.name));
- if (select.value) {
- countryAndStateValuesOnLoad[select.name] = select.value;
- }
- const stateField = document.querySelector(`select[name="${this.countryToStateFields[select.name]}"]`);
- if (stateField) {
- stateField.addEventListener("change", this.rememberState.bind(this, select.name));
- if (stateField.value) {
- countryAndStateValuesOnLoad[stateField.name] = stateField.value;
- }
- }
- });
- this.translateFields("supporter.country");
- //dont set these back if submission failed. EN / cookie will handle it.
- const submissionFailed = !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
- window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
- if (!submissionFailed) {
- for (let field in countryAndStateValuesOnLoad) {
- engrid_ENGrid.setFieldValue(field, countryAndStateValuesOnLoad[field], false);
- }
- }
+ this._form.onSubmit.subscribe(() => this.onSubmit());
+ }
+ static getInstance() {
+ if (!DataLayer.instance) {
+ DataLayer.instance = new DataLayer();
+ window._dataLayer = DataLayer.instance;
}
+ return DataLayer.instance;
}
- translateFields(countryName = "supporter.country") {
- this.resetTranslatedFields();
- const countryValue = engrid_ENGrid.getFieldValue(countryName);
- // Translate the State Field
- this.setStateField(countryValue, this.countryToStateFields[countryName]);
- if (countryName === "supporter.country") {
- if (countryValue in this.options) {
- this.options[countryValue].forEach((field) => {
- // console.log(field);
- this.translateField(field.field, field.translation);
- });
+ transformJSON(value) {
+ if (typeof value === "string") {
+ return value
+ .toUpperCase()
+ .trim()
+ .replace(/\s+/g, "-")
+ .replace(/:-/g, "-");
+ }
+ if (typeof value === "boolean") {
+ return value ? "TRUE" : "FALSE";
+ }
+ if (typeof value === "number") {
+ return value; // Preserve numeric type for analytics platforms that infer number vs string
+ }
+ return "";
+ }
+ onLoad() {
+ // Collect all data layer variables to push at once
+ const dataLayerData = {};
+ const suppressEcardData = engrid_ENGrid.getPageType() === "ECARD" &&
+ engrid_ENGrid.getOption("SuppressPurchaseEcard");
+ if (engrid_ENGrid.getGiftProcess()) {
+ // EN will chain together gift process data on the page json when redirecting from a completed donation to an ecard.
+ // Since the ecard page can be embedded on the thank you page of a donation, this can cause confusion in the data layer with events
+ // firing for both the donation and the ecard on the same page.
+ if (suppressEcardData) {
+ this.logger.log("β Gift process was detected BUT suppressing EN_SUCCESSFUL_DONATION event due to SuppressPurchaseEcard option enabled");
+ window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
}
- // Translate the "To:"
- const recipient_block = document.querySelectorAll(".recipient-block");
- if (!!recipient_block.length) {
- switch (countryValue) {
- case "FR":
- case "FRA":
- case "France":
- recipient_block.forEach((elem) => (elem.innerHTML = "Γ:"));
- break;
- case "DE":
- case "DEU":
- case "Germany":
- recipient_block.forEach((elem) => (elem.innerHTML = "Zu:"));
- break;
- case "NL":
- case "NLD":
- case "Netherlands":
- recipient_block.forEach((elem) => (elem.innerHTML = "Aan:"));
- break;
- }
+ else {
+ this.logger.log("EN_SUCCESSFUL_DONATION");
+ this.addEndOfGiftProcessEventsToDataLayer();
}
}
- }
- translateField(name, translation) {
- const field = document.querySelector(`[name="${name}"]`);
- if (field) {
- const fieldWrapper = field.closest(".en__field");
- if (fieldWrapper) {
- const fieldLabel = fieldWrapper.querySelector(".en__field__label");
- // Check if there's the simple country select class
- const simplecountriesSelect = fieldLabel.querySelector(".engrid-simple-country");
- let simplecountriesSelectClone = simplecountriesSelect
- ? simplecountriesSelect.cloneNode(true)
- : null;
- if (field instanceof HTMLInputElement && field.placeholder != "") {
- if (!fieldLabel || fieldLabel.innerHTML == field.placeholder) {
- field.dataset.original = field.placeholder;
- field.placeholder = translation;
- }
- }
- if (fieldLabel) {
- fieldLabel.dataset.original = fieldLabel.innerHTML;
- fieldLabel.innerHTML = translation;
- if (simplecountriesSelectClone) {
- fieldLabel.appendChild(simplecountriesSelectClone);
- }
+ if (window.pageJson) {
+ const pageJson = window.pageJson;
+ for (const property in pageJson) {
+ if (suppressEcardData && this.giftFields.includes(property)) {
+ continue;
}
+ const key = `EN_PAGEJSON_${property.toUpperCase()}`;
+ const value = pageJson[property];
+ dataLayerData[key] = this.transformJSON(value);
}
+ if (engrid_ENGrid.getPageCount() === engrid_ENGrid.getPageNumber()) {
+ dataLayerData[`EN_SUBMISSION_SUCCESS_${pageJson.pageType.toUpperCase()}`] = "TRUE";
+ }
+ }
+ const urlParams = new URLSearchParams(window.location.search);
+ urlParams.forEach((value, key) => {
+ dataLayerData[`EN_URLPARAM_${key.toUpperCase()}`] =
+ this.transformJSON(value);
+ });
+ this.addRetainedHashesToDataLayer(dataLayerData);
+ if (engrid_ENGrid.getPageType() === "DONATION") {
+ const recurrFreqEls = document.querySelectorAll('[name="transaction.recurrfreq"]');
+ const recurrValues = [...recurrFreqEls].map((el) => el.value);
+ dataLayerData[`EN_RECURRING_FREQUENCIES`] = recurrValues;
+ }
+ // Push all collected variables at once
+ if (Object.keys(dataLayerData).length > 0) {
+ dataLayerData.event = "pageJsonVariablesReady";
+ this.dataLayer.push(dataLayerData);
}
+ this.attachEventListeners();
}
- resetTranslatedFields() {
- const fields = document.querySelectorAll("[data-original]");
- fields.forEach((field) => {
- if (field instanceof HTMLInputElement && field.dataset.original) {
- field.placeholder = field.dataset.original;
- }
- else {
- // Check if there's the simple country select class
- const simplecountriesSelect = field.querySelector(".engrid-simple-country");
- let simplecountriesSelectClone = simplecountriesSelect
- ? simplecountriesSelect.cloneNode(true)
- : null;
- field.innerHTML = field.dataset.original;
- if (simplecountriesSelectClone) {
- field.appendChild(simplecountriesSelectClone);
- }
+ addRetainedHashesToDataLayer(dataLayerData) {
+ if (typeof window === "undefined" || !window.localStorage) {
+ return;
+ }
+ ["EMAIL", "ADDRESS", "PHONE"].forEach((suffix) => {
+ const storageKey = `EN_HASH_${suffix}`;
+ const storedValue = window.localStorage.getItem(storageKey);
+ if (storedValue) {
+ dataLayerData[storageKey] = storedValue;
}
- field.removeAttribute("data-original");
});
}
- setStateField(country, state) {
- switch (country) {
- case "ES":
- case "ESP":
- case "Spain":
- this.setStateValues(state, "Provincia", null);
- break;
- case "BR":
- case "BRA":
- case "Brazil":
- this.setStateValues(state, "Estado", null);
- break;
- case "FR":
- case "FRA":
- case "France":
- this.setStateValues(state, "RΓ©gion", null);
- break;
- case "GB":
- case "GBR":
- case "United Kingdom":
- this.setStateValues(state, "State/Region", null);
- break;
- case "DE":
- case "DEU":
- case "Germany":
- this.setStateValues(state, "Bundesland", null);
- break;
- case "NL":
- case "NLD":
- case "Netherlands":
- this.setStateValues(state, "Provincie", null);
- break;
- case "AU":
- case "AUS":
- this.setStateValues(state, "Province / State", [
- { label: "Select", value: "" },
- { label: "New South Wales", value: "NSW" },
- { label: "Victoria", value: "VIC" },
- { label: "Queensland", value: "QLD" },
- { label: "South Australia", value: "SA" },
- { label: "Western Australia", value: "WA" },
- { label: "Tasmania", value: "TAS" },
- { label: "Northern Territory", value: "NT" },
- { label: "Australian Capital Territory", value: "ACT" },
- ]);
- break;
- case "Australia":
- this.setStateValues(state, "Province / State", [
- { label: "Select", value: "" },
- { label: "New South Wales", value: "New South Wales" },
- { label: "Victoria", value: "Victoria" },
- { label: "Queensland", value: "Queensland" },
- { label: "South Australia", value: "South Australia" },
- { label: "Western Australia", value: "Western Australia" },
- { label: "Tasmania", value: "Tasmania" },
- { label: "Northern Territory", value: "Northern Territory" },
- {
- label: "Australian Capital Territory",
- value: "Australian Capital Territory",
- },
- ]);
- break;
- case "US":
- case "USA":
- this.setStateValues(state, "State", [
- { label: "Select State", value: "" },
- { label: "Alabama", value: "AL" },
- { label: "Alaska", value: "AK" },
- { label: "Arizona", value: "AZ" },
- { label: "Arkansas", value: "AR" },
- { label: "California", value: "CA" },
- { label: "Colorado", value: "CO" },
- { label: "Connecticut", value: "CT" },
- { label: "Delaware", value: "DE" },
- { label: "District of Columbia", value: "DC" },
- { label: "Florida", value: "FL" },
- { label: "Georgia", value: "GA" },
- { label: "Hawaii", value: "HI" },
- { label: "Idaho", value: "ID" },
- { label: "Illinois", value: "IL" },
- { label: "Indiana", value: "IN" },
- { label: "Iowa", value: "IA" },
- { label: "Kansas", value: "KS" },
- { label: "Kentucky", value: "KY" },
- { label: "Louisiana", value: "LA" },
- { label: "Maine", value: "ME" },
- { label: "Maryland", value: "MD" },
- { label: "Massachusetts", value: "MA" },
- { label: "Michigan", value: "MI" },
- { label: "Minnesota", value: "MN" },
- { label: "Mississippi", value: "MS" },
- { label: "Missouri", value: "MO" },
- { label: "Montana", value: "MT" },
- { label: "Nebraska", value: "NE" },
- { label: "Nevada", value: "NV" },
- { label: "New Hampshire", value: "NH" },
- { label: "New Jersey", value: "NJ" },
- { label: "New Mexico", value: "NM" },
- { label: "New York", value: "NY" },
- { label: "North Carolina", value: "NC" },
- { label: "North Dakota", value: "ND" },
- { label: "Ohio", value: "OH" },
- { label: "Oklahoma", value: "OK" },
- { label: "Oregon", value: "OR" },
- { label: "Pennsylvania", value: "PA" },
- { label: "Rhode Island", value: "RI" },
- { label: "South Carolina", value: "SC" },
- { label: "South Dakota", value: "SD" },
- { label: "Tennessee", value: "TN" },
- { label: "Texas", value: "TX" },
- { label: "Utah", value: "UT" },
- { label: "Vermont", value: "VT" },
- { label: "Virginia", value: "VA" },
- { label: "Washington", value: "WA" },
- { label: "West Virginia", value: "WV" },
- { label: "Wisconsin", value: "WI" },
- { label: "Wyoming", value: "WY" },
- {
- label: "── US Territories ──",
- value: "",
- disabled: true,
- },
- { label: "American Samoa", value: "AS" },
- { label: "Guam", value: "GU" },
- { label: "Northern Mariana Islands", value: "MP" },
- { label: "Puerto Rico", value: "PR" },
- { label: "US Minor Outlying Islands", value: "UM" },
- { label: "Virgin Islands", value: "VI" },
- {
- label: "── Armed Forces ──",
- value: "",
- disabled: true,
- },
- { label: "Armed Forces Americas", value: "AA" },
- { label: "Armed Forces Africa", value: "AE" },
- { label: "Armed Forces Canada", value: "AE" },
- { label: "Armed Forces Europe", value: "AE" },
- { label: "Armed Forces Middle East", value: "AE" },
- { label: "Armed Forces Pacific", value: "AP" },
- ]);
- break;
- case "United States":
- this.setStateValues(state, "State", [
- { label: "Select State", value: "" },
- { label: "Alabama", value: "Alabama" },
- { label: "Alaska", value: "Alaska" },
- { label: "Arizona", value: "Arizona" },
- { label: "Arkansas", value: "Arkansas" },
- { label: "California", value: "California" },
- { label: "Colorado", value: "Colorado" },
- { label: "Connecticut", value: "Connecticut" },
- { label: "Delaware", value: "Delaware" },
- { label: "District of Columbia", value: "District of Columbia" },
- { label: "Florida", value: "Florida" },
- { label: "Georgia", value: "Georgia" },
- { label: "Hawaii", value: "Hawaii" },
- { label: "Idaho", value: "Idaho" },
- { label: "Illinois", value: "Illinois" },
- { label: "Indiana", value: "Indiana" },
- { label: "Iowa", value: "Iowa" },
- { label: "Kansas", value: "Kansas" },
- { label: "Kentucky", value: "Kentucky" },
- { label: "Louisiana", value: "Louisiana" },
- { label: "Maine", value: "Maine" },
- { label: "Maryland", value: "Maryland" },
- { label: "Massachusetts", value: "Massachusetts" },
- { label: "Michigan", value: "Michigan" },
- { label: "Minnesota", value: "Minnesota" },
- { label: "Mississippi", value: "Mississippi" },
- { label: "Missouri", value: "Missouri" },
- { label: "Montana", value: "Montana" },
- { label: "Nebraska", value: "Nebraska" },
- { label: "Nevada", value: "Nevada" },
- { label: "New Hampshire", value: "New Hampshire" },
- { label: "New Jersey", value: "New Jersey" },
- { label: "New Mexico", value: "New Mexico" },
- { label: "New York", value: "New York" },
- { label: "North Carolina", value: "North Carolina" },
- { label: "North Dakota", value: "North Dakota" },
- { label: "Ohio", value: "Ohio" },
- { label: "Oklahoma", value: "Oklahoma" },
- { label: "Oregon", value: "Oregon" },
- { label: "Pennsylvania", value: "Pennsylvania" },
- { label: "Rhode Island", value: "Rhode Island" },
- { label: "South Carolina", value: "South Carolina" },
- { label: "South Dakota", value: "South Dakota" },
- { label: "Tennessee", value: "Tennessee" },
- { label: "Texas", value: "Texas" },
- { label: "Utah", value: "Utah" },
- { label: "Vermont", value: "Vermont" },
- { label: "Virginia", value: "Virginia" },
- { label: "Washington", value: "Washington" },
- { label: "West Virginia", value: "West Virginia" },
- { label: "Wisconsin", value: "Wisconsin" },
- { label: "Wyoming", value: "Wyoming" },
- {
- label: "── US Territories ──",
- value: "",
- disabled: true,
- },
- { label: "American Samoa", value: "American Samoa" },
- { label: "Guam", value: "Guam" },
- {
- label: "Northern Mariana Islands",
- value: "Northern Mariana Islands",
- },
- { label: "Puerto Rico", value: "Puerto Rico" },
- {
- label: "US Minor Outlying Islands",
- value: "US Minor Outlying Islands",
- },
- { label: "Virgin Islands", value: "Virgin Islands" },
- {
- label: "── Armed Forces ──",
- value: "",
- disabled: true,
- },
- { label: "Armed Forces Americas", value: "Armed Forces Americas" },
- { label: "Armed Forces Africa", value: "Armed Forces Africa" },
- { label: "Armed Forces Canada", value: "Armed Forces Canada" },
- { label: "Armed Forces Europe", value: "Armed Forces Europe" },
- {
- label: "Armed Forces Middle East",
- value: "Armed Forces Middle East",
- },
- { label: "Armed Forces Pacific", value: "Armed Forces Pacific" },
- ]);
- break;
- case "CA":
- case "CAN":
- this.setStateValues(state, "Province / Territory", [
- { label: "Select", value: "" },
- { label: "Alberta", value: "AB" },
- { label: "British Columbia", value: "BC" },
- { label: "Manitoba", value: "MB" },
- { label: "New Brunswick", value: "NB" },
- { label: "Newfoundland and Labrador", value: "NL" },
- { label: "Northwest Territories", value: "NT" },
- { label: "Nova Scotia", value: "NS" },
- { label: "Nunavut", value: "NU" },
- { label: "Ontario", value: "ON" },
- { label: "Prince Edward Island", value: "PE" },
- { label: "Quebec", value: "QC" },
- { label: "Saskatchewan", value: "SK" },
- { label: "Yukon", value: "YT" },
- ]);
- break;
- case "Canada":
- this.setStateValues(state, "Province / Territory", [
- { label: "Select", value: "" },
- { label: "Alberta", value: "Alberta" },
- { label: "British Columbia", value: "British Columbia" },
- { label: "Manitoba", value: "Manitoba" },
- { label: "New Brunswick", value: "New Brunswick" },
- {
- label: "Newfoundland and Labrador",
- value: "Newfoundland and Labrador",
- },
- { label: "Northwest Territories", value: "Northwest Territories" },
- { label: "Nova Scotia", value: "Nova Scotia" },
- { label: "Nunavut", value: "Nunavut" },
- { label: "Ontario", value: "Ontario" },
- { label: "Prince Edward Island", value: "Prince Edward Island" },
- { label: "Quebec", value: "Quebec" },
- { label: "Saskatchewan", value: "Saskatchewan" },
- { label: "Yukon", value: "Yukon" },
- ]);
- break;
- case "MX":
- case "MEX":
- this.setStateValues(state, "Estado", [
- { label: "Seleccione Estado", value: "" },
- { label: "Aguascalientes", value: "AGU" },
- { label: "Baja California", value: "BCN" },
- { label: "Baja California Sur", value: "BCS" },
- { label: "Campeche", value: "CAM" },
- { label: "Chiapas", value: "CHP" },
- { label: "Ciudad de Mexico", value: "CMX" },
- { label: "Chihuahua", value: "CHH" },
- { label: "Coahuila", value: "COA" },
- { label: "Colima", value: "COL" },
- { label: "Durango", value: "DUR" },
- { label: "Guanajuato", value: "GUA" },
- { label: "Guerrero", value: "GRO" },
- { label: "Hidalgo", value: "HID" },
- { label: "Jalisco", value: "JAL" },
- { label: "Michoacan", value: "MIC" },
- { label: "Morelos", value: "MOR" },
- { label: "Nayarit", value: "NAY" },
- { label: "Nuevo Leon", value: "NLE" },
- { label: "Oaxaca", value: "OAX" },
- { label: "Puebla", value: "PUE" },
- { label: "Queretaro", value: "QUE" },
- { label: "Quintana Roo", value: "ROO" },
- { label: "San Luis Potosi", value: "SLP" },
- { label: "Sinaloa", value: "SIN" },
- { label: "Sonora", value: "SON" },
- { label: "Tabasco", value: "TAB" },
- { label: "Tamaulipas", value: "TAM" },
- { label: "Tlaxcala", value: "TLA" },
- { label: "Veracruz", value: "VER" },
- { label: "Yucatan", value: "YUC" },
- { label: "Zacatecas", value: "ZAC" },
- ]);
- break;
- case "Mexico":
- this.setStateValues(state, "Estado", [
- { label: "Seleccione Estado", value: "" },
- { label: "Aguascalientes", value: "Aguascalientes" },
- { label: "Baja California", value: "Baja California" },
- { label: "Baja California Sur", value: "Baja California Sur" },
- { label: "Campeche", value: "Campeche" },
- { label: "Chiapas", value: "Chiapas" },
- { label: "Ciudad de Mexico", value: "Ciudad de Mexico" },
- { label: "Chihuahua", value: "Chihuahua" },
- { label: "Coahuila", value: "Coahuila" },
- { label: "Colima", value: "Colima" },
- { label: "Durango", value: "Durango" },
- { label: "Guanajuato", value: "Guanajuato" },
- { label: "Guerrero", value: "Guerrero" },
- { label: "Hidalgo", value: "Hidalgo" },
- { label: "Jalisco", value: "Jalisco" },
- { label: "Michoacan", value: "Michoacan" },
- { label: "Morelos", value: "Morelos" },
- { label: "Nayarit", value: "Nayarit" },
- { label: "Nuevo Leon", value: "Nuevo Leon" },
- { label: "Oaxaca", value: "Oaxaca" },
- { label: "Puebla", value: "Puebla" },
- { label: "Queretaro", value: "Queretaro" },
- { label: "Quintana Roo", value: "Quintana Roo" },
- { label: "San Luis Potosi", value: "San Luis Potosi" },
- { label: "Sinaloa", value: "Sinaloa" },
- { label: "Sonora", value: "Sonora" },
- { label: "Tabasco", value: "Tabasco" },
- { label: "Tamaulipas", value: "Tamaulipas" },
- { label: "Tlaxcala", value: "Tlaxcala" },
- { label: "Veracruz", value: "Veracruz" },
- { label: "Yucatan", value: "Yucatan" },
- { label: "Zacatecas", value: "Zacatecas" },
- ]);
- break;
- default:
- this.setStateValues(state, "Province / State", null);
- break;
+ onSubmit() {
+ const optIn = document.querySelector(".en__field__item:not(.en__field--question) input[name^='supporter.questions'][type='checkbox']:checked");
+ if (optIn) {
+ this.logger.log("EN_SUBMISSION_WITH_EMAIL_OPTIN");
+ this.dataLayer.push({
+ event: "EN_SUBMISSION_WITH_EMAIL_OPTIN",
+ });
+ }
+ else {
+ this.logger.log("EN_SUBMISSION_WITHOUT_EMAIL_OPTIN");
+ this.dataLayer.push({
+ event: "EN_SUBMISSION_WITHOUT_EMAIL_OPTIN",
+ });
}
}
- setStateValues(state, label, values) {
- const stateField = engrid_ENGrid.getField(state);
- const stateWrapper = stateField ? stateField.closest(".en__field") : null;
- if (stateWrapper) {
- const stateLabel = stateWrapper.querySelector(".en__field__label");
- const elementWrapper = stateWrapper.querySelector(".en__field__element");
- if (stateLabel) {
- stateLabel.innerHTML = label;
- }
- if (elementWrapper) {
- const selectedState = get(`engrid-state-${state}`);
- if (values === null || values === void 0 ? void 0 : values.length) {
- const select = document.createElement("select");
- select.name = state;
- select.id = "en__field_" + state.toLowerCase().replace(".", "_");
- select.classList.add("en__field__input");
- select.classList.add("en__field__input--select");
- select.autocomplete = "address-level1";
- let valueSelected = false;
- values.forEach((value) => {
- const option = document.createElement("option");
- option.value = value.value;
- option.innerHTML = value.label;
- if (selectedState === value.value && !valueSelected) {
- option.selected = true;
- valueSelected = true;
- }
- if (value.disabled) {
- option.disabled = true;
- }
- select.appendChild(option);
- });
- elementWrapper.innerHTML = "";
- elementWrapper.appendChild(select);
- select.addEventListener("change", this.rememberState.bind(this, state));
- select.dispatchEvent(new Event("change", { bubbles: true }));
+ attachEventListeners() {
+ const textInputs = document.querySelectorAll(".en__component--advrow input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=hidden]):not([unhidden]), .en__component--advrow textarea");
+ textInputs.forEach((el) => {
+ el.addEventListener("blur", (e) => {
+ this.handleFieldValueChange(e.target);
+ });
+ });
+ const radioAndCheckboxInputs = document.querySelectorAll(".en__component--advrow input[type=checkbox], .en__component--advrow input[type=radio]");
+ radioAndCheckboxInputs.forEach((el) => {
+ el.addEventListener("change", (e) => {
+ this.handleFieldValueChange(e.target);
+ });
+ });
+ const selectInputs = document.querySelectorAll(".en__component--advrow select");
+ selectInputs.forEach((el) => {
+ el.addEventListener("change", (e) => {
+ this.handleFieldValueChange(e.target);
+ });
+ });
+ }
+ handleFieldValueChange(el) {
+ var _a, _b, _c;
+ return data_layer_awaiter(this, void 0, void 0, function* () {
+ if (el.value === "" || this.excludedFields.includes(el.name))
+ return;
+ const value = this.hashedFields.includes(el.name)
+ ? yield this.hash(el.value)
+ : el.value;
+ if (["checkbox", "radio"].includes(el.type)) {
+ if (el.checked) {
+ if (el.name === "en__pg") {
+ //Premium gift handling
+ this.dataLayer.push({
+ event: "EN_FORM_VALUE_UPDATED",
+ enFieldName: el.name,
+ enFieldLabel: "Premium Gift",
+ enFieldValue: (_b = (_a = el
+ .closest(".en__pg__body")) === null || _a === void 0 ? void 0 : _a.querySelector(".en__pg__name")) === null || _b === void 0 ? void 0 : _b.textContent,
+ enProductId: (_c = document.querySelector('[name="transaction.selprodvariantid"]')) === null || _c === void 0 ? void 0 : _c.value,
+ });
+ }
+ else {
+ this.dataLayer.push({
+ event: "EN_FORM_VALUE_UPDATED",
+ enFieldName: el.name,
+ enFieldLabel: this.getFieldLabel(el),
+ enFieldValue: value,
+ });
+ }
}
- else {
- elementWrapper.innerHTML = "";
- const input = document.createElement("input");
- input.type = "text";
- input.name = state;
- input.placeholder = label;
- input.id = "en__field_" + state.toLowerCase().replace(".", "_");
- input.classList.add("en__field__input");
- input.classList.add("en__field__input--text");
- input.autocomplete = "address-level1";
- if (selectedState) {
- input.value = selectedState;
+ return;
+ }
+ if (el.name === this.retainedEmailField) {
+ const retainedEmailValue = this.geRetainedFieldsValue("email");
+ const sha256value = yield this.hash(retainedEmailValue);
+ localStorage.setItem(`EN_HASH_EMAIL`, sha256value);
+ this.dataLayer.push({
+ event: "EN_HASH_VALUE_UPDATED",
+ enFieldName: "email",
+ enFieldLabel: this.getFieldLabel(el),
+ enFieldValue: sha256value,
+ });
+ return;
+ }
+ else if (this.retainedAddressFields.includes(el.name)) {
+ const retainedAddressValue = this.geRetainedFieldsValue("address");
+ const sha256value = yield this.hash(retainedAddressValue);
+ localStorage.setItem(`EN_HASH_ADDRESS`, sha256value);
+ this.dataLayer.push({
+ event: "EN_HASH_VALUE_UPDATED",
+ enFieldName: "address",
+ enFieldLabel: "Supporter Address",
+ enFieldValue: sha256value,
+ });
+ }
+ else if (this.retainedPhoneFields.includes(el.name)) {
+ const retainedPhoneValue = this.geRetainedFieldsValue("phone");
+ const sha256value = yield this.hash(retainedPhoneValue);
+ localStorage.setItem(`EN_HASH_PHONE`, sha256value);
+ this.dataLayer.push({
+ event: "EN_HASH_VALUE_UPDATED",
+ enFieldName: "phone",
+ enFieldLabel: "Supporter Phone",
+ enFieldValue: sha256value,
+ });
+ }
+ this.dataLayer.push({
+ event: "EN_FORM_VALUE_UPDATED",
+ enFieldName: el.name,
+ enFieldLabel: this.getFieldLabel(el),
+ enFieldValue: value,
+ });
+ });
+ }
+ geRetainedFieldsValue(kind) {
+ switch (kind) {
+ case "email":
+ return engrid_ENGrid.getFieldValue(this.retainedEmailField);
+ case "address":
+ return this.retainedAddressFields
+ .map((field) => engrid_ENGrid.getFieldValue(field))
+ .filter((value) => value !== "")
+ .join("")
+ .toLocaleLowerCase()
+ .replace(/\s+/g, "");
+ case "phone":
+ // Only return the first phone number found - prioritize phoneNumber2 over phoneNumber and remove non-numeric characters
+ for (const field of this.retainedPhoneFields) {
+ const value = engrid_ENGrid.getFieldValue(field);
+ if (value !== "") {
+ return value.replace(/\D/g, "");
}
- elementWrapper.appendChild(input);
- input.addEventListener("change", this.rememberState.bind(this, state));
}
- }
+ return "";
+ default:
+ return "";
}
}
- rememberState(state) {
- const stateField = engrid_ENGrid.getField(state);
- if (stateField) {
- set(`engrid-state-${stateField.name}`, stateField.value, {
- expires: 1,
- sameSite: "none",
- secure: true,
- });
- }
+ hash(value) {
+ return data_layer_awaiter(this, void 0, void 0, function* () {
+ const data = this.encoder.encode(value);
+ const hashBuffer = yield crypto.subtle.digest("SHA-256", data);
+ return Array.from(new Uint8Array(hashBuffer))
+ .map((byte) => {
+ const hex = byte.toString(16);
+ return hex.length === 1 ? "0" + hex : hex;
+ })
+ .join("");
+ });
+ }
+ getFieldLabel(el) {
+ var _a, _b;
+ return ((_b = (_a = el.closest(".en__field")) === null || _a === void 0 ? void 0 : _a.querySelector("label")) === null || _b === void 0 ? void 0 : _b.textContent) || "";
+ }
+ addEndOfGiftProcessEvent(eventName, eventProperties = {}) {
+ this.storeEndOfGiftProcessData(Object.assign({ event: eventName }, eventProperties));
+ }
+ addEndOfGiftProcessVariable(variableName, variableValue = "") {
+ this.storeEndOfGiftProcessData({
+ [variableName.toUpperCase()]: variableValue,
+ });
+ }
+ storeEndOfGiftProcessData(data) {
+ const events = this.getEndOfGiftProcessData();
+ events.push(data);
+ window.sessionStorage.setItem(this.endOfGiftProcessStorageKey, JSON.stringify(events));
+ }
+ addEndOfGiftProcessEventsToDataLayer() {
+ this.getEndOfGiftProcessData().forEach((event) => {
+ this.dataLayer.push(event);
+ });
+ window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
+ }
+ getEndOfGiftProcessData() {
+ let eventsData = window.sessionStorage.getItem(this.endOfGiftProcessStorageKey);
+ return !eventsData ? [] : JSON.parse(eventsData);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/auto-country-select.js
-// This class works when the user has added ".simple_country_select" as a class in page builder for the Country select
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-replace.js
+// This script is used to replace merge tags in the EN Blocks of the page.
+// It searches for HTML elements containing the data to be replaced and replaces it.
+// The data to be replaced is passed as URL parameters, example: ?engrid_data[key]=value.
+// The merge tag, if found, is replaced with the value from the URL parameter.
+// If no value is found, the default value is used.
+// The default value is the value inside the merge tag, example: {engrid_data~key~default}.
+// If no default value is set, an empty string is used.
-class AutoCountrySelect {
+class DataReplace {
constructor() {
- this._countryEvent = Country.getInstance();
- this.countryWrapper = document.querySelector(".simple_country_select");
- this.countrySelect = this._countryEvent
- .countryField;
- this.country = null;
- const engridAutofill = get("engrid-autofill");
- const submissionFailed = !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
- const hasIntlSupport = !!engrid_ENGrid.checkNested(window.Intl, "DisplayNames");
- // Only run if there's no engrid-autofill cookie && if it has Intl support && no country data in url
- const locationDataInUrl = engrid_ENGrid.getUrlParameter("supporter.country") ||
- engrid_ENGrid.getUrlParameter("supporter.region") ||
- (engrid_ENGrid.getUrlParameter("ea.url.id") &&
- !engrid_ENGrid.getUrlParameter("forwarded"));
- // If fast form is active, then personal details have already been filled somehow and we should not override the country selection
- // The client is also likely using WelcomeBack.
- const fastFormActive = engrid_ENGrid.getBodyData("hide-fast-address-details") ||
- engrid_ENGrid.getBodyData("hide-fast-personal-details");
- if (!engridAutofill &&
- !submissionFailed &&
- hasIntlSupport &&
- !locationDataInUrl &&
- !fastFormActive) {
- fetch(`https://${window.location.hostname}/cdn-cgi/trace`)
- .then((res) => res.text())
- .then((t) => {
- let data = t.replace(/[\r\n]+/g, '","').replace(/\=+/g, '":"');
- data = '{"' + data.slice(0, data.lastIndexOf('","')) + '"}';
- const jsondata = JSON.parse(data);
- this.country = jsondata.loc;
- this.init();
- // console.log("Country:", this.country);
+ this.logger = new logger_EngridLogger("DataReplace", "#333333", "#00f3ff", "‡οΈ");
+ this.enElements = new Array();
+ this.searchElements();
+ if (!this.shouldRun())
+ return;
+ this.logger.log("Elements Found:", this.enElements);
+ this.replaceAll();
+ }
+ /**
+ * Searches for HTML elements containing the data to be replaced.
+ */
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field
+ `);
+ if (enElements.length > 0) {
+ enElements.forEach((item) => {
+ if (item instanceof HTMLElement &&
+ item.innerHTML.includes("{engrid_data~")) {
+ this.enElements.push(item);
+ }
});
}
- else {
- this.init();
- }
}
- init() {
- if (this.countrySelect) {
- if (this.country) {
- const countriesNames = new Intl.DisplayNames(["en"], {
- type: "region",
- });
- // We are setting the country by Name because the ISO code is not always the same. They have 2 and 3 letter codes.
- this.setCountryByName(countriesNames.of(this.country), this.country);
- }
- }
+ /**
+ * Checks if there are elements to be replaced.
+ * @returns True if there are elements to be replaced, false otherwise.
+ */
+ shouldRun() {
+ return this.enElements.length > 0;
}
- setCountryByName(countryName, countryCode) {
- if (this.countrySelect) {
- let countrySelectOptions = this.countrySelect.options;
- for (let i = 0; i < countrySelectOptions.length; i++) {
- if (countrySelectOptions[i].innerHTML.toLowerCase() ==
- countryName.toLowerCase() ||
- countrySelectOptions[i].value.toLowerCase() ==
- countryCode.toLowerCase()) {
- this.countrySelect.selectedIndex = i;
- break;
- }
+ /**
+ * Replaces all occurrences of data in the HTML elements.
+ */
+ replaceAll() {
+ const regEx = /{engrid_data~\[([\w-]+)\]~?\[?(.+?)?\]?}/g;
+ this.enElements.forEach((item) => {
+ const array = item.innerHTML.matchAll(regEx);
+ for (const match of array) {
+ this.replaceItem(item, match);
}
- const event = new Event("change", { bubbles: true });
- this.countrySelect.dispatchEvent(event);
+ });
+ engrid_ENGrid.setBodyData("merge-tags-processed", "");
+ }
+ /**
+ * Replaces a specific data item in the given HTML element.
+ * @param where The HTML element where the replacement should occur.
+ * @param item The matched data item.
+ * @param key The key of the data item.
+ * @param defaultValue The default value to use if the data item is not found.
+ */
+ replaceItem(where, [item, key, defaultValue]) {
+ var _a;
+ let value = (_a = engrid_ENGrid.getUrlParameter(`engrid_data[${key}]`)) !== null && _a !== void 0 ? _a : defaultValue;
+ if (typeof value === "string") {
+ value = value.replace(/\r?\\n|\n|\r/g, " ");
+ }
+ else {
+ value = "";
}
+ this.logger.log("Replacing", key, value);
+ where.innerHTML = where.innerHTML.replace(item, value);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/skip-link.js
-// Javascript that adds an accessible "Skip Link" button after the opening that jumps to
-// the first or field in a "body-" section, or the first if none are found
-// in those sections
-// Depends on _engrid-skip-link.scss
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-hide.js
+// Hides elements based on URL arguments.
+//
+// The DataHide class is used to hide elements based on URL arguments.
+// It retrieves the elements to hide from the URL arguments and hides them.
+// If no elements are found, the constructor returns early.
+// Otherwise, it logs the found elements and hides them.
-class SkipToMainContentLink {
+class DataHide {
constructor() {
- const firstTitleInEngridBody = document.querySelector("div[class*='body-'] title");
- const firstH1InEngridBody = document.querySelector("div[class*='body-'] h1");
- const firstTitle = document.querySelector("title");
- const firstH1 = document.querySelector("h1");
- if (firstTitleInEngridBody && firstTitleInEngridBody.parentElement) {
- firstTitleInEngridBody.parentElement.id = "skip-link";
- this.insertSkipLinkSpan();
- }
- else if (firstH1InEngridBody && firstH1InEngridBody.parentElement) {
- firstH1InEngridBody.parentElement.id = "skip-link";
- this.insertSkipLinkSpan();
- }
- else if (firstTitle && firstTitle.parentElement) {
- firstTitle.parentElement.id = "skip-link";
- this.insertSkipLinkSpan();
- }
- else if (firstH1 && firstH1.parentElement) {
- firstH1.parentElement.id = "skip-link";
- this.insertSkipLinkSpan();
- }
- else {
- if (engrid_ENGrid.debug)
- console.log("This page contains no or and a 'Skip to main content' link was not added");
+ this.logger = new logger_EngridLogger("DataHide", "#333333", "#f0f0f0", "π");
+ this.enElements = new Array();
+ this.logger.log("Constructor");
+ this.enElements = engrid_ENGrid.getUrlParameter("engrid_hide[]");
+ if (!this.enElements || this.enElements.length === 0) {
+ this.logger.log("No Elements Found");
+ return;
}
+ this.logger.log("Elements Found:", this.enElements);
+ this.hideAll();
}
- insertSkipLinkSpan() {
- document.body.insertAdjacentHTML("afterbegin", 'Skip to main content ');
+ /**
+ * Hides all the elements based on the URL arguments.
+ */
+ hideAll() {
+ this.enElements.forEach((element) => {
+ const item = Object.keys(element)[0];
+ const type = Object.values(element)[0];
+ this.hideItem(item, type);
+ });
+ return;
+ }
+ /**
+ * Hides a specific element based on the item and type.
+ * @param item - The item to hide (ID or class name).
+ * @param type - The type of the item (either "id" or "class").
+ */
+ hideItem(item, type) {
+ const regEx = /engrid_hide\[([\w-]+)\]/g;
+ const itemData = [...item.matchAll(regEx)].map((match) => match[1])[0];
+ switch (type) {
+ case "id":
+ const element = document.getElementById(itemData);
+ if (element) {
+ this.logger.log("Hiding By ID", itemData, element);
+ element.setAttribute("hidden-via-url-argument", "");
+ }
+ else {
+ this.logger.error("Element Not Found By ID", itemData);
+ }
+ break;
+ case "class":
+ default:
+ const elements = document.getElementsByClassName(itemData);
+ if (elements.length > 0) {
+ for (let i = 0; i < elements.length; i++) {
+ this.logger.log("Hiding By Class", itemData, elements[i]);
+ elements[i].setAttribute("hidden-via-url-argument", "");
+ }
+ }
+ else {
+ this.logger.log("No Elements Found By Class", itemData);
+ }
+ break;
+ }
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/src-defer.js
-// Build Notes: Add the vanilla Javascript version inline inside the page template right before
-// In the event the vanilla javascript is not inlined we should still process any assets with a data-src still defined on it. Plus we only process background video via this JS file as to not block the page with a large video file downloading.
-// // 4Site's simplified image lazy loader
-// var srcDefer = document.querySelectorAll("img[data-src]");
-// window.addEventListener('DOMContentLoaded', (event) => {
-// for (var i = 0; i < srcDefer.length; i++) {
-// let dataSrc = srcDefer[i].getAttribute("data-src");
-// if (dataSrc) {
-// srcDefer[i].setAttribute("decoding", "async"); // Gets image processing off the main working thread
-// srcDefer[i].setAttribute("loading", "lazy"); // Lets the browser determine when the asset should be downloaded
-// srcDefer[i].setAttribute("src", dataSrc); // Sets the src which will cause the browser to retrieve the asset
-// srcDefer[i].setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
-// srcDefer[i].removeAttribute("data-src"); // Removes the data-source
-// }
-// }
-// });
-class SrcDefer {
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/add-name-to-message.js
+/*
+ Adds first and last name when First Name and Last Name fields lose focus if name shortcodes aren't present
+*/
+
+class AddNameToMessage {
constructor() {
- // Find all images and videos with a data-src defined
- this.imgSrcDefer = document.querySelectorAll("img[data-src]");
- this.videoBackground = document.querySelectorAll("video");
- this.videoBackgroundSource = document.querySelectorAll("video source");
- // Process images
- for (let i = 0; i < this.imgSrcDefer.length; i++) {
- let img = this.imgSrcDefer[i];
- if (img) {
- img.setAttribute("decoding", "async"); // Gets image processing off the main working thread, and decodes the image asynchronously to reduce delay in presenting other content
- img.setAttribute("loading", "lazy"); // Lets the browser determine when the asset should be downloaded using it's native lazy loading
- let imgDataSrc = img.getAttribute("data-src");
- if (imgDataSrc) {
- img.setAttribute("src", imgDataSrc); // Sets the src which will cause the browser to retrieve the asset
- }
- img.setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
- img.removeAttribute("data-src"); // Removes the data-source
- }
+ if (!this.shouldRun()) {
+ // Don't run the script if the page isn't email to target
+ return;
}
- // Process video
- for (let i = 0; i < this.videoBackground.length; i++) {
- let video = this.videoBackground[i];
- // Process one or more defined sources in the tag
- this.videoBackgroundSource = video.querySelectorAll("source");
- if (this.videoBackgroundSource) {
- // loop through all the sources
- for (let j = 0; j < this.videoBackgroundSource.length; j++) {
- let videoSource = this.videoBackgroundSource[j];
- if (videoSource) {
- let videoBackgroundSourcedDataSrc = videoSource.getAttribute("data-src");
- if (videoBackgroundSourcedDataSrc) {
- videoSource.setAttribute("src", videoBackgroundSourcedDataSrc);
- videoSource.setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
- videoSource.removeAttribute("data-src"); // Removes the data-source
+ this.replaceNameShortcode("#en__field_supporter_firstName", "#en__field_supporter_lastName");
+ }
+ shouldRun() {
+ return engrid_ENGrid.getPageType() === "EMAILTOTARGET";
+ }
+ replaceNameShortcode(fName, lName) {
+ const firstName = document.querySelector(fName);
+ const lastName = document.querySelector(lName);
+ let message = document.querySelector('[name="contact.message"]');
+ let addedFirstName = false;
+ let addedLastName = false;
+ if (message) {
+ if (message.value.includes("{user_data~First Name") ||
+ message.value.includes("{user_data~Last Name")) {
+ return;
+ }
+ else {
+ if (!message.value.includes("{user_data~First Name") && firstName) {
+ firstName.addEventListener("blur", (e) => {
+ const target = e.target;
+ if (message && !addedFirstName) {
+ addedFirstName = true;
+ message.value = message.value.concat("\n" + target.value);
}
- }
+ });
}
- // To get the browser to request the video asset defined we need to remove the tag and re-add it
- let videoBackgroundParent = video.parentNode; // Determine the parent of the tag
- let copyOfVideoBackground = video; // Copy the tag
- if (videoBackgroundParent && copyOfVideoBackground) {
- videoBackgroundParent.replaceChild(copyOfVideoBackground, video); // Replace the with the copy of itself
- // Update the video to auto play, mute, loop
- video.muted = true; // Mute the video by default
- video.controls = false; // Hide the browser controls
- video.loop = true; // Loop the video
- video.playsInline = true; // Encourage the user agent to display video content within the element's playback area
- video.play(); // Plays the video
+ if (!message.value.includes("{user_data~Last Name") && lastName) {
+ lastName.addEventListener("blur", (e) => {
+ const target = e.target;
+ if (message && !addedLastName) {
+ addedLastName = true;
+ message.value = message.value.concat(" " + target.value);
+ }
+ });
}
}
}
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/set-recurr-freq.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/expand-region-name.js
+// Populates hidden supporter field "Region Long Format" with expanded name (e.g FL becomes Florida)
-class setRecurrFreq {
+class ExpandRegionName {
constructor() {
- this._frequency = DonationFrequency.getInstance();
- this._amount = DonationAmount.getInstance();
- this.linkClass = "setRecurrFreq-";
- this.checkboxName = "engrid.recurrfreq";
- // Watch the links that starts with linkClass
- document
- .querySelectorAll(`a[class^="${this.linkClass}"]`)
- .forEach((element) => {
- element.addEventListener("click", (e) => {
- // Get the right class
- const setRecurrFreqClass = element.className
- .split(" ")
- .filter((linkClass) => linkClass.startsWith(this.linkClass));
- if (engrid_ENGrid.debug)
- console.log(setRecurrFreqClass);
- if (setRecurrFreqClass.length) {
- e.preventDefault();
- engrid_ENGrid.setFieldValue("transaction.recurrfreq", setRecurrFreqClass[0]
- .substring(this.linkClass.length)
- .toUpperCase());
- this._frequency.load();
- }
- });
- });
- const currentFrequency = engrid_ENGrid.getFieldValue("transaction.recurrfreq").toUpperCase();
- // Watch checkboxes with the name checkboxName
- document.getElementsByName(this.checkboxName).forEach((element) => {
- // Set checked status per currently-set frequency
- const frequency = element.value.toUpperCase();
- if (frequency === currentFrequency) {
- element.checked = true;
- }
- else {
- element.checked = false;
+ this._form = en_form_EnForm.getInstance();
+ this.logger = new logger_EngridLogger("ExpandRegionName", "#333333", "#00eb65", "π");
+ if (this.shouldRun()) {
+ const expandedRegionField = engrid_ENGrid.getOption("RegionLongFormat");
+ console.log("expandedRegionField", expandedRegionField);
+ const hiddenRegion = document.querySelector(`[name="${expandedRegionField}"]`);
+ if (!hiddenRegion) {
+ this.logger.log(`CREATED field ${expandedRegionField}`);
+ engrid_ENGrid.createHiddenInput(expandedRegionField);
}
- element.addEventListener("change", () => {
- const frequency = element.value.toUpperCase();
- if (element.checked) {
- engrid_ENGrid.setFieldValue("transaction.recurrfreq", frequency);
- engrid_ENGrid.setFieldValue("transaction.recurrpay", "Y");
- this._frequency.load();
- this._amount.setAmount(this._amount.amount, false);
+ this._form.onValidate.subscribe(() => this.expandRegion());
+ }
+ }
+ shouldRun() {
+ return !!engrid_ENGrid.getOption("RegionLongFormat");
+ }
+ expandRegion() {
+ if (!this._form.validate)
+ return;
+ const userRegion = document.querySelector('[name="supporter.region"]'); // User entered region on the page
+ const expandedRegionField = engrid_ENGrid.getOption("RegionLongFormat");
+ const hiddenRegion = document.querySelector(`[name="${expandedRegionField}"]`); // Hidden region long form field
+ if (!userRegion) {
+ this.logger.log("No region field to populate the hidden region field with");
+ return; // Don't populate hidden region field if user region field isn't on page
+ }
+ if (userRegion.tagName === "SELECT" && "options" in userRegion) {
+ const regionValue = userRegion.options[userRegion.selectedIndex].innerText;
+ hiddenRegion.value = regionValue;
+ this.logger.log("Populated field", hiddenRegion.value);
+ }
+ else if (userRegion.tagName === "INPUT") {
+ const regionValue = userRegion.value;
+ hiddenRegion.value = regionValue;
+ this.logger.log("Populated field", hiddenRegion.value);
+ }
+ return true;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/url-to-form.js
+// Component that allows to set a field value from URL parameters
+// Workflow:
+// 1. Loop through all the URL parameters
+// 2. Check if there's a match with the field name
+// 3. If there's a match AND the field is empty, set the value
+
+class UrlToForm {
+ constructor() {
+ this.logger = new logger_EngridLogger("UrlToForm", "white", "magenta", "π");
+ this.urlParams = new URLSearchParams(document.location.search);
+ if (!this.shouldRun())
+ return;
+ this.urlParams.forEach((value, key) => {
+ const field = document.getElementsByName(key)[0];
+ if (field) {
+ if (field.type === "checkbox") {
+ field.checked = value === "true" || value === "Y" || value === "1";
+ engrid_ENGrid.setFieldValue(key, field.checked);
+ this.logger.log(`Set: ${key} to ${field.checked}`);
}
- else if (frequency !== "ONETIME") {
- engrid_ENGrid.setFieldValue("transaction.recurrfreq", "ONETIME");
- engrid_ENGrid.setFieldValue("transaction.recurrpay", "N");
- this._frequency.load();
- this._amount.setAmount(this._amount.amount, false);
+ else if (!["text", "textarea", "email"].includes(field.type) ||
+ !field.value) {
+ engrid_ENGrid.setFieldValue(key, value);
+ this.logger.log(`Set: ${key} to ${value}`);
}
- });
+ }
});
- // Uncheck the checkbox when frequency != checkbox value
- this._frequency.onFrequencyChange.subscribe(() => {
- const currentFrequency = this._frequency.frequency.toUpperCase();
- document.getElementsByName(this.checkboxName).forEach((element) => {
- const elementFrequency = element.value.toUpperCase();
- if (element.checked && elementFrequency !== currentFrequency) {
- element.checked = false;
- }
- else if (!element.checked && elementFrequency === currentFrequency) {
- element.checked = true;
- }
- });
+ }
+ shouldRun() {
+ return !!document.location.search && this.hasFields();
+ }
+ hasFields() {
+ const ret = [...this.urlParams.keys()].map((key) => {
+ return document.getElementsByName(key).length > 0;
});
+ return ret.includes(true);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/page-background.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/required-if-visible.js
-class PageBackground {
+class RequiredIfVisible {
constructor() {
- // @TODO: Change page-backgroundImage to page-background
- this.pageBackground = document.querySelector(".page-backgroundImage");
- this.mutationObserver = null;
- this.logger = new logger_EngridLogger("PageBackground", "lightblue", "darkblue", "πΌοΈ");
- if (!this.pageBackground) {
- this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");
+ this.logger = new logger_EngridLogger("RequiredIfVisible", "#FFFFFF", "#811212", "π₯");
+ this._form = en_form_EnForm.getInstance();
+ this.requiredIfVisibleElements = document.querySelectorAll(`
+ .i-required .en__field,
+ .i1-required .en__field:nth-of-type(1),
+ .i2-required .en__field:nth-of-type(2),
+ .i3-required .en__field:nth-of-type(3),
+ .i4-required .en__field:nth-of-type(4),
+ .i5-required .en__field:nth-of-type(5),
+ .i6-required .en__field:nth-of-type(6),
+ .i7-required .en__field:nth-of-type(7),
+ .i8-required .en__field:nth-of-type(8),
+ .i9-required .en__field:nth-of-type(9),
+ .i10-required .en__field:nth-of-type(10),
+ .i11-required .en__field:nth-of-type(11)
+ `);
+ if (!this.shouldRun())
return;
- }
- this.initializeBackgroundImage();
- this.setDataAttributes();
- this.processAttributionPositioning();
- this.setupMutationObserver();
+ this._form.onValidate.subscribe(this.validate.bind(this));
}
- /**
- * Initialize background image by finding and setting CSS custom property
- */
- initializeBackgroundImage() {
- if (!this.pageBackground)
+ shouldRun() {
+ return this.requiredIfVisibleElements.length > 0;
+ }
+ validate() {
+ // We're converting the NodeListOf to an Array
+ // because we need to reverse the order of the elements so the last error
+ // is the highest element to get focus()
+ Array.from(this.requiredIfVisibleElements)
+ .reverse()
+ .forEach((field) => {
+ engrid_ENGrid.removeError(field);
+ if (engrid_ENGrid.isVisible(field)) {
+ this.logger.log(`${field.getAttribute("class")} is visible`);
+ const fieldElement = field.querySelector("input:not([type=hidden]) , select, textarea");
+ if (fieldElement &&
+ fieldElement.closest("[data-unhidden]") === null &&
+ !engrid_ENGrid.getFieldValue(fieldElement.getAttribute("name"))) {
+ const fieldLabel = field.querySelector(".en__field__label");
+ if (fieldLabel) {
+ this.logger.log(`${fieldLabel.innerText} is required`);
+ window.setTimeout(() => {
+ engrid_ENGrid.setError(field, `${fieldLabel.innerText} is required`);
+ }, 100);
+ }
+ else {
+ this.logger.log(`${fieldElement.getAttribute("name")} is required`);
+ window.setTimeout(() => {
+ engrid_ENGrid.setError(field, `This field is required`);
+ }, 100);
+ }
+ fieldElement.focus();
+ this._form.validate = false;
+ }
+ }
+ });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/tidycontact.js
+var tidycontact_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+class TidyContact {
+ constructor() {
+ var _a, _b, _c, _d, _e;
+ this.logger = new logger_EngridLogger("TidyContact", "#FFFFFF", "#4d9068", "π§");
+ this.endpoint = "https://api.tidycontact.io";
+ this.wasCalled = false; // True if the API endpoint was called
+ this.httpStatus = 0;
+ this.timeout = 5; // Seconds to API Timeout
+ this.isDirty = false; // True if the address was changed by the user
+ this._form = en_form_EnForm.getInstance();
+ this.countries_list = [
+ ["Afghanistan", "af", "93", "070 123 4567"],
+ ["Albania", "al", "355", "067 212 3456"],
+ ["Algeria", "dz", "213", "0551 23 45 67"],
+ ["American Samoa", "as", "1", "(684) 733-1234"],
+ ["Andorra", "ad", "376", "312 345"],
+ ["Angola", "ao", "244", "923 123 456"],
+ ["Anguilla", "ai", "1", "(264) 235-1234"],
+ ["Antigua and Barbuda", "ag", "1", "(268) 464-1234"],
+ ["Argentina", "ar", "54", "011 15-2345-6789"],
+ ["Armenia", "am", "374", "077 123456"],
+ ["Aruba", "aw", "297", "560 1234"],
+ ["Australia", "au", "61", "0412 345 678"],
+ ["Austria", "at", "43", "0664 123456"],
+ ["Azerbaijan", "az", "994", "040 123 45 67"],
+ ["Bahamas", "bs", "1", "(242) 359-1234"],
+ ["Bahrain", "bh", "973", "3600 1234"],
+ ["Bangladesh", "bd", "880", "01812-345678"],
+ ["Barbados", "bb", "1", "(246) 250-1234"],
+ ["Belarus", "by", "375", "8 029 491-19-11"],
+ ["Belgium", "be", "32", "0470 12 34 56"],
+ ["Belize", "bz", "501", "622-1234"],
+ ["Benin", "bj", "229", "90 01 12 34"],
+ ["Bermuda", "bm", "1", "(441) 370-1234"],
+ ["Bhutan", "bt", "975", "17 12 34 56"],
+ ["Bolivia", "bo", "591", "71234567"],
+ ["Bosnia and Herzegovina", "ba", "387", "061 123 456"],
+ ["Botswana", "bw", "267", "71 123 456"],
+ ["Brazil", "br", "55", "(11) 96123-4567"],
+ ["British Indian Ocean Territory", "io", "246", "380 1234"],
+ ["British Virgin Islands", "vg", "1", "(284) 300-1234"],
+ ["Brunei", "bn", "673", "712 3456"],
+ ["Bulgaria", "bg", "359", "048 123 456"],
+ ["Burkina Faso", "bf", "226", "70 12 34 56"],
+ ["Burundi", "bi", "257", "79 56 12 34"],
+ ["Cambodia", "kh", "855", "091 234 567"],
+ ["Cameroon", "cm", "237", "6 71 23 45 67"],
+ ["Canada", "ca", "1", "(506) 234-5678"],
+ ["Cape Verde", "cv", "238", "991 12 34"],
+ ["Caribbean Netherlands", "bq", "599", "318 1234"],
+ ["Cayman Islands", "ky", "1", "(345) 323-1234"],
+ ["Central African Republic", "cf", "236", "70 01 23 45"],
+ ["Chad", "td", "235", "63 01 23 45"],
+ ["Chile", "cl", "56", "(2) 2123 4567"],
+ ["China", "cn", "86", "131 2345 6789"],
+ ["Christmas Island", "cx", "61", "0412 345 678"],
+ ["Cocos Islands", "cc", "61", "0412 345 678"],
+ ["Colombia", "co", "57", "321 1234567"],
+ ["Comoros", "km", "269", "321 23 45"],
+ ["Congo", "cd", "243", "0991 234 567"],
+ ["Congo", "cg", "242", "06 123 4567"],
+ ["Cook Islands", "ck", "682", "71 234"],
+ ["Costa Rica", "cr", "506", "8312 3456"],
+ ["CΓ΄te dβIvoire", "ci", "225", "01 23 45 6789"],
+ ["Croatia", "hr", "385", "092 123 4567"],
+ ["Cuba", "cu", "53", "05 1234567"],
+ ["CuraΓ§ao", "cw", "599", "9 518 1234"],
+ ["Cyprus", "cy", "357", "96 123456"],
+ ["Czech Republic", "cz", "420", "601 123 456"],
+ ["Denmark", "dk", "45", "32 12 34 56"],
+ ["Djibouti", "dj", "253", "77 83 10 01"],
+ ["Dominica", "dm", "1", "(767) 225-1234"],
+ ["Dominican Republic", "do", "1", "(809) 234-5678"],
+ ["Ecuador", "ec", "593", "099 123 4567"],
+ ["Egypt", "eg", "20", "0100 123 4567"],
+ ["El Salvador", "sv", "503", "7012 3456"],
+ ["Equatorial Guinea", "gq", "240", "222 123 456"],
+ ["Eritrea", "er", "291", "07 123 456"],
+ ["Estonia", "ee", "372", "5123 4567"],
+ ["Eswatini", "sz", "268", "7612 3456"],
+ ["Ethiopia", "et", "251", "091 123 4567"],
+ ["Falkland Islands", "fk", "500", "51234"],
+ ["Faroe Islands", "fo", "298", "211234"],
+ ["Fiji", "fj", "679", "701 2345"],
+ ["Finland", "fi", "358", "041 2345678"],
+ ["France", "fr", "33", "06 12 34 56 78"],
+ ["French Guiana", "gf", "594", "0694 20 12 34"],
+ ["French Polynesia", "pf", "689", "87 12 34 56"],
+ ["Gabon", "ga", "241", "06 03 12 34"],
+ ["Gambia", "gm", "220", "301 2345"],
+ ["Georgia", "ge", "995", "555 12 34 56"],
+ ["Germany", "de", "49", "01512 3456789"],
+ ["Ghana", "gh", "233", "023 123 4567"],
+ ["Gibraltar", "gi", "350", "57123456"],
+ ["Greece", "gr", "30", "691 234 5678"],
+ ["Greenland", "gl", "299", "22 12 34"],
+ ["Grenada", "gd", "1", "(473) 403-1234"],
+ ["Guadeloupe", "gp", "590", "0690 00 12 34"],
+ ["Guam", "gu", "1", "(671) 300-1234"],
+ ["Guatemala", "gt", "502", "5123 4567"],
+ ["Guernsey", "gg", "44", "07781 123456"],
+ ["Guinea", "gn", "224", "601 12 34 56"],
+ ["Guinea-Bissau", "gw", "245", "955 012 345"],
+ ["Guyana", "gy", "592", "609 1234"],
+ ["Haiti", "ht", "509", "34 10 1234"],
+ ["Honduras", "hn", "504", "9123-4567"],
+ ["Hong Kong", "hk", "852", "5123 4567"],
+ ["Hungary", "hu", "36", "06 20 123 4567"],
+ ["Iceland", "is", "354", "611 1234"],
+ ["India", "in", "91", "081234 56789"],
+ ["Indonesia", "id", "62", "0812-345-678"],
+ ["Iran", "ir", "98", "0912 345 6789"],
+ ["Iraq", "iq", "964", "0791 234 5678"],
+ ["Ireland", "ie", "353", "085 012 3456"],
+ ["Isle of Man", "im", "44", "07924 123456"],
+ ["Israel", "il", "972", "050-234-5678"],
+ ["Italy", "it", "39", "312 345 6789"],
+ ["Jamaica", "jm", "1", "(876) 210-1234"],
+ ["Japan", "jp", "81", "090-1234-5678"],
+ ["Jersey", "je", "44", "07797 712345"],
+ ["Jordan", "jo", "962", "07 9012 3456"],
+ ["Kazakhstan", "kz", "7", "8 (771) 000 9998"],
+ ["Kenya", "ke", "254", "0712 123456"],
+ ["Kiribati", "ki", "686", "72001234"],
+ ["Kosovo", "xk", "383", "043 201 234"],
+ ["Kuwait", "kw", "965", "500 12345"],
+ ["Kyrgyzstan", "kg", "996", "0700 123 456"],
+ ["Laos", "la", "856", "020 23 123 456"],
+ ["Latvia", "lv", "371", "21 234 567"],
+ ["Lebanon", "lb", "961", "71 123 456"],
+ ["Lesotho", "ls", "266", "5012 3456"],
+ ["Liberia", "lr", "231", "077 012 3456"],
+ ["Libya", "ly", "218", "091-2345678"],
+ ["Liechtenstein", "li", "423", "660 234 567"],
+ ["Lithuania", "lt", "370", "(8-612) 34567"],
+ ["Luxembourg", "lu", "352", "628 123 456"],
+ ["Macau", "mo", "853", "6612 3456"],
+ ["North Macedonia", "mk", "389", "072 345 678"],
+ ["Madagascar", "mg", "261", "032 12 345 67"],
+ ["Malawi", "mw", "265", "0991 23 45 67"],
+ ["Malaysia", "my", "60", "012-345 6789"],
+ ["Maldives", "mv", "960", "771-2345"],
+ ["Mali", "ml", "223", "65 01 23 45"],
+ ["Malta", "mt", "356", "9696 1234"],
+ ["Marshall Islands", "mh", "692", "235-1234"],
+ ["Martinique", "mq", "596", "0696 20 12 34"],
+ ["Mauritania", "mr", "222", "22 12 34 56"],
+ ["Mauritius", "mu", "230", "5251 2345"],
+ ["Mayotte", "yt", "262", "0639 01 23 45"],
+ ["Mexico", "mx", "52", "222 123 4567"],
+ ["Micronesia", "fm", "691", "350 1234"],
+ ["Moldova", "md", "373", "0621 12 345"],
+ ["Monaco", "mc", "377", "06 12 34 56 78"],
+ ["Mongolia", "mn", "976", "8812 3456"],
+ ["Montenegro", "me", "382", "067 622 901"],
+ ["Montserrat", "ms", "1", "(664) 492-3456"],
+ ["Morocco", "ma", "212", "0650-123456"],
+ ["Mozambique", "mz", "258", "82 123 4567"],
+ ["Myanmar", "mm", "95", "09 212 3456"],
+ ["Namibia", "na", "264", "081 123 4567"],
+ ["Nauru", "nr", "674", "555 1234"],
+ ["Nepal", "np", "977", "984-1234567"],
+ ["Netherlands", "nl", "31", "06 12345678"],
+ ["New Caledonia", "nc", "687", "75.12.34"],
+ ["New Zealand", "nz", "64", "021 123 4567"],
+ ["Nicaragua", "ni", "505", "8123 4567"],
+ ["Niger", "ne", "227", "93 12 34 56"],
+ ["Nigeria", "ng", "234", "0802 123 4567"],
+ ["Niue", "nu", "683", "888 4012"],
+ ["Norfolk Island", "nf", "672", "3 81234"],
+ ["North Korea", "kp", "850", "0192 123 4567"],
+ ["Northern Mariana Islands", "mp", "1", "(670) 234-5678"],
+ ["Norway", "no", "47", "406 12 345"],
+ ["Oman", "om", "968", "9212 3456"],
+ ["Pakistan", "pk", "92", "0301 2345678"],
+ ["Palau", "pw", "680", "620 1234"],
+ ["Palestine", "ps", "970", "0599 123 456"],
+ ["Panama", "pa", "507", "6123-4567"],
+ ["Papua New Guinea", "pg", "675", "7012 3456"],
+ ["Paraguay", "py", "595", "0961 456789"],
+ ["Peru", "pe", "51", "912 345 678"],
+ ["Philippines", "ph", "63", "0905 123 4567"],
+ ["Poland", "pl", "48", "512 345 678"],
+ ["Portugal", "pt", "351", "912 345 678"],
+ ["Puerto Rico", "pr", "1", "(787) 234-5678"],
+ ["Qatar", "qa", "974", "3312 3456"],
+ ["RΓ©union", "re", "262", "0692 12 34 56"],
+ ["Romania", "ro", "40", "0712 034 567"],
+ ["Russia", "ru", "7", "8 (912) 345-67-89"],
+ ["Rwanda", "rw", "250", "0720 123 456"],
+ ["Saint BarthΓ©lemy", "bl", "590", "0690 00 12 34"],
+ ["Saint Helena", "sh", "290", "51234"],
+ ["Saint Kitts and Nevis", "kn", "1", "(869) 765-2917"],
+ ["Saint Lucia", "lc", "1", "(758) 284-5678"],
+ ["Saint Martin", "mf", "590", "0690 00 12 34"],
+ ["Saint Pierre and Miquelon", "pm", "508", "055 12 34"],
+ ["Saint Vincent and the Grenadines", "vc", "1", "(784) 430-1234"],
+ ["Samoa", "ws", "685", "72 12345"],
+ ["San Marino", "sm", "378", "66 66 12 12"],
+ ["SΓ£o TomΓ© and PrΓncipe", "st", "239", "981 2345"],
+ ["Saudi Arabia", "sa", "966", "051 234 5678"],
+ ["Senegal", "sn", "221", "70 123 45 67"],
+ ["Serbia", "rs", "381", "060 1234567"],
+ ["Seychelles", "sc", "248", "2 510 123"],
+ ["Sierra Leone", "sl", "232", "(025) 123456"],
+ ["Singapore", "sg", "65", "8123 4567"],
+ ["Sint Maarten", "sx", "1", "(721) 520-5678"],
+ ["Slovakia", "sk", "421", "0912 123 456"],
+ ["Slovenia", "si", "386", "031 234 567"],
+ ["Solomon Islands", "sb", "677", "74 21234"],
+ ["Somalia", "so", "252", "7 1123456"],
+ ["South Africa", "za", "27", "071 123 4567"],
+ ["South Korea", "kr", "82", "010-2000-0000"],
+ ["South Sudan", "ss", "211", "0977 123 456"],
+ ["Spain", "es", "34", "612 34 56 78"],
+ ["Sri Lanka", "lk", "94", "071 234 5678"],
+ ["Sudan", "sd", "249", "091 123 1234"],
+ ["Suriname", "sr", "597", "741-2345"],
+ ["Svalbard and Jan Mayen", "sj", "47", "412 34 567"],
+ ["Sweden", "se", "46", "070-123 45 67"],
+ ["Switzerland", "ch", "41", "078 123 45 67"],
+ ["Syria", "sy", "963", "0944 567 890"],
+ ["Taiwan", "tw", "886", "0912 345 678"],
+ ["Tajikistan", "tj", "992", "917 12 3456"],
+ ["Tanzania", "tz", "255", "0621 234 567"],
+ ["Thailand", "th", "66", "081 234 5678"],
+ ["Timor-Leste", "tl", "670", "7721 2345"],
+ ["Togo", "tg", "228", "90 11 23 45"],
+ ["Tokelau", "tk", "690", "7290"],
+ ["Tonga", "to", "676", "771 5123"],
+ ["Trinidad and Tobago", "tt", "1", "(868) 291-1234"],
+ ["Tunisia", "tn", "216", "20 123 456"],
+ ["Turkey", "tr", "90", "0501 234 56 78"],
+ ["Turkmenistan", "tm", "993", "8 66 123456"],
+ ["Turks and Caicos Islands", "tc", "1", "(649) 231-1234"],
+ ["Tuvalu", "tv", "688", "90 1234"],
+ ["U.S. Virgin Islands", "vi", "1", "(340) 642-1234"],
+ ["Uganda", "ug", "256", "0712 345678"],
+ ["Ukraine", "ua", "380", "050 123 4567"],
+ ["United Arab Emirates", "ae", "971", "050 123 4567"],
+ ["United Kingdom", "gb", "44", "07400 123456"],
+ ["United States", "us", "1", "(201) 555-0123"],
+ ["Uruguay", "uy", "598", "094 231 234"],
+ ["Uzbekistan", "uz", "998", "8 91 234 56 78"],
+ ["Vanuatu", "vu", "678", "591 2345"],
+ ["Vatican City", "va", "39", "312 345 6789"],
+ ["Venezuela", "ve", "58", "0412-1234567"],
+ ["Vietnam", "vn", "84", "091 234 56 78"],
+ ["Wallis and Futuna", "wf", "681", "82 12 34"],
+ ["Western Sahara", "eh", "212", "0650-123456"],
+ ["Yemen", "ye", "967", "0712 345 678"],
+ ["Zambia", "zm", "260", "095 5123456"],
+ ["Zimbabwe", "zw", "263", "071 234 5678"],
+ ["Γ
land Islands", "ax", "358", "041 2345678"],
+ ];
+ this.countries_dropdown = null;
+ this.country_ip = null;
+ this.options = engrid_ENGrid.getOption("TidyContact");
+ if (this.options === false || !((_a = this.options) === null || _a === void 0 ? void 0 : _a.cid))
return;
- const pageBackgroundImg = this.pageBackground.querySelector("img");
- if (!pageBackgroundImg) {
- this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");
+ if (!this.shouldRun()) {
+ this.logger.log("TidyContact is disabled on this page type");
return;
}
- const dataSrc = pageBackgroundImg.getAttribute("data-src");
- const src = pageBackgroundImg.src;
- if (dataSrc) {
- this.setBackgroundImageUrl(dataSrc, "data-src");
+ this.loadOptions();
+ if (!this.hasAddressFields() && !this.phoneEnabled()) {
+ this.logger.log("No address fields found");
+ return;
}
- else if (src) {
- this.setBackgroundImageUrl(src, "src");
+ this.createFields();
+ this.addEventListeners();
+ if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
+ !window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed() &&
+ engrid_ENGrid.getFieldValue((_c = (_b = this.options) === null || _b === void 0 ? void 0 : _b.address_fields) === null || _c === void 0 ? void 0 : _c.address1) !=
+ "") {
+ this.logger.log("Address Field is not empty");
+ this.isDirty = true;
}
- else {
- this.logger.log("A background image set in the page was found but without a data-src or src value, no action taken", pageBackgroundImg);
+ if (this.phoneEnabled()) {
+ this.createPhoneFields();
+ this.createPhoneMarginVariable();
+ this.logger.log("Phone Standardization is enabled");
+ if (this.countryDropDownEnabled()) {
+ this.renderFlagsDropDown();
+ }
+ const phoneField = engrid_ENGrid.getField((_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.address_fields) === null || _e === void 0 ? void 0 : _e.phone);
+ if (phoneField) {
+ phoneField.addEventListener("keyup", (e) => {
+ this.handlePhoneInputKeydown(e);
+ });
+ this.setDefaultPhoneCountry();
+ }
}
}
- /**
- * Set the background image URL as a CSS custom property
- */
- setBackgroundImageUrl(imageUrl, sourceType) {
- if (!this.pageBackground || !imageUrl)
- return;
- try {
- const cssUrl = `url('${imageUrl}')`;
- this.pageBackground.style.setProperty("--engrid__page-backgroundImage_url", cssUrl);
- this.logger.log(`A background image set in the page was found with a ${sourceType} value, setting it as --engrid__page-backgroundImage_url`, imageUrl);
- }
- catch (error) {
- this.logger.error("Error setting background image URL:", error);
+ shouldRun() {
+ if (this.options &&
+ this.options.page_types &&
+ this.options.page_types.length > 0) {
+ return this.options.page_types.includes(engrid_ENGrid.getPageType());
}
+ return true;
}
- /**
- * Processes attribution positioning for background images by moving positioning classes
- * and data attributes from images to their parent column containers.
- *
- * This function handles two attribution patterns:
- * 1. Class-based:
- * 2. Data attribute-based:
- *
- * Examples:
- *
- * Class-based attribution:
- *
- * β Moves "attribution-bottomright" class to parent .en__component--column
- *
- * Data attribute-based attribution:
- *
- * β Converts to "attribution-top" class and moves to parent .en__component--column
- *
- * Supported positioning values:
- * - center
- * - top, topcenter (these result in the same positioning)
- * - right, rightcenter (these result in the same positioning)
- * - bottom, bottomcenter (these result in the same positioning)
- * - left, leftcenter (these result in the same positioning)
- * - topright
- * - bottomright
- * - bottomleft
- * - topleft
- */
- processAttributionPositioning() {
- if (!this.pageBackground) {
- this.logger.log("No background section found for attribution positioning processing");
+ loadOptions() {
+ var _a, _b, _c, _d;
+ if (this.options) {
+ if (!this.options.address_fields) {
+ this.options.address_fields = {
+ address1: "supporter.address1",
+ address2: "supporter.address2",
+ address3: "supporter.address3",
+ city: "supporter.city",
+ region: "supporter.region",
+ postalCode: "supporter.postcode",
+ country: "supporter.country",
+ phone: "supporter.phoneNumber2", // Phone field
+ };
+ }
+ this.options.address_enable = (_a = this.options.address_enable) !== null && _a !== void 0 ? _a : true;
+ if (this.options.phone_enable) {
+ this.options.phone_flags = (_b = this.options.phone_flags) !== null && _b !== void 0 ? _b : true;
+ this.options.phone_country_from_ip =
+ (_c = this.options.phone_country_from_ip) !== null && _c !== void 0 ? _c : true;
+ this.options.phone_preferred_countries =
+ (_d = this.options.phone_preferred_countries) !== null && _d !== void 0 ? _d : [];
+ }
+ }
+ }
+ createFields() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options || !this.hasAddressFields())
return;
+ // Creating Latitude and Longitude fields
+ const latitudeField = engrid_ENGrid.getField("supporter.geo.latitude");
+ const longitudeField = engrid_ENGrid.getField("supporter.geo.longitude");
+ if (!latitudeField) {
+ engrid_ENGrid.createHiddenInput("supporter.geo.latitude", "");
+ this.logger.log("Creating Hidden Field: supporter.geo.latitude");
}
- this.logger.log("Processing attribution positioning for background section:", this.pageBackground);
- // Define all supported attribution positioning classes
- const allowedClasses = [
- "attribution-center",
- "attribution-bottom",
- "attribution-bottomcenter",
- "attribution-bottomright",
- "attribution-bottomleft",
- "attribution-top",
- "attribution-topcenter",
- "attribution-topright",
- "attribution-topleft",
- "attribution-left",
- "attribution-leftcenter",
- "attribution-right",
- "attribution-rightcenter",
- ];
- try {
- // Find all images in the background section (after any DOM transformations)
- const images = this.pageBackground.querySelectorAll("img");
- this.logger.log("Found images in background section:", images.length);
- images.forEach((img) => {
- this.processImageAttribution(img, allowedClasses);
- });
+ if (!longitudeField) {
+ engrid_ENGrid.createHiddenInput("supporter.geo.longitude", "");
+ this.logger.log("Creating Hidden Field: supporter.geo.longitude");
}
- catch (error) {
- this.logger.error("Error processing attribution positioning:", error);
+ if (this.options.record_field) {
+ const recordField = engrid_ENGrid.getField(this.options.record_field);
+ if (!recordField) {
+ engrid_ENGrid.createHiddenInput(this.options.record_field, "");
+ this.logger.log("Creating Hidden Field: " + this.options.record_field);
+ }
}
- }
- /**
- * Process attribution for a single image
- */
- processImageAttribution(img, allowedClasses) {
- // Pattern 1: Check for class-based attribution positioning
- // Example:
- const matchedClass = allowedClasses.find((cls) => img.classList.contains(cls));
- // Pattern 2: Check for data attribute-based attribution positioning
- // Example:
- const dataPosition = img.getAttribute("data-background-position");
- if (matchedClass) {
- this.handleClassBasedAttribution(img, matchedClass);
+ if (this.options.date_field) {
+ const dateField = engrid_ENGrid.getField(this.options.date_field);
+ if (!dateField) {
+ engrid_ENGrid.createHiddenInput(this.options.date_field, "");
+ this.logger.log("Creating Hidden Field: " + this.options.date_field);
+ }
}
- else if (dataPosition) {
- this.handleDataAttributeAttribution(img, dataPosition);
+ if (this.options.status_field) {
+ const statusField = engrid_ENGrid.getField(this.options.status_field);
+ if (!statusField) {
+ engrid_ENGrid.createHiddenInput(this.options.status_field, "");
+ this.logger.log("Creating Hidden Field: " + this.options.status_field);
+ }
}
- }
- /**
- * Handle class-based attribution positioning
- */
- handleClassBasedAttribution(img, matchedClass) {
- this.logger.log("Found attribution class on image:", matchedClass, img);
- const parentDiv = img.closest(".en__component--column");
- if (parentDiv) {
- // Move the class from image to parent column
- img.classList.remove(matchedClass);
- parentDiv.classList.add(matchedClass);
- this.logger.log("Moved attribution class from image to parent column:", matchedClass, parentDiv);
+ // If there's no Address 2 or Address 3 field, create them
+ if (!engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address2)) {
+ engrid_ENGrid.createHiddenInput((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2, "");
+ this.logger.log("Creating Hidden Field: " + ((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.address2));
}
- else {
- this.logger.log("No parent .en__component--column found for image:", img);
+ if (!engrid_ENGrid.getField((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.address3)) {
+ engrid_ENGrid.createHiddenInput((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.address3, "");
+ this.logger.log("Creating Hidden Field: " + ((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.address3));
}
}
- /**
- * Handle data attribute-based attribution positioning
- */
- handleDataAttributeAttribution(img, dataPosition) {
- // Convert data attribute value to attribution class format
- const attributionClass = `attribution-${dataPosition}`;
- this.logger.log("Found data-background-position on image:", dataPosition, "->", attributionClass, img);
- const parentDiv = img.closest(".en__component--column");
- if (parentDiv) {
- // Remove data attribute from image and add class to parent column
- img.removeAttribute("data-background-position");
- parentDiv.classList.add(attributionClass);
- this.logger.log("Moved data-background-position from image to parent column as class:", attributionClass, parentDiv);
+ createPhoneFields() {
+ if (!this.options)
+ return;
+ engrid_ENGrid.createHiddenInput("tc.phone.country", "");
+ this.logger.log("Creating hidden field: tc.phone.country");
+ if (this.options.phone_record_field) {
+ const recordField = engrid_ENGrid.getField(this.options.phone_record_field);
+ if (!recordField) {
+ engrid_ENGrid.createHiddenInput(this.options.phone_record_field, "");
+ this.logger.log("Creating hidden field: " + this.options.phone_record_field);
+ }
}
- else {
- this.logger.log("No parent .en__component--column found for image:", img);
+ if (this.options.phone_date_field) {
+ const dateField = engrid_ENGrid.getField(this.options.phone_date_field);
+ if (!dateField) {
+ engrid_ENGrid.createHiddenInput(this.options.phone_date_field, "");
+ this.logger.log("Creating hidden field: " + this.options.phone_date_field);
+ }
}
- }
- setupMutationObserver() {
- if (!this.pageBackground || !window.MutationObserver) {
- if (!window.MutationObserver) {
- this.logger.log("MutationObserver not supported in this browser");
+ if (this.options.phone_status_field) {
+ const statusField = engrid_ENGrid.getField(this.options.phone_status_field);
+ if (!statusField) {
+ engrid_ENGrid.createHiddenInput(this.options.phone_status_field, "");
+ this.logger.log("Creating hidden field: " + this.options.phone_status_field);
}
+ }
+ }
+ createPhoneMarginVariable() {
+ var _a;
+ if (!this.options)
return;
+ const phone = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ if (phone) {
+ const phoneStyle = window.getComputedStyle(phone);
+ const marginTop = phoneStyle.marginTop;
+ const marginBottom = phoneStyle.marginBottom;
+ document.documentElement.style.setProperty("--tc-phone-margin-top", marginTop);
+ document.documentElement.style.setProperty("--tc-phone-margin-bottom", marginBottom);
}
- try {
- this.mutationObserver = new MutationObserver((mutations) => {
- let shouldReprocess = false;
- mutations.forEach((mutation) => {
- // Check if nodes were added or attributes changed
- if (mutation.type === "childList" || mutation.type === "attributes") {
- shouldReprocess = true;
+ }
+ addEventListeners() {
+ if (!this.options)
+ return;
+ // Add event listeners to fields
+ if (this.options.address_fields) {
+ for (const [key, value] of Object.entries(this.options.address_fields)) {
+ const field = engrid_ENGrid.getField(value);
+ if (!field)
+ continue;
+ field.addEventListener("change", () => {
+ this.logger.log("Changed " + field.name, true);
+ this.isDirty = true;
+ });
+ }
+ }
+ // Add event listener to submit
+ this._form.onSubmit.subscribe(this.callAPI.bind(this));
+ // Attach the API call event to the Give By Select to anticipate the use of Digital Wallets
+ const transactionGiveBySelect = document.getElementsByName("transaction.giveBySelect");
+ if (transactionGiveBySelect) {
+ transactionGiveBySelect.forEach((giveBySelect) => {
+ giveBySelect.addEventListener("change", () => {
+ if (["stripedigitalwallet", "paypaltouch"].includes(giveBySelect.value.toLowerCase())) {
+ this.logger.log("Clicked Digital Wallet Button");
+ window.setTimeout(() => {
+ this.callAPI();
+ }, 500);
}
});
- if (shouldReprocess) {
- this.logger.log("DOM changes detected in background section, reprocessing attribution classes");
- // Use a small delay to ensure all changes are complete
- setTimeout(() => {
- this.processAttributionPositioning();
- }, 100);
- }
- });
- // Start observing the background section
- this.mutationObserver.observe(this.pageBackground, {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ["class"],
});
- this.logger.log("MutationObserver set up for background section");
}
- catch (error) {
- this.logger.error("Error setting up MutationObserver:", error);
+ }
+ checkSum(str) {
+ return tidycontact_awaiter(this, void 0, void 0, function* () {
+ // encode as UTF-8
+ const msgBuffer = new TextEncoder().encode(str);
+ // hash the message
+ const hashBuffer = yield crypto.subtle.digest("SHA-256", msgBuffer);
+ // convert ArrayBuffer to Array
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ // convert bytes to hex string
+ const hashHex = hashArray
+ .map((b) => ("00" + b.toString(16)).slice(-2))
+ .join("");
+ return hashHex;
+ });
+ }
+ todaysDate() {
+ return new Date()
+ .toLocaleString("en-ZA", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ })
+ .replace(/\/+/g, ""); // Format date as YYYYMMDD
+ }
+ countryAllowed(country) {
+ var _a;
+ if (!this.options)
+ return false;
+ // If the country list is empty, allow all countries
+ if (!this.options.countries || this.options.countries.length === 0) {
+ return true;
}
+ return !!((_a = this.options.countries) === null || _a === void 0 ? void 0 : _a.includes(country.toLowerCase()));
}
- // Public method to manually trigger reprocessing
- reprocessAttributionPositioning() {
- this.logger.log("Manually reprocessing attribution positioning");
- this.processAttributionPositioning();
+ fetchTimeOut(url, params) {
+ const abort = new AbortController();
+ const signal = abort.signal;
+ params = Object.assign(Object.assign({}, params), { signal });
+ const promise = fetch(url, params);
+ if (signal)
+ signal.addEventListener("abort", () => abort.abort());
+ const timeout = setTimeout(() => abort.abort(), this.timeout * 1000);
+ return promise.finally(() => clearTimeout(timeout));
}
- /**
- * Clean up resources and observers
- */
- destroy() {
- if (this.mutationObserver) {
- this.mutationObserver.disconnect();
- this.mutationObserver = null;
- this.logger.log("MutationObserver disconnected");
+ writeError(error) {
+ if (!this.options)
+ return;
+ const recordField = engrid_ENGrid.getField(this.options.record_field);
+ const dateField = engrid_ENGrid.getField(this.options.date_field);
+ const statusField = engrid_ENGrid.getField(this.options.status_field);
+ if (recordField) {
+ let errorType = "";
+ switch (this.httpStatus) {
+ case 400:
+ errorType = "Bad Request";
+ break;
+ case 401:
+ errorType = "Unauthorized";
+ break;
+ case 403:
+ errorType = "Forbidden";
+ break;
+ case 404:
+ errorType = "Not Found";
+ break;
+ case 408:
+ errorType = "API Request Timeout";
+ break;
+ case 500:
+ errorType = "Internal Server Error";
+ break;
+ case 503:
+ errorType = "Service Unavailable";
+ break;
+ default:
+ errorType = "Unknown Error";
+ break;
+ }
+ const errorData = {
+ status: this.httpStatus,
+ error: typeof error === "string" ? error : errorType.toUpperCase(),
+ };
+ recordField.value = JSON.stringify(errorData);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "ERROR-API";
}
}
- setDataAttributes() {
- if (this.hasVideoBackground()) {
- return engrid_ENGrid.setBodyData("page-background", "video");
+ setFields(data) {
+ var _a, _b, _c, _d, _e;
+ if (!this.options || !this.options.address_enable)
+ return {};
+ let response = {};
+ const country = this.getCountry();
+ const postalCodeValue = engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.postalCode);
+ const zipDivider = (_b = this.options.us_zip_divider) !== null && _b !== void 0 ? _b : "+";
+ // Check if there's no address2 field
+ const address2Field = engrid_ENGrid.getField((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.address2);
+ if ("address2" in data && !address2Field) {
+ const address = engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.address1);
+ if (address == data.address1 + " " + data.address2) {
+ delete data.address1;
+ delete data.address2;
+ }
+ else {
+ data.address1 = data.address1 + " " + data.address2;
+ delete data.address2;
+ }
}
- if (this.hasImageBackground()) {
- return engrid_ENGrid.setBodyData("page-background", "image");
+ if ("postalCode" in data &&
+ postalCodeValue.replace("+", zipDivider) ===
+ data.postalCode.replace("+", zipDivider)) {
+ // Postal code is the same
+ delete data.postalCode;
}
- return engrid_ENGrid.setBodyData("page-background", "empty");
+ // Set the fields
+ for (const key in data) {
+ const fieldKey = this.options.address_fields &&
+ Object.keys(this.options.address_fields).includes(key)
+ ? this.options.address_fields[key]
+ : key;
+ const field = engrid_ENGrid.getField(fieldKey);
+ if (field) {
+ let value = data[key];
+ if (key === "postalCode" &&
+ ["US", "USA", "United States"].includes(country)) {
+ value = (_e = value.replace("+", zipDivider)) !== null && _e !== void 0 ? _e : ""; // Replace the "+" with the zip divider
+ }
+ response[key] = { from: field.value, to: value };
+ this.logger.log(`Set ${field.name} to ${value} (${field.value})`);
+ engrid_ENGrid.setFieldValue(fieldKey, value, false);
+ }
+ else {
+ this.logger.log(`Field ${key} not found`);
+ }
+ }
+ return response;
}
- hasVideoBackground() {
- if (!this.pageBackground) {
+ hasAddressFields() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options || !this.options.address_enable)
+ return false;
+ const address1 = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
+ const address2 = engrid_ENGrid.getField((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2);
+ const city = engrid_ENGrid.getField((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.city);
+ const region = engrid_ENGrid.getField((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.region);
+ const postalCode = engrid_ENGrid.getField((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.postalCode);
+ const country = engrid_ENGrid.getField((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.country);
+ return !!(address1 || address2 || city || region || postalCode || country);
+ }
+ canUseAPI() {
+ var _a, _b, _c, _d;
+ if (!this.options || !this.hasAddressFields())
return false;
+ const country = !!this.getCountry();
+ const address1 = !!engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
+ const city = !!engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.city);
+ const region = !!engrid_ENGrid.getFieldValue((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.region);
+ const postalCode = !!engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.postalCode);
+ if (country && address1) {
+ return (city && region) || postalCode;
}
- return !!this.pageBackground.querySelector("video");
+ this.logger.log("API cannot be used");
+ return false;
}
- hasImageBackground() {
- if (!this.pageBackground) {
+ canUsePhoneAPI() {
+ var _a;
+ if (!this.options)
return false;
+ if (this.phoneEnabled()) {
+ const phone = !!engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ const countryPhone = !!engrid_ENGrid.getFieldValue("tc.phone.country");
+ return phone && countryPhone;
}
- return (!this.hasVideoBackground() && !!this.pageBackground.querySelector("img"));
+ this.logger.log("Phone API is not enabled");
+ return false;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/neverbounce.js
-
-
-class NeverBounce {
- constructor(apiKey, dateField = null, statusField = null, dateFormat) {
- this.apiKey = apiKey;
- this.dateField = dateField;
- this.statusField = statusField;
- this.dateFormat = dateFormat;
- this.form = en_form_EnForm.getInstance();
- this.emailField = null;
- this.emailWrapper = document.querySelector(".en__field--emailAddress");
- this.nbDate = null;
- this.nbStatus = null;
- this.logger = new logger_EngridLogger("NeverBounce", "#039bc4", "#dfdfdf", "π§");
- this.shouldRun = true;
- this.nbLoaded = false;
- this.bypassEmails = [
- "noaddress.ea",
- ];
- this.neverBounceTimeout = engrid_ENGrid.getOption("NeverBounceTimeout") || 10000;
- this.neverBounceTimeoutFunc = null;
- const searchParams = new URLSearchParams(window.location.search);
- if (searchParams.has("bypassemailvalidation")) {
- this.logger.log("Bypass Email Validation Enabled - not running NeverBounce");
- return;
+ getCountry() {
+ var _a, _b;
+ if (!this.options)
+ return "";
+ const countryFallback = (_a = this.options.country_fallback) !== null && _a !== void 0 ? _a : "";
+ const country = engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.country);
+ return country || countryFallback.toUpperCase();
+ }
+ getCountryByCode(code) {
+ var _a;
+ const countryItem = (_a = this.countries_list.find((country) => country.includes(code))) !== null && _a !== void 0 ? _a : "";
+ if (countryItem) {
+ return {
+ name: countryItem[0],
+ code: countryItem[1],
+ dialCode: countryItem[2],
+ placeholder: countryItem[3],
+ };
}
- this.emailField = document.getElementById("en__field_supporter_emailAddress");
- window._NBSettings = {
- apiKey: this.apiKey,
- autoFieldHookup: false,
- inputLatency: 1500,
- displayPoweredBy: false,
- loadingMessage: "Validating...",
- softRejectMessage: "Invalid email",
- acceptedMessage: "Email validated!",
- feedback: false,
- // Set NB timeout 1 second than our timeout. Ensures NB response will always be before our timeout if there is not a server error.
- timeout: Math.floor((this.neverBounceTimeout - 1000) / 1000),
- };
- engrid_ENGrid.loadJS("https://cdn.neverbounce.com/widget/dist/NeverBounce.js");
- if (this.emailField) {
- if (this.emailField.value) {
- this.logger.log("E-mail Field Found");
- this.shouldRun = false;
+ return null;
+ }
+ phoneEnabled() {
+ return !!(this.options && this.options.phone_enable);
+ }
+ countryDropDownEnabled() {
+ return !!(this.options && this.options.phone_flags);
+ }
+ getCountryFromIP() {
+ return tidycontact_awaiter(this, void 0, void 0, function* () {
+ return fetch(`https://${window.location.hostname}/cdn-cgi/trace`)
+ .then((res) => res.text())
+ .then((t) => {
+ let data = t.replace(/[\r\n]+/g, '","').replace(/\=+/g, '":"');
+ data = '{"' + data.slice(0, data.lastIndexOf('","')) + '"}';
+ const jsondata = JSON.parse(data);
+ this.country_ip = jsondata.loc;
+ return this.country_ip;
+ });
+ });
+ }
+ renderFlagsDropDown() {
+ var _a;
+ if (!this.options)
+ return;
+ const phoneInput = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ if (!phoneInput)
+ return;
+ this.countries_dropdown = document.createElement("div");
+ this.countries_dropdown.classList.add("tc-flags-container");
+ const selectedFlag = document.createElement("div");
+ selectedFlag.classList.add("tc-selected-flag");
+ selectedFlag.setAttribute("role", "combobox");
+ selectedFlag.setAttribute("aria-haspopup", "listbox");
+ selectedFlag.setAttribute("aria-expanded", "false");
+ selectedFlag.setAttribute("aria-owns", "tc-flags-list");
+ selectedFlag.setAttribute("aria-label", "Select Country");
+ selectedFlag.setAttribute("tabindex", "0");
+ const seletedFlagInner = document.createElement("div");
+ seletedFlagInner.classList.add("tc-flag");
+ // seletedFlagInner.innerHTML = this.getFlagImage("us", "United States");
+ const flagArrow = document.createElement("div");
+ flagArrow.classList.add("tc-flag-arrow");
+ // flagArrow.innerHTML = "▼";
+ selectedFlag.appendChild(seletedFlagInner);
+ selectedFlag.appendChild(flagArrow);
+ selectedFlag.addEventListener("click", (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (selectedFlag.classList.contains("tc-open")) {
+ this.closeCountryDropDown();
+ }
+ else {
+ this.openCountryDropDown();
}
- this.emailField.addEventListener("change", (e) => {
- var _a;
- if (!this.nbLoaded) {
- this.shouldRun = true;
- this.init();
- if ((_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value) {
- setTimeout(function () {
- window._nb.fields
- .get(document.querySelector("[data-nb-id]"))[0]
- .forceUpdate();
- }, 100);
- }
+ });
+ const countryList = document.createElement("ul");
+ countryList.classList.add("tc-country-list");
+ countryList.classList.add("tc-hide");
+ countryList.setAttribute("id", "tc-country-list");
+ countryList.setAttribute("role", "listbox");
+ countryList.setAttribute("aria-label", "List of Countries");
+ countryList.setAttribute("aria-hidden", "true");
+ if (this.options.phone_preferred_countries.length > 0) {
+ const preferredCountries = [];
+ this.options.phone_preferred_countries.forEach((country) => {
+ const countryItem = this.getCountryByCode(country);
+ if (countryItem) {
+ preferredCountries.push(countryItem);
}
});
- window.setTimeout(() => {
- if (this.emailField && this.emailField.value) {
- this.logger.log("E-mail Filled Programatically");
- this.shouldRun = false;
- }
- this.init();
- }, 1000);
+ this.appendCountryItems(countryList, preferredCountries, "tc-country-list-item", true);
+ const divider = document.createElement("li");
+ divider.classList.add("tc-divider");
+ divider.setAttribute("role", "separator");
+ divider.setAttribute("aria-disabled", "true");
+ countryList.appendChild(divider);
+ this.logger.log("Rendering preferred countries", JSON.stringify(preferredCountries));
}
- this.form.onValidate.subscribe(this.validate.bind(this));
+ const countryListItems = [];
+ this.countries_list.forEach((country) => {
+ countryListItems.push({
+ name: country[0],
+ code: country[1],
+ dialCode: country[2],
+ placeholder: country[3],
+ });
+ });
+ this.appendCountryItems(countryList, countryListItems, "tc-country-list-item");
+ countryList.addEventListener("click", (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const target = e.target.closest("li");
+ if (target.classList.contains("tc-country-list-item")) {
+ const countryItem = this.getCountryByCode(target.getAttribute("data-country-code"));
+ if (countryItem) {
+ this.setPhoneCountry(countryItem);
+ }
+ }
+ });
+ countryList.addEventListener("mouseover", (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const target = e.target.closest("li.tc-country-list-item");
+ if (target) {
+ this.highlightCountry(target.getAttribute("data-country-code"));
+ }
+ });
+ this.countries_dropdown.appendChild(selectedFlag);
+ this.countries_dropdown.appendChild(countryList);
+ phoneInput.parentNode.insertBefore(this.countries_dropdown, phoneInput);
+ phoneInput.parentNode.classList.add("tc-has-country-flags");
+ this.countries_dropdown.addEventListener("keydown", (e) => {
+ var _a, _b;
+ const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
+ if (isDropdownHidden &&
+ ["ArrowUp", "Up", "ArrowDown", "Down", " ", "Enter"].indexOf(e.key) !==
+ -1) {
+ // prevent form from being submitted if "ENTER" was pressed
+ e.preventDefault();
+ // prevent event from being handled again by document
+ e.stopPropagation();
+ this.openCountryDropDown();
+ }
+ // allow navigation from dropdown to input on TAB
+ if (e.key === "Tab")
+ this.closeCountryDropDown();
+ });
+ document.addEventListener("keydown", (e) => {
+ var _a, _b;
+ const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
+ if (!isDropdownHidden) {
+ // prevent down key from scrolling the whole page,
+ // and enter key from submitting a form etc
+ e.preventDefault();
+ // up and down to navigate
+ if (e.key === "ArrowUp" ||
+ e.key === "Up" ||
+ e.key === "ArrowDown" ||
+ e.key === "Down")
+ this.handleUpDownKey(e.key);
+ // enter to select
+ else if (e.key === "Enter")
+ this.handleEnterKey();
+ // esc to close
+ else if (e.key === "Escape")
+ this.closeCountryDropDown();
+ }
+ });
+ document.addEventListener("click", (e) => {
+ var _a, _b;
+ const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
+ if (!isDropdownHidden &&
+ !e.target.closest(".tc-country-list")) {
+ this.closeCountryDropDown();
+ }
+ });
}
- init() {
- if (!this.shouldRun) {
- this.logger.log("Should Not Run");
- return;
- }
- if (this.nbLoaded) {
- this.logger.log("Already Loaded");
- return;
+ handleUpDownKey(key) {
+ var _a;
+ const highlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
+ if (highlightedCountry) {
+ let next = key === "ArrowUp" || key === "Up"
+ ? highlightedCountry.previousElementSibling
+ : highlightedCountry.nextElementSibling;
+ if (next) {
+ if (next.classList.contains("tc-divider")) {
+ next =
+ key === "ArrowUp" || key === "Up"
+ ? next.previousElementSibling
+ : next.nextElementSibling;
+ }
+ this.highlightCountry(next === null || next === void 0 ? void 0 : next.getAttribute("data-country-code"));
+ }
}
- this.logger.log("Init Function");
- if (this.dateField && document.getElementsByName(this.dateField).length)
- this.nbDate = document.querySelector("[name='" + this.dateField + "']");
- if (this.statusField && document.getElementsByName(this.statusField).length)
- this.nbStatus = document.querySelector("[name='" + this.statusField + "']");
- if (!this.emailField) {
- this.logger.log("E-mail Field Not Found");
- return;
+ }
+ handleEnterKey() {
+ var _a;
+ const highlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
+ if (highlightedCountry) {
+ const countryItem = this.getCountryByCode(highlightedCountry === null || highlightedCountry === void 0 ? void 0 : highlightedCountry.getAttribute("data-country-code"));
+ this.setPhoneCountry(countryItem);
}
- this.wrap(this.emailField, document.createElement("div"));
- const parentNode = this.emailField.parentNode;
- parentNode.id = "nb-wrapper";
- // Define HTML structure for a Custom NB Message and insert it after Email field
- const nbCustomMessageHTML = document.createElement("div");
- nbCustomMessageHTML.innerHTML =
- 'Enter a valid email.
';
- this.insertAfter(nbCustomMessageHTML, this.emailField);
- const NBClass = this;
- document.body.addEventListener("nb:registered", function (event) {
- const field = document.querySelector('[data-nb-id="' + event.detail.id + '"]');
- field.addEventListener("nb:loading", function (e) {
- engrid_ENGrid.disableSubmit("Validating Your Email");
- NBClass.setEmailStatus("loading");
- NBClass.clearTimeout();
- NBClass.neverBounceTimeoutFunc = setTimeout(() => {
- NBClass.setEmailStatus("unknown");
- if (NBClass.nbDate) {
- NBClass.nbDate.value = engrid_ENGrid.formatDate(new Date(), NBClass.dateFormat);
- }
- if (NBClass.nbStatus) {
- NBClass.nbStatus.value = "unknown";
- }
- engrid_ENGrid.enableSubmit();
- window._nb.fields.unregisterListener(NBClass.emailField);
- NBClass.nbLoaded = false;
- NBClass.logger.log("NeverBounce Timeout Reached. Bypassing validation, setting unknown status and removing NB.");
- }, NBClass.neverBounceTimeout);
- });
- // Never Bounce: Do work when input changes or when API responds with an error
- field.addEventListener("nb:clear", function (e) {
- if (!NBClass.nbLoaded)
- return;
- NBClass.clearTimeout();
- NBClass.setEmailStatus("clear");
- engrid_ENGrid.enableSubmit();
- if (NBClass.nbDate)
- NBClass.nbDate.value = "";
- if (NBClass.nbStatus)
- NBClass.nbStatus.value = "";
- });
- // Never Bounce: Do work when results have an input that does not look like an email (i.e. missing @ or no .com/.net/etc...)
- field.addEventListener("nb:soft-result", function (e) {
- if (!NBClass.nbLoaded)
- return;
- NBClass.clearTimeout();
- NBClass.setEmailStatus("soft-result");
- if (NBClass.nbDate)
- NBClass.nbDate.value = "";
- if (NBClass.nbStatus)
- NBClass.nbStatus.value = "";
- engrid_ENGrid.enableSubmit();
- });
- // Never Bounce: When results have been received
- field.addEventListener("nb:result", function (e) {
- if (!NBClass.nbLoaded)
- return;
- NBClass.clearTimeout();
- if (e.detail.result.is(window._nb.settings.getAcceptedStatusCodes())) {
- NBClass.setEmailStatus("valid");
- if (NBClass.nbDate)
- NBClass.nbDate.value = engrid_ENGrid.formatDate(new Date(), NBClass.dateFormat);
- if (NBClass.nbStatus)
- NBClass.nbStatus.value = (e).detail.result.response.result;
+ }
+ handlePhoneInputKeydown(e) {
+ const phoneInput = e.target;
+ const phoneNumber = phoneInput.value;
+ if (phoneNumber.charAt(0) === "+") {
+ if (phoneNumber.length > 2) {
+ const countryItem = this.getCountryByCode(phoneNumber.substring(1, 3));
+ if (countryItem) {
+ this.setPhoneCountry(countryItem);
}
else {
- NBClass.setEmailStatus("invalid");
- if (NBClass.nbDate)
- NBClass.nbDate.value = "";
- if (NBClass.nbStatus)
- NBClass.nbStatus.value = "";
+ this.setDefaultPhoneCountry();
}
- engrid_ENGrid.enableSubmit();
- });
- });
- // Never Bounce: Register field with the widget and broadcast nb:registration event
- window._nb.fields.registerListener(NBClass.emailField, true);
- this.nbLoaded = true;
+ }
+ }
}
- clearStatus() {
- if (!this.emailField) {
- this.logger.log("E-mail Field Not Found");
+ openCountryDropDown() {
+ if (!this.countries_dropdown)
return;
+ const countryList = this.countries_dropdown.querySelector(".tc-country-list");
+ const selectedFlag = this.countries_dropdown.querySelector(".tc-selected-flag");
+ if (countryList && selectedFlag) {
+ countryList.classList.remove("tc-hide");
+ selectedFlag.setAttribute("aria-expanded", "true");
+ selectedFlag.classList.add("tc-open");
}
- this.emailField.classList.remove("rm-error");
- // Search page for the NB Wrapper div and set as variable
- const nb_email_field_wrapper = (document.getElementById("nb-wrapper"));
- // Search page for the NB Feedback div and set as variable
- const nb_email_feedback_field = (document.getElementById("nb-feedback"));
- nb_email_field_wrapper.className = "";
- nb_email_feedback_field.className = "en__field__error nb-hidden";
- nb_email_feedback_field.innerHTML = "";
- this.emailWrapper.classList.remove("en__field--validationFailed");
- }
- deleteENFieldError() {
- const errorField = (document.querySelector(".en__field--emailAddress>div.en__field__error"));
- if (errorField)
- errorField.remove();
}
- setEmailStatus(status) {
- this.logger.log("Status:", status);
- if (!this.emailField) {
- this.logger.log("E-mail Field Not Found");
+ closeCountryDropDown() {
+ var _a;
+ if (!this.options)
return;
- }
- if (this.isBypassEmail()) {
- this.logger.log("Bypass email detected. Skipping status update.");
+ if (!this.countries_dropdown)
return;
+ const countryList = this.countries_dropdown.querySelector(".tc-country-list");
+ const selectedFlag = this.countries_dropdown.querySelector(".tc-selected-flag");
+ if (countryList && selectedFlag) {
+ countryList.classList.add("tc-hide");
+ selectedFlag.setAttribute("aria-expanded", "false");
+ selectedFlag.classList.remove("tc-open");
}
- // Search page for the NB Wrapper div and set as variable
- const nb_email_field_wrapper = (document.getElementById("nb-wrapper"));
- // Search page for the NB Feedback div and set as variable
- let nb_email_feedback_field = (document.getElementById("nb-feedback"));
- // classes to add or remove based on neverbounce results
- const nb_email_field_wrapper_success = "nb-success";
- const nb_email_field_wrapper_error = "nb-error";
- const nb_email_feedback_hidden = "nb-hidden";
- const nb_email_feedback_loading = "nb-loading";
- const nb_email_field_error = "rm-error";
- if (!nb_email_feedback_field) {
- const nbWrapperDiv = nb_email_field_wrapper.querySelector("div");
- if (nbWrapperDiv)
- nbWrapperDiv.innerHTML =
- 'Enter a valid email.
';
- nb_email_feedback_field = (document.getElementById("nb-feedback"));
- }
- if (status == "valid") {
- this.clearStatus();
- }
- else {
- nb_email_field_wrapper.classList.remove(nb_email_field_wrapper_success);
- nb_email_field_wrapper.classList.add(nb_email_field_wrapper_error);
- switch (status) {
- case "required": // special case status that we added ourselves -- doesn't come from NB
- this.deleteENFieldError();
- nb_email_feedback_field.innerHTML = "A valid email is required";
- nb_email_feedback_field.classList.remove(nb_email_feedback_loading);
- nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
- this.emailField.classList.add(nb_email_field_error);
- break;
- case "soft-result":
- if (this.emailField.value) {
- this.deleteENFieldError();
- nb_email_feedback_field.innerHTML = "Invalid email";
- nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
- this.emailField.classList.add(nb_email_field_error);
- }
- else {
- this.clearStatus();
- }
- break;
- case "invalid":
- this.deleteENFieldError();
- nb_email_feedback_field.innerHTML = "Invalid email";
- nb_email_feedback_field.classList.remove(nb_email_feedback_loading);
- nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
- this.emailField.classList.add(nb_email_field_error);
- break;
- case "loading":
- case "clear":
- default:
- this.clearStatus();
- break;
- }
- }
- }
- // Function to insert HTML after a DIV
- insertAfter(el, referenceNode) {
- var _a;
- (_a = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(el, referenceNode.nextSibling);
+ const phoneInput = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ phoneInput.focus();
}
- // to Wrap HTML around a DIV
- wrap(el, wrapper) {
- var _a;
- (_a = el.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, el);
- wrapper.appendChild(el);
+ getFlagImage(code, name) {
+ return `
+
+
+
+ `;
}
- isBypassEmail() {
- if (!this.emailField || !this.emailField.value)
- return false;
- const email = this.emailField.value.toLowerCase();
- return this.bypassEmails.some((bypassEmail) => email.includes(bypassEmail.toLowerCase()));
+ appendCountryItems(countryContainer, countries, className, preferred = false) {
+ let html = "";
+ // for each country
+ for (let i = 0; i < countries.length; i++) {
+ const c = countries[i];
+ const idSuffix = !!preferred ? "-preferred" : true && "" !== void 0 ? "" : "";
+ // open the list item
+ html += ``;
+ // add the flag
+ html += `${this.getFlagImage(c.code, c.name)}
`;
+ // and the country name and dial code
+ html += `${c.name} `;
+ html += `+${c.dialCode} `;
+ // close the list item
+ html += " ";
+ }
+ countryContainer.insertAdjacentHTML("beforeend", html);
}
- validate() {
+ setDefaultPhoneCountry() {
var _a;
- if (!this.form.validate)
- return;
- const nbResult = engrid_ENGrid.getFieldValue("nb-result");
- if (!this.emailField || !this.shouldRun || !this.nbLoaded || !nbResult) {
- this.logger.log("validate(): Should Not Run. Returning true.");
+ if (!this.options)
return;
- }
- if (this.isBypassEmail()) {
- this.logger.log("Bypass email detected. Skipping validation.");
+ // First, try to get the country from IP
+ if (this.options.phone_country_from_ip) {
+ this.getCountryFromIP()
+ .then((country) => {
+ this.logger.log("Country from IP:", country);
+ this.setPhoneCountry(this.getCountryByCode((country !== null && country !== void 0 ? country : "us").toLowerCase()));
+ })
+ .catch((error) => {
+ this.setPhoneCountry(this.getCountryByCode("us"));
+ });
return;
}
- if (this.nbStatus) {
- this.nbStatus.value = nbResult;
- }
- if (!["catchall", "unknown", "valid"].includes(nbResult)) {
- this.setEmailStatus("required");
- (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
- this.logger.log("NB-Result:", engrid_ENGrid.getFieldValue("nb-result"));
- this.form.validate = false;
- }
- }
- /**
- * Clears the backup timeout function if it exists.
- * @private
- */
- clearTimeout() {
- if (this.neverBounceTimeoutFunc) {
- clearTimeout(this.neverBounceTimeoutFunc);
- this.neverBounceTimeoutFunc = null;
+ // Then, get the default country Text
+ const countryField = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.country);
+ if (countryField) {
+ const countryText = countryField.options[countryField.selectedIndex].text;
+ // Then, get the country code from the Text
+ const countryData = this.getCountryByCode(countryText);
+ if (countryData) {
+ this.setPhoneCountry(countryData);
+ return;
+ }
+ else if (this.options.phone_preferred_countries.length > 0) {
+ // If no country code is found, use the first priority country
+ this.setPhoneCountry(this.getCountryByCode(this.options.phone_preferred_countries[0]));
+ return;
+ }
}
+ // If nothing works, GO USA!
+ this.setPhoneCountry(this.getCountryByCode("us"));
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/freshaddress.js
-// According to the FreshAddress documentation, you need to add the following code to your page:
-// jQuery library.
-//
-// FreshAddress client-side integration library
-//
-//
-// I know. jQuery. But it's not my fault. It's FreshAddress's fault.
-
-
-class FreshAddress {
- constructor() {
- var _a;
- this.form = en_form_EnForm.getInstance();
- this.emailField = null;
- this.emailWrapper = document.querySelector(".en__field--emailAddress");
- this.faDate = null;
- this.faStatus = null;
- this.faMessage = null;
- this.logger = new logger_EngridLogger("FreshAddress", "#039bc4", "#dfdfdf", "π§");
- this.shouldRun = true;
- this.options = engrid_ENGrid.getOption("FreshAddress");
- if (this.options === false ||
- (!window.FreshAddress && !((_a = this.options) === null || _a === void 0 ? void 0 : _a.proxyUrl))) {
+ setPhoneCountry(country) {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options || !country)
return;
- }
- this.emailField = document.getElementById("en__field_supporter_emailAddress");
- if (this.emailField) {
- this.createFields();
- this.addEventListeners();
- window.FreshAddressStatus = "idle";
- if (this.emailField.value) {
- this.logger.log("E-mail Field Found");
- this.shouldRun = false;
+ const countryInput = engrid_ENGrid.getField("tc.phone.country");
+ if (countryInput.value === country.code)
+ return;
+ const phoneInput = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ if (this.countryDropDownEnabled()) {
+ const selectedFlag = (_b = this.countries_dropdown) === null || _b === void 0 ? void 0 : _b.querySelector(".tc-selected-flag");
+ const flagElement = (_c = this.countries_dropdown) === null || _c === void 0 ? void 0 : _c.querySelector(".tc-flag");
+ if (selectedFlag && flagElement) {
+ flagElement.innerHTML = this.getFlagImage(country.code, country.name);
+ selectedFlag.setAttribute("data-country", country.code);
+ }
+ const currentSelectedCountry = (_d = this.countries_dropdown) === null || _d === void 0 ? void 0 : _d.querySelector(".tc-country-list-item[aria-selected='true']");
+ if (currentSelectedCountry) {
+ currentSelectedCountry.classList.remove("tc-selected");
+ currentSelectedCountry.setAttribute("aria-selected", "false");
+ }
+ const currentHighlightedCountry = (_e = this.countries_dropdown) === null || _e === void 0 ? void 0 : _e.querySelector(".tc-highlight");
+ if (currentHighlightedCountry) {
+ currentHighlightedCountry.classList.remove("tc-highlight");
+ }
+ const countryListItem = (_f = this.countries_dropdown) === null || _f === void 0 ? void 0 : _f.querySelector(`.tc-country-list-item[data-country-code='${country.code}']`);
+ if (countryListItem) {
+ countryListItem.classList.add("tc-selected");
+ countryListItem.setAttribute("aria-selected", "true");
+ countryListItem.classList.add("tc-highlight");
}
- window.setTimeout(() => {
- if (this.emailField && this.emailField.value) {
- this.logger.log("E-mail Filled Programatically");
- this.shouldRun = false;
- }
- }, 1000);
- }
- else {
- this.logger.log("E-mail Field Not Found");
+ if (selectedFlag === null || selectedFlag === void 0 ? void 0 : selectedFlag.classList.contains("tc-open"))
+ this.closeCountryDropDown();
}
+ phoneInput.setAttribute("placeholder", country.placeholder);
+ countryInput.value = country.code;
+ this.logger.log(`Setting phone country to ${country.code} - ${country.name}`);
}
- createFields() {
- if (!this.options)
+ highlightCountry(countryCode) {
+ var _a, _b;
+ if (!countryCode)
return;
- this.options.dateField = this.options.dateField || "fa_date";
- this.faDate = engrid_ENGrid.getField(this.options.dateField);
- if (!this.faDate) {
- this.logger.log("Date Field Not Found. Creating...");
- engrid_ENGrid.createHiddenInput(this.options.dateField, "");
- this.faDate = engrid_ENGrid.getField(this.options.dateField);
- }
- this.options.statusField = this.options.statusField || "fa_status";
- this.faStatus = engrid_ENGrid.getField(this.options.statusField);
- if (!this.faStatus) {
- this.logger.log("Status Field Not Found. Creating...");
- engrid_ENGrid.createHiddenInput(this.options.statusField, "");
- this.faStatus = engrid_ENGrid.getField(this.options.statusField);
+ const currentHighlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
+ if (currentHighlightedCountry) {
+ currentHighlightedCountry.classList.remove("tc-highlight");
}
- this.options.messageField = this.options.messageField || "fa_message";
- this.faMessage = engrid_ENGrid.getField(this.options.messageField);
- if (!this.faMessage) {
- this.logger.log("Message Field Not Found. Creating...");
- engrid_ENGrid.createHiddenInput(this.options.messageField, "");
- this.faMessage = engrid_ENGrid.getField(this.options.messageField);
+ const countryList = (_b = this.countries_dropdown) === null || _b === void 0 ? void 0 : _b.querySelector(".tc-country-list");
+ if (countryList) {
+ const country = countryList.querySelector(`.tc-country[data-country-code='${countryCode}']`);
+ if (country) {
+ country.classList.add("tc-highlight");
+ country.scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ inline: "nearest",
+ });
+ }
}
}
- writeToFields(status, message) {
- if (!this.options)
- return;
- this.faDate.value = engrid_ENGrid.formatDate(new Date(), this.options.dateFieldFormat || "yyyy-MM-dd");
- this.faStatus.value = status;
- this.faMessage.value = message;
- this.emailWrapper.dataset.freshaddressSafetosendstatus =
- status.toLowerCase();
- }
- addEventListeners() {
+ setPhoneDataFromAPI(data, id) {
var _a;
- if (!this.options)
- return;
- // Add event listeners to fields
- (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.addEventListener("change", () => {
- var _a, _b;
- if (!this.shouldRun ||
- ((_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value.includes("@4sitestudios.com"))) {
- engrid_ENGrid.removeError(this.emailWrapper);
- this.writeToFields("Valid", "Skipped");
- this.logger.log("Skipping E-mail Validation");
+ return tidycontact_awaiter(this, void 0, void 0, function* () {
+ if (!this.options)
return;
- }
- this.logger.log("Validating " + ((_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value));
- if (this.options && this.options.proxyUrl) {
- this.callProxy();
+ const phoneField = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ const recordField = engrid_ENGrid.getField(this.options.phone_record_field);
+ const dateField = engrid_ENGrid.getField(this.options.phone_date_field);
+ const statusField = engrid_ENGrid.getField(this.options.phone_status_field);
+ let record = {};
+ record["formData"] = { [phoneField.name]: phoneField.value };
+ record["formatted"] = data.formatted;
+ record["number_type"] = data.number_type;
+ if (data.valid === true) {
+ if (phoneField.value !== data.formatted.e164) {
+ record["phone"] = {
+ from: phoneField.value,
+ to: data.formatted.e164,
+ };
+ phoneField.value = data.formatted.e164;
+ }
+ yield this.checkSum(JSON.stringify(record)).then((checksum) => {
+ this.logger.log("Phone Checksum", checksum);
+ record["requestId"] = id; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if (recordField) {
+ record = Object.assign({ date: this.todaysDate(), status: "SUCCESS" }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "SUCCESS";
+ }
}
else {
- this.callAPI();
+ yield this.checkSum(JSON.stringify(record)).then((checksum) => {
+ this.logger.log("Phone Checksum", checksum);
+ record["requestId"] = id; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if (recordField) {
+ record = Object.assign({ date: this.todaysDate(), status: "ERROR" }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value =
+ "error" in data ? `ERROR: ` + data.error : "INVALIDPHONE";
+ }
}
});
- // Add event listener to submit
- this.form.onValidate.subscribe(this.validate.bind(this));
}
callAPI() {
- var _a;
- if (!this.options || !window.FreshAddress)
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options)
return;
- if (!this.shouldRun)
+ if (!this.isDirty || this.wasCalled)
+ return;
+ if (!this._form.submit) {
+ this.logger.log("Form Submission Interrupted by Other Component");
return;
- window.FreshAddressStatus = "validating";
- const email = (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value;
- const options = { emps: false, rtc_timeout: 1200 };
- const ret = window.FreshAddress.validateEmail(email, options).then((response) => {
- this.logger.log("Validate API Response", JSON.parse(JSON.stringify(response)));
- return this.validateResponse(response);
- });
- }
- validateResponse(data) {
- var _a;
- /* ERROR HANDLING: Let through in case of a service error. Enable form submission. */
- if (data.isServiceError()) {
- this.logger.log("Service Error");
- this.writeToFields("Service Error", data.getErrorResponse());
- return true;
}
- /* CHECK RESULT: */
- if (data.isValid()) {
- // Set response message. No action required.
- this.writeToFields("Valid", data.getComment());
- engrid_ENGrid.removeError(this.emailWrapper);
- if (data.hasSuggest()) {
- // Valid, with Suggestion
- engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
- this.emailField.value = data.getSuggEmail();
+ const recordField = engrid_ENGrid.getField(this.options.record_field);
+ const dateField = engrid_ENGrid.getField(this.options.date_field);
+ const statusField = engrid_ENGrid.getField(this.options.status_field);
+ const latitudeField = engrid_ENGrid.getField("supporter.geo.latitude");
+ const longitudeField = engrid_ENGrid.getField("supporter.geo.longitude");
+ if (!this.canUseAPI() && !this.canUsePhoneAPI()) {
+ this.logger.log("Not Enough Data to Call API");
+ if (dateField) {
+ dateField.value = this.todaysDate();
}
- }
- else if (data.isError()) {
- // Error Condition 1 - the service should always respond with finding E/W/V
- this.writeToFields("Invalid", data.getErrorResponse());
- engrid_ENGrid.setError(this.emailWrapper, data.getErrorResponse());
- (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
- if (data.hasSuggest()) {
- // Error, with Suggestion
- engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
- this.emailField.value = data.getSuggEmail();
- this.writeToFields("Error", data.getErrorResponse());
+ if (statusField) {
+ statusField.value = "PARTIALADDRESS";
}
+ return true;
}
- else if (data.isWarning()) {
- this.writeToFields("Invalid", data.getErrorResponse());
- engrid_ENGrid.setError(this.emailWrapper, data.getErrorResponse());
- if (data.hasSuggest()) {
- // Warning, with Suggestion
- engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
- this.emailField.value = data.getSuggEmail();
- this.writeToFields("Warning", data.getErrorResponse());
+ // Call the API
+ const address1 = engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
+ const address2 = engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2);
+ const city = engrid_ENGrid.getFieldValue((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.city);
+ const region = engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.region);
+ const postalCode = engrid_ENGrid.getFieldValue((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.postalCode);
+ const country = this.getCountry();
+ if (!this.countryAllowed(country)) {
+ this.logger.log("Country not allowed: " + country);
+ if (recordField) {
+ let record = {};
+ record = Object.assign({ date: this.todaysDate(), status: "DISALLOWED" }, record);
+ recordField.value = JSON.stringify(record);
}
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "DISALLOWED";
+ }
+ return true;
}
- else {
- // Error Condition 2 - the service should always respond with finding E/W/V
- this.writeToFields("API Error", "Unknown Error");
- }
- window.FreshAddressStatus = "idle";
- engrid_ENGrid.enableSubmit();
- }
- validate() {
- var _a;
- engrid_ENGrid.removeError(this.emailWrapper);
- if (!this.form.validate)
- return;
- if (!this.options) {
- this.form.validate = true;
- return;
- }
- if (!this.shouldRun) {
- this.form.validate = true;
- return;
- }
- if (window.FreshAddressStatus === "validating") {
- this.logger.log("Waiting for API Response");
- // Self resolving Promise that waits 1000ms
- const wait = new Promise((resolve, reject) => {
- setTimeout(() => {
- var _a;
- const status = this.faStatus.value;
- if (status === "" || status === "Invalid") {
- this.logger.log("Promise Rejected");
- (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
- reject(false);
- return;
- }
- this.logger.log("Promise Resolved");
- resolve(true);
- }, 700);
+ let formData = {
+ url: window.location.href,
+ cid: this.options.cid,
+ };
+ if (this.canUseAPI()) {
+ formData = Object.assign(formData, {
+ address1,
+ address2,
+ city,
+ region,
+ postalCode,
+ country,
});
- this.form.validatePromise = wait;
- return;
- }
- else if (this.faStatus.value === "Invalid") {
- this.form.validate = false;
- window.setTimeout(() => {
- engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
- }, 100);
- (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
- engrid_ENGrid.enableSubmit();
- return false;
}
- this.form.validate = true;
- return true;
- }
- callProxy() {
- var _a, _b;
- if (!this.options || !this.shouldRun)
- return;
- window.FreshAddressStatus = "validating";
- engrid_ENGrid.disableSubmit("Validating Email Address...");
- // Before calling the API, do a basic check to see if the email is in a valid format.
- // This is to prevent unnecessary API calls.
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
- if (!emailRegex.test(this.emailField.value)) {
- this.logger.log("Invalid Email Format from Basic Check");
- this.writeToFields("Invalid", "Invalid Email Format");
- engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
- (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
- engrid_ENGrid.enableSubmit();
- return;
+ if (this.canUsePhoneAPI()) {
+ formData.phone = engrid_ENGrid.getFieldValue((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.phone);
+ formData.phoneCountry = engrid_ENGrid.getFieldValue("tc.phone.country");
}
- fetch(this.options.proxyUrl, {
+ this.wasCalled = true;
+ this.logger.log("FormData", JSON.parse(JSON.stringify(formData)));
+ const ret = this.fetchTimeOut(this.endpoint, {
+ headers: { "Content-Type": "application/json; charset=utf-8" },
method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ email: (_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value }),
- signal: AbortSignal.timeout(5000),
+ body: JSON.stringify(formData),
})
.then((response) => {
- if (!response.ok) {
- throw new Error(`HTTP error ${response.status}`);
- }
+ this.httpStatus = response.status;
return response.json();
})
- .then((data) => {
- this.logger.log("Proxy API Response", data);
- this.validateProxyResponse(data);
- })
+ .then((data) => tidycontact_awaiter(this, void 0, void 0, function* () {
+ this.logger.log("callAPI response", JSON.parse(JSON.stringify(data)));
+ if (data.valid === true) {
+ let record = {};
+ if ("changed" in data) {
+ record = this.setFields(data.changed);
+ }
+ record["formData"] = formData;
+ yield this.checkSum(JSON.stringify(record)).then((checksum) => {
+ this.logger.log("Checksum", checksum);
+ record["requestId"] = data.requestId; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if ("latitude" in data) {
+ latitudeField.value = data.latitude;
+ record["latitude"] = data.latitude;
+ }
+ if ("longitude" in data) {
+ longitudeField.value = data.longitude;
+ record["longitude"] = data.longitude;
+ }
+ if (recordField) {
+ record = Object.assign({ date: this.todaysDate(), status: "SUCCESS" }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "SUCCESS";
+ }
+ }
+ else {
+ let record = {};
+ record["formData"] = formData;
+ yield this.checkSum(JSON.stringify(record)).then((checksum) => {
+ this.logger.log("Checksum", checksum);
+ record["requestId"] = data.requestId; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if (recordField) {
+ record = Object.assign({ date: this.todaysDate(), status: "ERROR" }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value =
+ "error" in data ? `ERROR: ` + data.error : "INVALIDADDRESS";
+ }
+ }
+ if (this.phoneEnabled() && "phone" in data) {
+ yield this.setPhoneDataFromAPI(data.phone, data.requestId);
+ }
+ }))
.catch((error) => {
- // 422 (Unprocessable Content) - This means the email is in an invalid format.
- if (error.message.includes("422")) {
- this.logger.log("Invalid Email Format");
- this.writeToFields("Invalid", "Invalid Email Format");
- engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
- return;
+ if (error.toString().includes("AbortError")) {
+ // fetch aborted due to timeout
+ this.logger.log("Fetch aborted");
+ this.httpStatus = 408;
}
- if (error.name === "AbortError") {
- this.logger.log("Proxy API request timed out");
- this.writeToFields("Request Timeout", "The request took too long.");
+ // network error or json parsing error
+ this.writeError(error);
+ });
+ this._form.submitPromise = ret;
+ return ret;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/live-currency.js
+// This script enables live currency symbol and code to the page.
+
+class LiveCurrency {
+ constructor() {
+ this.logger = new logger_EngridLogger("LiveCurrency", "#1901b1", "#feb47a", "π²");
+ this.elementsFound = false;
+ this.isUpdating = false;
+ this._amount = DonationAmount.getInstance();
+ this._frequency = DonationFrequency.getInstance();
+ this._fees = ProcessingFees.getInstance();
+ this.searchElements();
+ if (!this.shouldRun())
+ return;
+ engrid_ENGrid.setBodyData("live-currency", "active");
+ this.updateCurrency();
+ this.addEventListeners();
+ // Make labels visible on page load
+ document
+ .querySelectorAll(".en__field--donationAmt .en__field__element--radio .en__field__item")
+ .forEach((node) => {
+ node.setAttribute("data-engrid-currency-symbol-updated", "true");
+ });
+ }
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field label,
+ .en__submit
+ `);
+ if (enElements.length > 0) {
+ this.elementsFound = true;
+ const currency = engrid_ENGrid.getCurrencySymbol();
+ const currencyCode = engrid_ENGrid.getCurrencyCode();
+ const currencyElement = `${currency} `;
+ const currencyCodeElement = `${currencyCode} `;
+ enElements.forEach((item) => {
+ // If item starts with
+//
+// This will override the default CustomCurrency options for that page.
+//
-class ProgressBar {
+class CustomCurrency {
constructor() {
- var _a, _b;
- const progressIndicator = document.querySelector("span[data-engrid-progress-indicator]");
- const pageCount = engrid_ENGrid.getPageCount();
- const pageNumber = engrid_ENGrid.getPageNumber();
- if (!progressIndicator || !pageCount || !pageNumber) {
+ this.logger = new logger_EngridLogger("CustomCurrency", "#1901b1", "#00cc95", "π€");
+ this.currencyElement = document.querySelector("[name='transaction.paycurrency']");
+ this._country = Country.getInstance();
+ if (!this.shouldRun())
return;
+ this.addEventListeners();
+ this.loadCurrencies();
+ }
+ shouldRun() {
+ // Only run if the currency field is present, and the CustomCurrency option is not false
+ if (!this.currencyElement || !engrid_ENGrid.getOption("CustomCurrency")) {
+ return false;
}
- let maxValue = (_a = progressIndicator.getAttribute("max")) !== null && _a !== void 0 ? _a : 100;
- if (typeof maxValue === "string")
- maxValue = parseInt(maxValue);
- let amountValue = (_b = progressIndicator.getAttribute("amount")) !== null && _b !== void 0 ? _b : 0;
- if (typeof amountValue === "string")
- amountValue = parseInt(amountValue);
- const prevPercentage = pageNumber === 1
- ? 0
- : Math.ceil(((pageNumber - 1) / pageCount) * maxValue);
- let percentage = pageNumber === 1 ? 0 : Math.ceil((pageNumber / pageCount) * maxValue);
- const scalePrev = prevPercentage / 100;
- let scale = percentage / 100;
- if (amountValue) {
- percentage =
- Math.ceil(amountValue) > Math.ceil(maxValue) ? maxValue : amountValue;
- scale = percentage / 100;
- }
- progressIndicator.innerHTML = `
-
-
- ${percentage}%
-
`;
- if (percentage !== prevPercentage) {
- const progress = document.querySelector(".indicator__progress");
- requestAnimationFrame(function () {
- progress.style.transform = `scaleX(${scale})`;
+ return true;
+ }
+ addEventListeners() {
+ if (this._country.countryField) {
+ this._country.onCountryChange.subscribe((country) => {
+ this.loadCurrencies(country);
});
}
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/remember-me.js
-
-
-const remember_me_tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
-class RememberMe {
- constructor(options) {
- this._form = en_form_EnForm.getInstance();
- this._events = RememberMeEvents.getInstance();
- this.iframe = null;
- this.remoteUrl = options.remoteUrl ? options.remoteUrl : null;
- this.cookieName = options.cookieName
- ? options.cookieName
- : "engrid-autofill";
- this.cookieExpirationDays = options.cookieExpirationDays
- ? options.cookieExpirationDays
- : 365;
- this.rememberMeOptIn = options.checked ? options.checked : false;
- this.fieldNames = options.fieldNames ? options.fieldNames : [];
- this.fieldDonationAmountRadioName = options.fieldDonationAmountRadioName
- ? options.fieldDonationAmountRadioName
- : "transaction.donationAmt";
- this.fieldDonationAmountOtherName = options.fieldDonationAmountOtherName
- ? options.fieldDonationAmountOtherName
- : "transaction.donationAmt.other";
- this.fieldDonationRecurrPayRadioName =
- options.fieldDonationRecurrPayRadioName
- ? options.fieldDonationRecurrPayRadioName
- : "transaction.recurrpay";
- this.fieldDonationAmountOtherCheckboxID =
- options.fieldDonationAmountOtherCheckboxID
- ? options.fieldDonationAmountOtherCheckboxID
- : "#en__field_transaction_donationAmt4";
- this.fieldOptInSelectorTarget = options.fieldOptInSelectorTarget
- ? options.fieldOptInSelectorTarget
- : ".en__field--emailAddress.en__field";
- this.fieldOptInSelectorTargetLocation =
- options.fieldOptInSelectorTargetLocation
- ? options.fieldOptInSelectorTargetLocation
- : "after";
- this.fieldClearSelectorTarget = options.fieldClearSelectorTarget
- ? options.fieldClearSelectorTarget
- : 'label[for="en__field_supporter_firstName"]';
- this.fieldClearSelectorTargetLocation =
- options.fieldClearSelectorTargetLocation
- ? options.fieldClearSelectorTargetLocation
- : "before";
- this.fieldData = {};
- if (this.useRemote()) {
- this.createIframe(() => {
- if (this.iframe && this.iframe.contentWindow) {
- this.iframe.contentWindow.postMessage(JSON.stringify({ key: this.cookieName, operation: "read" }), "*");
- this._form.onSubmit.subscribe(() => {
- if (this.rememberMeOptIn) {
- this.readFields();
- this.saveCookieToRemote();
- }
- });
- }
- }, (event) => {
- let data;
- if (event.data &&
- typeof event.data === "string" &&
- this.isJson(event.data)) {
- data = JSON.parse(event.data);
- }
- if (data &&
- data.key &&
- data.value !== undefined &&
- data.key === this.cookieName) {
- this.updateFieldData(data.value);
- this.writeFields();
- let hasFieldData = Object.keys(this.fieldData).length > 0;
- if (!hasFieldData) {
- this.insertRememberMeOptin();
- }
- else {
- this.insertClearRememberMeLink();
- }
- }
- });
+ // Changes the options in the currency field to match the selected country options
+ loadCurrencies(country = "default") {
+ const options = engrid_ENGrid.getOption("CustomCurrency");
+ if (!options)
+ return;
+ const label = options.label || `Give with [$$$]`;
+ let currencies = options.default;
+ if (options.countries && options.countries[country]) {
+ currencies = options.countries[country];
}
- else {
- this.readCookie();
- let hasFieldData = Object.keys(this.fieldData).length > 0;
- if (!hasFieldData) {
- this.insertRememberMeOptin();
- this.rememberMeOptIn = false;
- }
- else {
- this.insertClearRememberMeLink();
- this.rememberMeOptIn = true;
- }
- this.writeFields();
- this._form.onSubmit.subscribe(() => {
- if (this.rememberMeOptIn) {
- this.readFields();
- this.saveCookie();
- }
- });
+ if (!currencies) {
+ this.logger.log(`No currencies found for ${country}`);
+ return;
}
- }
- updateFieldData(jsonData) {
- if (jsonData) {
- let data = JSON.parse(jsonData);
- for (let i = 0; i < this.fieldNames.length; i++) {
- if (data[this.fieldNames[i]] !== undefined) {
- this.fieldData[this.fieldNames[i]] = decodeURIComponent(data[this.fieldNames[i]]);
- }
- }
+ this.logger.log(`Loading currencies for ${country}`);
+ this.currencyElement.innerHTML = "";
+ for (const currency in currencies) {
+ const option = document.createElement("option");
+ option.value = currency;
+ option.text = label
+ .replace("[$$$]", currency)
+ .replace("[$]", currencies[currency]);
+ option.setAttribute("data-currency-code", currency);
+ option.setAttribute("data-currency-symbol", currencies[currency]);
+ this.currencyElement.appendChild(option);
}
+ // Set the currency to the first option and trigger a change event
+ this.currencyElement.selectedIndex = 0;
+ const event = new Event("change", { bubbles: true });
+ this.currencyElement.dispatchEvent(event);
}
- insertClearRememberMeLink() {
- let clearRememberMeField = document.getElementById("clear-autofill-data");
- if (!clearRememberMeField) {
- const clearAutofillLabel = "clear autofill";
- clearRememberMeField = document.createElement("a");
- clearRememberMeField.setAttribute("id", "clear-autofill-data");
- clearRememberMeField.classList.add("label-tooltip");
- clearRememberMeField.setAttribute("style", "cursor: pointer;");
- clearRememberMeField.innerHTML = `(${clearAutofillLabel})`;
- const targetField = this.getElementByFirstSelector(this.fieldClearSelectorTarget);
- if (targetField) {
- if (this.fieldClearSelectorTargetLocation === "after") {
- targetField.appendChild(clearRememberMeField);
- }
- else {
- targetField.prepend(clearRememberMeField);
- }
- }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/autosubmit.js
+// Automatically submits the page if a URL argument is present
+
+class Autosubmit {
+ constructor() {
+ this.logger = new logger_EngridLogger("Autosubmit", "#f0f0f0", "#ff0000", "π");
+ this._form = en_form_EnForm.getInstance();
+ if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
+ !window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed() &&
+ engrid_ENGrid.getUrlParameter("autosubmit") === "Y") {
+ this.logger.log("Autosubmitting Form");
+ // Fix EN ?chain parameter not working with email addresses with + in them
+ engrid_ENGrid.setFieldValue("supporter.emailAddress", engrid_ENGrid.getFieldValue("supporter.emailAddress").replace(/\s/g, "+"));
+ this._form.submitForm();
}
- clearRememberMeField.addEventListener("click", (e) => {
- e.preventDefault();
- this.clearFields(["supporter.country" /*, 'supporter.emailAddress'*/]);
- if (this.useRemote()) {
- this.clearCookieOnRemote();
- }
- else {
- this.clearCookie();
- }
- let clearAutofillLink = document.getElementById("clear-autofill-data");
- if (clearAutofillLink) {
- clearAutofillLink.style.display = "none";
- }
- this.rememberMeOptIn = false;
- this._events.dispatchClear();
- window.dispatchEvent(new CustomEvent("RememberMe_Cleared"));
- });
- this._events.dispatchLoad(true);
- window.dispatchEvent(new CustomEvent("RememberMe_Loaded", { detail: { withData: true } }));
}
- getElementByFirstSelector(selectorsString) {
- // iterate through the selectors until we find one that exists
- let targetField = null;
- const selectorTargets = selectorsString.split(",");
- for (let i = 0; i < selectorTargets.length; i++) {
- targetField = document.querySelector(selectorTargets[i]);
- if (targetField) {
- break;
- }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/event-tickets.js
+class EventTickets {
+ constructor() {
+ // --------------------------------------------
+ // Format ticket amounts as currency.
+ const ticketCostElements = document.getElementsByClassName("en__ticket__field--cost");
+ const ticketCurrencyElements = document.getElementsByClassName("en__ticket__currency");
+ for (const ticketCurrencyElement of ticketCurrencyElements) {
+ ticketCurrencyElement.classList.add("en__ticket__currency__hidden");
}
- return targetField;
- }
- insertRememberMeOptin() {
- let rememberMeOptInField = document.getElementById("remember-me-opt-in");
- if (!rememberMeOptInField) {
- const rememberMeLabel = "Remember Me";
- const rememberMeInfo = `
- Check βRemember meβ to complete forms on this device faster.
- While your financial information wonβt be stored, you should only check this box from a personal device.
- Click βClear autofillβ to remove the information from your device at any time.
- `;
- const rememberMeOptInFieldChecked = this.rememberMeOptIn ? "checked" : "";
- const rememberMeOptInField = document.createElement("div");
- rememberMeOptInField.classList.add("en__field", "en__field--checkbox", "en__field--question", "rememberme-wrapper");
- rememberMeOptInField.setAttribute("id", "remember-me-opt-in");
- rememberMeOptInField.setAttribute("style", "overflow-x: hidden;");
- rememberMeOptInField.innerHTML = `
-
-
-
-
-
- ${rememberMeLabel}
-
-
-
-
-
-
-
- `;
- const targetField = this.getElementByFirstSelector(this.fieldOptInSelectorTarget);
- if (targetField && targetField.parentNode) {
- targetField.parentNode.insertBefore(rememberMeOptInField, this.fieldOptInSelectorTargetLocation == "before"
- ? targetField
- : targetField.nextSibling);
- const rememberMeCheckbox = document.getElementById("remember-me-checkbox");
- if (rememberMeCheckbox) {
- rememberMeCheckbox.addEventListener("change", () => {
- if (rememberMeCheckbox.checked) {
- this.rememberMeOptIn = true;
- }
- else {
- this.rememberMeOptIn = false;
- }
- });
- }
- remember_me_tippy("#rememberme-learn-more-toggle", { content: rememberMeInfo });
+ for (const ticketCostElement of ticketCostElements) {
+ const ticketAmountElement = ticketCostElement.getElementsByClassName("en__ticket__price")[0];
+ const ticketCurrencyElement = ticketCostElement.getElementsByClassName("en__ticket__currency")[0];
+ const formatterOptions = {
+ style: "currency",
+ currency: ticketCurrencyElement.innerText,
+ };
+ let ticketAmountAsCurrency = Intl.NumberFormat(undefined, formatterOptions).format(Number(ticketAmountElement.innerText));
+ if (ticketAmountAsCurrency.slice(-3) === ".00") {
+ ticketAmountAsCurrency = ticketAmountAsCurrency.slice(0, -3);
}
+ ticketAmountElement.innerText = ticketAmountAsCurrency;
}
- else if (this.rememberMeOptIn) {
- rememberMeOptInField.checked = true;
- }
- this._events.dispatchLoad(false);
- window.dispatchEvent(new CustomEvent("RememberMe_Loaded", { detail: { withData: false } }));
- }
- useRemote() {
- return (!!this.remoteUrl &&
- typeof window.postMessage === "function" &&
- window.JSON &&
- window.localStorage);
- }
- createIframe(iframeLoaded, messageReceived) {
- if (this.remoteUrl) {
- let iframe = document.createElement("iframe");
- iframe.style.cssText =
- "position:absolute;width:1px;height:1px;left:-9999px;";
- iframe.src = this.remoteUrl;
- iframe.setAttribute("sandbox", "allow-same-origin allow-scripts");
- iframe.setAttribute("title", "Remember Me iframe");
- this.iframe = iframe;
- document.body.appendChild(this.iframe);
- this.iframe.addEventListener("load", () => iframeLoaded(), false);
- window.addEventListener("message", (event) => {
- var _a;
- if (((_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) === event.source) {
- messageReceived(event);
- }
- }, false);
- }
- }
- clearCookie() {
- this.fieldData = {};
- this.saveCookie();
}
- clearCookieOnRemote() {
- this.fieldData = {};
- this.saveCookieToRemote();
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/swap-amounts.js
+// This script allows you to override the default donation amounts in Engaging Networks
+// with a custom list of amounts.
+// If the URL contains a query parameter "engrid-amounts" with a comma separated values, the script will load the
+// amounts from the parameter and set them as the default amounts for the donation
+// form.
+/**
+ * Example:
+ * window.EngridAmounts = {
+ * "onetime": {
+ * amounts: {
+ * "10": 10,
+ * "30": 30,
+ * "50": 50,
+ * "100": 100,
+ * "Other": "other",
+ * },
+ * default: 30,
+ * stickyDefault: false, // Optional. When true, every swap forces the default amount to be (re)selected
+ * },
+ * "monthly": {
+ * amounts: {
+ * "5": 5,
+ * "15": 15,
+ * "25": 25,
+ * "30": 30,
+ * "Other": "other",
+ * },
+ * default: 15,
+ * stickyDefault: true, // Example forcing default on each frequency swap
+ * },
+ * };
+ */
+
+class SwapAmounts {
+ constructor() {
+ this.logger = new logger_EngridLogger("SwapAmounts", "purple", "white", "π°");
+ this._amount = DonationAmount.getInstance();
+ this._frequency = DonationFrequency.getInstance();
+ this.defaultChange = false; // Tracks if user changed away from default after swap
+ this.swapped = false; // Tracks if we've already executed at least one swap
+ this.loadAmountsFromUrl();
+ if (!this.shouldRun())
+ return;
+ // Respond when frequency changes
+ this._frequency.onFrequencyChange.subscribe(() => this.swapAmounts());
+ // Track if donor moves away from the swapped default amount
+ this._amount.onAmountChange.subscribe(() => {
+ const configs = window.EngridAmounts;
+ if (!configs)
+ return;
+ const freq = this._frequency.frequency;
+ if (!(freq in configs))
+ return;
+ if (!this.swapped)
+ return; // ignore early changes before initial swap
+ const currentConfig = configs[freq];
+ this.defaultChange = this._amount.amount !== currentConfig.default;
+ });
}
- saveCookieToRemote() {
- if (this.iframe && this.iframe.contentWindow) {
- this.iframe.contentWindow.postMessage(JSON.stringify({
- key: this.cookieName,
- value: this.fieldData,
- operation: "write",
- expires: this.cookieExpirationDays,
- }), "*");
+ loadAmountsFromUrl() {
+ const urlParams = new URLSearchParams(window.location.search);
+ const amounts = urlParams.get("engrid-amounts");
+ if (amounts) {
+ this.defaultChange = true; // if amounts come from URL, treat as user-set
+ const amountArray = amounts
+ .split(",")
+ .map((amt) => amt.trim())
+ .filter(Boolean);
+ if (!amountArray.length)
+ return;
+ const urlDefaultParam = engrid_ENGrid.getUrlParameter("transaction.donationAmt");
+ const parsedFirst = parseFloat(amountArray[0]);
+ const defaultAmount = (urlDefaultParam && parseFloat(urlDefaultParam)) ||
+ parsedFirst;
+ const amountsObj = {};
+ amountArray.forEach((raw) => {
+ const numeric = parseFloat(raw);
+ amountsObj[raw] = isNaN(numeric) ? raw : numeric;
+ });
+ // Ensure Other choice always present at the end
+ amountsObj["Other"] = "other";
+ const config = {
+ amounts: amountsObj,
+ default: defaultAmount,
+ // stickyDefault omitted so it defaults to false behavior
+ };
+ window.EngridAmounts = {
+ onetime: config,
+ monthly: config,
+ };
}
}
- readCookie() {
- this.updateFieldData(get(this.cookieName) || "");
+ swapAmounts() {
+ const configs = window.EngridAmounts;
+ if (!configs)
+ return;
+ const freq = this._frequency.frequency;
+ const config = configs[freq];
+ if (!config)
+ return;
+ const stickyDefault = !!config.stickyDefault;
+ // If stickyDefault, always ignore current value so selected flag in list enforces default
+ const ignoreCurrentValue = stickyDefault ? true : this.ignoreCurrentValue();
+ window.EngagingNetworks.require._defined.enjs.swapList("donationAmt", this.toEnAmountList(config), { ignoreCurrentValue });
+ this._amount.load();
+ this.logger.log("Amounts Swapped To", config, { ignoreCurrentValue });
+ this.swapped = true;
}
- saveCookie() {
- set(this.cookieName, JSON.stringify(this.fieldData), {
- expires: this.cookieExpirationDays,
- });
+ /**
+ * Convert the internal config object into the structure Engaging Networks expects
+ */
+ toEnAmountList(config) {
+ return Object.entries(config.amounts).map(([label, value]) => ({
+ selected: value === config.default,
+ label,
+ value: value.toString(),
+ }));
}
- readFields() {
- for (let i = 0; i < this.fieldNames.length; i++) {
- let fieldSelector = "[name='" + this.fieldNames[i] + "']";
- let field = document.querySelector(fieldSelector);
- if (field) {
- if (field.tagName === "INPUT") {
- let type = field.getAttribute("type");
- if (type === "radio" || type === "checkbox") {
- field = document.querySelector(fieldSelector + ":checked");
- }
- this.fieldData[this.fieldNames[i]] = encodeURIComponent(field.value);
- }
- else if (field.tagName === "SELECT") {
- this.fieldData[this.fieldNames[i]] = encodeURIComponent(field.value);
- }
- }
+ shouldRun() {
+ const hasNSG = window.EngagingNetworks.suggestedGift !== undefined &&
+ Object.keys(window.EngagingNetworks.suggestedGift).length > 0;
+ if (!!window.EngridAmounts && hasNSG) {
+ this.logger.log("Not swapping amounts because NSG is active on page");
}
+ return !!window.EngridAmounts && !hasNSG;
}
- setFieldValue(field, value, overwrite = false) {
- value = decodeURIComponent(value || "");
- if (field && value !== undefined) {
- if ("type" in field) {
- switch (field.type) {
- case "select-one":
- case "select-multiple": {
- const selectField = field;
- for (const option of Array.from(selectField.options)) {
- if (option.value === value) {
- if ((selectField.value && overwrite) || !selectField.value) {
- option.selected = true;
- selectField.dispatchEvent(new Event("change", { bubbles: true }));
- }
- break;
- }
- }
- break;
- }
- case "checkbox":
- case "radio": {
- const inputField = field;
- if (inputField.value === value) {
- inputField.checked = true;
- inputField.dispatchEvent(new Event("change", { bubbles: true }));
- }
- break;
- }
- case "textarea":
- case "text":
- default:
- if ((field.value && overwrite) || !field.value) {
- field.value = value;
- field.dispatchEvent(new Event("change", { bubbles: true }));
- field.dispatchEvent(new Event("blur", { bubbles: true }));
- }
- }
- }
+ ignoreCurrentValue() {
+ const urlParam = engrid_ENGrid.getUrlParameter("transaction.donationAmt");
+ if (urlParam !== null) {
+ const urlAmount = parseFloat(urlParam);
+ return this._amount.amount !== urlAmount;
}
+ // If submission failed or donor manually changed away from default, respect current value
+ const submissionFailed = window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed();
+ return !(submissionFailed || this.defaultChange);
}
- clearFields(skipFields) {
- for (let key in this.fieldData) {
- if (skipFields.includes(key)) {
- delete this.fieldData[key];
- }
- else if (this.fieldData[key] === "") {
- delete this.fieldData[key];
- }
- else {
- this.fieldData[key] = "";
- }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/debug-panel.js
+
+class DebugPanel {
+ constructor(pageLayouts) {
+ var _a, _b;
+ this.logger = new logger_EngridLogger("Debug Panel", "#f0f0f0", "#ff0000", "π₯");
+ this.brandingHtml = new BrandingHtml();
+ this.element = null;
+ this.currentTimestamp = this.getCurrentTimestamp();
+ this.quickFills = {
+ "pi-general": [
+ {
+ name: "supporter.title",
+ value: "Ms",
+ },
+ {
+ name: "supporter.firstName",
+ value: "4Site",
+ },
+ {
+ name: "supporter.lastName",
+ value: "Studio",
+ },
+ {
+ name: "supporter.emailAddress",
+ value: "en-test@4sitestudios.com",
+ },
+ {
+ name: "supporter.phoneNumber",
+ value: "555-555-5555",
+ },
+ ],
+ "pi-unique": [
+ {
+ name: "supporter.title",
+ value: "Ms",
+ },
+ {
+ name: "supporter.firstName",
+ value: `4Site ${this.currentTimestamp}`,
+ },
+ {
+ name: "supporter.lastName",
+ value: "Studio",
+ },
+ {
+ name: "supporter.emailAddress",
+ value: `en-test+${this.currentTimestamp}@4sitestudios.com`,
+ },
+ {
+ name: "supporter.phoneNumber",
+ value: "555-555-5555",
+ },
+ ],
+ "us-address": [
+ {
+ name: "supporter.address1",
+ value: "3431 14th St NW",
+ },
+ {
+ name: "supporter.address2",
+ value: "Suite 1",
+ },
+ {
+ name: "supporter.city",
+ value: "Washington",
+ },
+ {
+ name: "supporter.region",
+ value: "DC",
+ },
+ {
+ name: "supporter.postcode",
+ value: "20010",
+ },
+ {
+ name: "supporter.country",
+ value: "US",
+ },
+ ],
+ "us-address-senate-rep": [
+ {
+ name: "supporter.address1",
+ value: "20 W 34th Street",
+ },
+ {
+ name: "supporter.address2",
+ value: "",
+ },
+ {
+ name: "supporter.city",
+ value: "New York",
+ },
+ {
+ name: "supporter.region",
+ value: "NY",
+ },
+ {
+ name: "supporter.postcode",
+ value: "10001",
+ },
+ {
+ name: "supporter.country",
+ value: "US",
+ },
+ ],
+ "us-address-nonexistent": [
+ {
+ name: "supporter.address1",
+ value: "12345 Main Street",
+ },
+ {
+ name: "supporter.address2",
+ value: "",
+ },
+ {
+ name: "supporter.city",
+ value: "New York",
+ },
+ {
+ name: "supporter.region",
+ value: "TX",
+ },
+ {
+ name: "supporter.postcode",
+ value: "90210",
+ },
+ {
+ name: "supporter.country",
+ value: "US",
+ },
+ ],
+ "cc-paysafe-visa": [
+ {
+ name: "transaction.ccnumber",
+ value: "4530910000012345",
+ },
+ {
+ name: "transaction.ccexpire",
+ value: "12/27",
+ },
+ {
+ name: "transaction.ccvv",
+ value: "111",
+ },
+ ],
+ "cc-paysafe-visa-invalid": [
+ {
+ name: "transaction.ccnumber",
+ value: "411111",
+ },
+ {
+ name: "transaction.ccexpire",
+ value: "12/27",
+ },
+ {
+ name: "transaction.ccvv",
+ value: "111",
+ },
+ ],
+ "cc-paysafe-mastercard": [
+ {
+ name: "transaction.ccnumber",
+ value: "5036150000001115",
+ },
+ {
+ name: "transaction.ccexpire",
+ value: "12/27",
+ },
+ {
+ name: "transaction.ccvv",
+ value: "111",
+ },
+ ],
+ "cc-stripe-visa": [
+ {
+ name: "transaction.ccnumber",
+ value: "4242424242424242",
+ },
+ {
+ name: "transaction.ccexpire",
+ value: "12/27",
+ },
+ {
+ name: "transaction.ccvv",
+ value: "111",
+ },
+ ],
+ "quick-fill-pi-unique-us-address-senate-rep-cc-stripe-visa": [
+ {
+ name: "supporter.title",
+ value: "Ms",
+ },
+ {
+ name: "supporter.firstName",
+ value: `4Site ${this.currentTimestamp}`,
+ },
+ {
+ name: "supporter.lastName",
+ value: "Studio",
+ },
+ {
+ name: "supporter.emailAddress",
+ value: `en-test+${this.currentTimestamp}@4sitestudios.com`,
+ },
+ {
+ name: "supporter.phoneNumber",
+ value: "555-555-5555",
+ },
+ {
+ name: "supporter.address1",
+ value: "20 W 34th Street",
+ },
+ {
+ name: "supporter.address2",
+ value: "",
+ },
+ {
+ name: "supporter.city",
+ value: "New York",
+ },
+ {
+ name: "supporter.region",
+ value: "NY",
+ },
+ {
+ name: "supporter.postcode",
+ value: "10001",
+ },
+ {
+ name: "supporter.country",
+ value: "US",
+ },
+ {
+ name: "transaction.ccnumber",
+ value: "4242424242424242",
+ },
+ {
+ name: "transaction.ccexpire",
+ value: "12/27",
+ },
+ {
+ name: "transaction.ccvv",
+ value: "111",
+ },
+ ],
+ };
+ this.logger.log("Adding debug panel and starting a debug session");
+ this.pageLayouts = pageLayouts;
+ this.loadDebugPanel();
+ this.element = document.querySelector(".debug-panel");
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
+ var _a;
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.add("debug-panel--open");
+ });
+ const debugPanelClose = document.querySelector(".debug-panel__close");
+ debugPanelClose === null || debugPanelClose === void 0 ? void 0 : debugPanelClose.addEventListener("click", (e) => {
+ var _a;
+ e.stopPropagation();
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.remove("debug-panel--open");
+ });
+ if (engrid_ENGrid.getUrlParameter("assets") === "local") {
+ (_b = this.element) === null || _b === void 0 ? void 0 : _b.classList.add("debug-panel--local");
}
- this.writeFields(true);
+ window.sessionStorage.setItem(DebugPanel.debugSessionStorageKey, "active");
+ }
+ loadDebugPanel() {
+ document.body.insertAdjacentHTML("beforeend", `
+
+
Debug
+
+
+
+
+ Quick-fill
+
+ Choose an option
+ Quick-fill - Unique w/ Senate Address - Stripe Visa
+ Personal Info - General
+ Personal Info - Unique
+ US Address - w/ Senate Rep
+ US Address - w/o Senate Rep
+ US Address - Nonexistent
+ CC - Paysafe - Visa
+ CC - Paysafe - Visa (Invalid)
+ CC - Paysafe - Mastercard
+ CC - Stripe - Visa
+
+
+
+ Layout
+
+
+
+
+
+
+ Embedded layout
+
+
+
+
+
+ Theme
+
+
+
+ Sub-theme
+
+
+
+ Submit form
+
+
+
+
+
+
`);
+ this.setupLayoutSwitcher();
+ this.setupThemeSwitcher();
+ this.setupSubThemeSwitcher();
+ this.setupFormQuickfill();
+ this.createDebugSessionEndHandler();
+ this.setupEmbeddedLayoutSwitcher();
+ this.setupDebugLayoutSwitcher();
+ this.setupBrandingHtmlHandler();
+ this.setupEditBtnHandler();
+ this.setupForceSubmitLinkHandler();
+ this.setupSubmitBtnHandler();
}
- /**
- * Writes the values from the fieldData object to the corresponding HTML input fields.
- *
- * This function iterates over the fieldNames array and for each field name, it selects the corresponding HTML input field.
- * If the field is found and its tag name is "INPUT", it checks if the field name matches certain conditions (like being a donation recurring payment radio button or a donation amount radio button).
- * Depending on these conditions, it either clicks the field or sets its value using the setFieldValue function.
- * If the field tag name is "SELECT", it sets its value using the setFieldValue function.
- *
- * @param overwrite - A boolean indicating whether to overwrite the existing value of the fields. Defaults to false.
- */
- writeFields(overwrite = false) {
- for (let i = 0; i < this.fieldNames.length; i++) {
- let fieldSelector = "[name='" + this.fieldNames[i] + "']";
- let field = document.querySelector(fieldSelector);
- if (field) {
- if (field.tagName === "INPUT") {
- if (this.fieldNames[i] === this.fieldDonationRecurrPayRadioName) {
- if (this.fieldData[this.fieldNames[i]] === "Y") {
- field.click();
- }
- }
- else if (this.fieldDonationAmountRadioName === this.fieldNames[i]) {
- field = document.querySelector(fieldSelector +
- "[value='" +
- this.fieldData[this.fieldNames[i]] +
- "']");
- if (field) {
- field.click();
- }
- else {
- field = document.querySelector("input[name='" + this.fieldDonationAmountOtherName + "']");
- this.setFieldValue(field, this.fieldData[this.fieldNames[i]], true);
- }
- }
- else {
- this.setFieldValue(field, this.fieldData[this.fieldNames[i]], overwrite);
- }
- }
- else if (field.tagName === "SELECT") {
- this.setFieldValue(field, this.fieldData[this.fieldNames[i]], true);
- }
- }
- }
+ switchENGridLayout(layout) {
+ engrid_ENGrid.setBodyData("layout", layout);
}
- isJson(str) {
- try {
- JSON.parse(str);
+ setupLayoutSwitcher() {
+ var _a, _b;
+ const engridLayoutSwitch = document.getElementById("engrid-layout-switch");
+ if (engridLayoutSwitch) {
+ (_a = this.pageLayouts) === null || _a === void 0 ? void 0 : _a.forEach((layout) => {
+ engridLayoutSwitch.insertAdjacentHTML("beforeend", `${layout} `);
+ });
+ engridLayoutSwitch.value = (_b = engrid_ENGrid.getBodyData("layout")) !== null && _b !== void 0 ? _b : "";
+ engridLayoutSwitch.addEventListener("change", (e) => {
+ const target = e.target;
+ this.switchENGridLayout(target.value);
+ });
}
- catch (e) {
- return false;
+ }
+ setupThemeSwitcher() {
+ var _a;
+ const engridThemeInput = document.getElementById("engrid-theme");
+ if (engridThemeInput) {
+ engridThemeInput.value = (_a = engrid_ENGrid.getBodyData("theme")) !== null && _a !== void 0 ? _a : "";
+ ["keyup", "blur"].forEach((ev) => {
+ engridThemeInput.addEventListener(ev, (e) => {
+ const target = e.target;
+ this.switchENGridTheme(target.value);
+ });
+ });
}
- return true;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/show-if-amount.js
-
-
-class ShowIfAmount {
- constructor() {
- this._amount = DonationAmount.getInstance();
- this.logger = new logger_EngridLogger("ShowIfAmount", "yellow", "black", "π");
- this._elements = document.querySelectorAll('[class*="showifamount"]');
- if (this._elements.length > 0) {
- this._amount.onAmountChange.subscribe(() => this.init());
- this.init();
- return;
+ switchENGridTheme(theme) {
+ engrid_ENGrid.setBodyData("theme", theme);
+ }
+ setupSubThemeSwitcher() {
+ var _a;
+ const engridSubthemeInput = document.getElementById("engrid-subtheme");
+ if (engridSubthemeInput) {
+ engridSubthemeInput.value = (_a = engrid_ENGrid.getBodyData("subtheme")) !== null && _a !== void 0 ? _a : "";
+ ["keyup", "blur"].forEach((ev) => {
+ engridSubthemeInput.addEventListener(ev, (e) => {
+ const target = e.target;
+ this.switchENGridSubtheme(target.value);
+ });
+ });
}
- this.logger.log("Show If Amount: NO ELEMENTS FOUND");
}
- init() {
- //If we are on a thank you page, use the window.pageJson.amount
- const amount = engrid_ENGrid.getGiftProcess()
- ? window.pageJson.amount
- : this._amount.amount;
- this._elements.forEach((element) => {
- this.lessthan(amount, element);
- this.lessthanorequalto(amount, element);
- this.equalto(amount, element);
- this.greaterthanorequalto(amount, element);
- this.greaterthan(amount, element);
- this.between(amount, element);
- });
+ switchENGridSubtheme(subtheme) {
+ engrid_ENGrid.setBodyData("subtheme", subtheme);
}
- getClassNameByOperand(classList, operand) {
- let myClass = null;
- classList.forEach((className) => {
- if (className.includes(`showifamount-${operand}-`)) {
- myClass = className;
- }
+ setupFormQuickfill() {
+ const engridQuickfill = document.getElementById("engrid-form-quickfill");
+ engridQuickfill === null || engridQuickfill === void 0 ? void 0 : engridQuickfill.addEventListener("change", (e) => {
+ const target = e.target;
+ this.quickFills[target.value].forEach((qf) => {
+ this.setFieldValue(qf);
+ });
});
- return myClass;
}
- lessthan(amount, element) {
- const showifamountClass = this.getClassNameByOperand(element.classList, "lessthan");
- if (showifamountClass) {
- let amountCheck = showifamountClass.split("-").slice(-1)[0];
- if (amount < Number(amountCheck)) {
- this.logger.log("(lessthan):", element);
- element.classList.add("engrid-open");
+ setFieldValue(qf) {
+ if (qf.name === "transaction.ccexpire") {
+ const ccExpireEls = document.getElementsByName("transaction.ccexpire");
+ if (ccExpireEls.length > 0) {
+ const expirationDate = qf.value.split("/");
+ ccExpireEls[0].value = expirationDate[0];
+ ccExpireEls[1].value = expirationDate[1];
+ ccExpireEls[0].dispatchEvent(new Event("change", { bubbles: true }));
+ ccExpireEls[1].dispatchEvent(new Event("change", { bubbles: true }));
}
else {
- element.classList.remove("engrid-open");
+ ccExpireEls[0].value = qf.value;
+ ccExpireEls[0].dispatchEvent(new Event("change", { bubbles: true }));
}
+ return;
}
+ engrid_ENGrid.setFieldValue(qf.name, qf.value, true, true);
}
- lessthanorequalto(amount, element) {
- const showifamountClass = this.getClassNameByOperand(element.classList, "lessthanorequalto");
- if (showifamountClass) {
- let amountCheck = showifamountClass.split("-").slice(-1)[0];
- if (amount <= Number(amountCheck)) {
- this.logger.log("(lessthanorequalto):", element);
- element.classList.add("engrid-open");
- }
- else {
- element.classList.remove("engrid-open");
- }
- }
+ getCurrentTimestamp() {
+ const now = new Date();
+ const year = now.getFullYear();
+ const month = String(now.getMonth() + 1).padStart(2, "0");
+ const day = String(now.getDate()).padStart(2, "0");
+ const hours = String(now.getHours()).padStart(2, "0");
+ const minutes = String(now.getMinutes()).padStart(2, "0");
+ return `${year}${month}${day}-${hours}${minutes}`;
}
- equalto(amount, element) {
- const showifamountClass = this.getClassNameByOperand(element.classList, "equalto");
- if (showifamountClass) {
- let amountCheck = showifamountClass.split("-").slice(-1)[0];
- if (amount == Number(amountCheck)) {
- this.logger.log("(equalto):", element);
- element.classList.add("engrid-open");
- }
- else {
- element.classList.remove("engrid-open");
- }
- }
+ createDebugSessionEndHandler() {
+ const debugSessionEndBtn = document.querySelector(".debug-panel__end-debug-link");
+ debugSessionEndBtn === null || debugSessionEndBtn === void 0 ? void 0 : debugSessionEndBtn.addEventListener("click", () => {
+ var _a;
+ this.logger.log("Removing panel and ending debug session");
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.remove();
+ window.sessionStorage.removeItem(DebugPanel.debugSessionStorageKey);
+ });
}
- greaterthanorequalto(amount, element) {
- const showifamountClass = this.getClassNameByOperand(element.classList, "greaterthanorequalto");
- if (showifamountClass) {
- let amountCheck = showifamountClass.split("-").slice(-1)[0];
- if (amount >= Number(amountCheck)) {
- this.logger.log("(greaterthanorequalto):", element);
- element.classList.add("engrid-open");
- }
- else {
- element.classList.remove("engrid-open");
- }
+ setupEmbeddedLayoutSwitcher() {
+ const embeddedLayoutSwitch = document.getElementById("engrid-embedded-layout");
+ if (embeddedLayoutSwitch) {
+ embeddedLayoutSwitch.checked = !!engrid_ENGrid.getBodyData("embedded");
+ embeddedLayoutSwitch.addEventListener("change", (e) => {
+ const target = e.target;
+ engrid_ENGrid.setBodyData("embedded", target.checked);
+ });
}
}
- greaterthan(amount, element) {
- const showifamountClass = this.getClassNameByOperand(element.classList, "greaterthan");
- if (showifamountClass) {
- let amountCheck = showifamountClass.split("-").slice(-1)[0];
- if (amount > Number(amountCheck)) {
- this.logger.log("(greaterthan):", element);
- element.classList.add("engrid-open");
- }
- else {
- element.classList.remove("engrid-open");
- }
+ setupDebugLayoutSwitcher() {
+ const debugLayoutSwitch = document.getElementById("engrid-debug-layout");
+ if (debugLayoutSwitch) {
+ debugLayoutSwitch.checked = engrid_ENGrid.getBodyData("debug") === "layout";
+ debugLayoutSwitch.addEventListener("change", (e) => {
+ const target = e.target;
+ if (target.checked) {
+ engrid_ENGrid.setBodyData("debug", "layout");
+ }
+ else {
+ engrid_ENGrid.setBodyData("debug", "");
+ }
+ });
}
}
- between(amount, element) {
- const showifamountClass = this.getClassNameByOperand(element.classList, "between");
- if (showifamountClass) {
- let amountCheckMin = showifamountClass.split("-").slice(-2, -1)[0];
- let amountCheckMax = showifamountClass.split("-").slice(-1)[0];
- if (amount > Number(amountCheckMin) && amount < Number(amountCheckMax)) {
- this.logger.log("(between):", element);
- element.classList.add("engrid-open");
+ setupBrandingHtmlHandler() {
+ const brandingInput = document.getElementById("engrid-branding");
+ brandingInput.checked =
+ engrid_ENGrid.getUrlParameter("development") === "branding";
+ brandingInput.addEventListener("change", (e) => {
+ if (brandingInput.checked) {
+ this.brandingHtml.show();
}
else {
- element.classList.remove("engrid-open");
+ this.brandingHtml.hide();
}
- }
+ });
+ }
+ setupEditBtnHandler() {
+ const editBtn = document.querySelector(".debug-panel__edit-link");
+ editBtn === null || editBtn === void 0 ? void 0 : editBtn.addEventListener("click", () => {
+ window.open(`https://${engrid_ENGrid.getDataCenter()}.engagingnetworks.app/index.html#pages/${engrid_ENGrid.getPageID()}/edit`, "_blank");
+ });
+ }
+ setupForceSubmitLinkHandler() {
+ const submitBtn = document.querySelector(".debug-panel__force-submit-link");
+ submitBtn === null || submitBtn === void 0 ? void 0 : submitBtn.addEventListener("click", () => {
+ const enForm = document.querySelector("form.en__component");
+ enForm === null || enForm === void 0 ? void 0 : enForm.submit();
+ });
+ }
+ setupSubmitBtnHandler() {
+ const submitBtn = document.querySelector(".debug-panel__btn--submit");
+ submitBtn === null || submitBtn === void 0 ? void 0 : submitBtn.addEventListener("click", () => {
+ const enForm = document.querySelector(".en__submit button");
+ enForm === null || enForm === void 0 ? void 0 : enForm.click();
+ });
}
}
+DebugPanel.debugSessionStorageKey = "engrid_debug_panel";
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/other-amount.js
-// This class automatically select other radio input when an amount is entered into it.
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/debug-hidden-fields.js
+// Switches hidden fields to be type text when debug mode is enabled.
-class OtherAmount {
+class DebugHiddenFields {
constructor() {
- this.logger = new logger_EngridLogger("OtherAmount", "green", "black", "π°");
- this._amount = DonationAmount.getInstance();
- "focusin input".split(" ").forEach((e) => {
- var _a;
- // We're attaching this event to the body because sometimes the other amount input is not in the DOM yet and comes via AJAX.
- (_a = document.querySelector("body")) === null || _a === void 0 ? void 0 : _a.addEventListener(e, (event) => {
- const target = event.target;
- if (target.classList.contains("en__field__input--other")) {
- this.logger.log("Other Amount Field Focused");
- this.setRadioInput();
- }
- });
- });
- const otherAmountField = document.querySelector("[name='transaction.donationAmt.other'");
- if (otherAmountField) {
- otherAmountField.setAttribute("inputmode", "decimal");
- // ADD THE MISSING LABEL FOR IMPROVED ACCESSABILITY
- otherAmountField.setAttribute("aria-label", "Enter your custom donation amount");
- otherAmountField.setAttribute("autocomplete", "off");
- otherAmountField.setAttribute("data-lpignore", "true");
- otherAmountField.addEventListener("change", (e) => {
- const target = e.target;
- const amount = target.value;
- const cleanAmount = engrid_ENGrid.cleanAmount(amount);
- if (amount !== cleanAmount.toString()) {
- this.logger.log(`Other Amount Field Changed: ${amount} => ${cleanAmount}`);
- if ("dataLayer" in window) {
- window.dataLayer.push({
- event: "otherAmountTransformed",
- otherAmountTransformation: `${amount} => ${cleanAmount}`,
- });
- }
- target.value =
- cleanAmount % 1 != 0
- ? cleanAmount.toFixed(2)
- : cleanAmount.toString();
+ this.logger = new logger_EngridLogger("Debug hidden fields", "#f0f0f0", "#ff0000", "π«£");
+ this.ignoreFields = ["transaction.paycurrency"];
+ // Query all hidden input elements within the specified selectors
+ const fields = document.querySelectorAll(".en__component--row [type='hidden'][class*='en_'], .engrid-added-input[type='hidden']");
+ // Check if there are any hidden fields
+ if (fields.length > 0) {
+ // Log the names of the hidden fields being changed to type 'text'
+ this.logger.log(`Switching the following type 'hidden' fields to type 'text': ${[
+ ...fields,
+ ]
+ .map((f) => f.name)
+ .join(", ")}`);
+ // Iterate through each hidden input element
+ fields.forEach((el) => {
+ // Check if the field name is in the ignore list
+ if (this.ignoreFields.includes(el.name)) {
+ this.logger.log(`Ignoring field: ${el.name} because it is in the ignore list`);
+ return;
}
- });
- // On blur, if the amount is 0, select the previous amount
- otherAmountField.addEventListener("blur", (e) => {
- const target = e.target;
- const amount = target.value;
- const cleanAmount = engrid_ENGrid.cleanAmount(amount);
- if (cleanAmount === 0) {
- this.logger.log("Other Amount Field Blurred with 0 amount");
- // Get Live Amount
- const liveAmount = this._amount.amount;
- if (liveAmount > 0) {
- this._amount.setAmount(liveAmount, false);
- }
+ // Change the input type to 'text' and add the required classes
+ el.type = "text";
+ el.classList.add("en__field__input", "en__field__input--text");
+ // Create a new label element and set its text and classes
+ const label = document.createElement("label");
+ label.textContent = "Hidden field: " + el.name;
+ label.classList.add("en__field__label");
+ // Create a new 'div' element for the input field and add the required classes
+ const fieldElement = document.createElement("div");
+ fieldElement.classList.add("en__field__element", "en__field__element--text");
+ // Create a new 'div' container for the label and input field, and add the required classes and attribute
+ const fieldContainer = document.createElement("div");
+ fieldContainer.classList.add("en__field", "en__field--text", "hide");
+ fieldContainer.dataset.unhidden = "";
+ fieldContainer.appendChild(label);
+ fieldContainer.appendChild(fieldElement);
+ // Insert the new field container before the original input element and move the input element into the field element div
+ if (el.parentNode) {
+ el.parentNode.insertBefore(fieldContainer, el);
+ fieldElement.appendChild(el);
}
});
}
}
- setRadioInput() {
- const target = document.querySelector(".en__field--donationAmt .en__field__input--other");
- if (target && target.parentNode && target.parentNode.parentNode) {
- const targetWrapper = target.parentNode;
- targetWrapper.classList.remove("en__field__item--hidden");
- if (targetWrapper.parentNode) {
- const lastRadioInput = targetWrapper.parentNode.querySelector(".en__field__item:nth-last-child(2) input");
- lastRadioInput.checked = !0;
- }
- }
- }
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/logger.js
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/branding-html.js
+var branding_html_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
/**
- * A better logger. It only works if debug is enabled.
+ * Inserts all of the branding HTML from https://github.com/4site-interactive-studios/engrid/tree/main/reference-materials/html/brand-guide-markup
+ * into the body-main section of the page.
*/
-class logger_EngridLogger {
- constructor(prefix, color, background, emoji) {
- this.prefix = "";
- this.color = "black";
- this.background = "white";
- this.emoji = "";
- if (emoji) {
- this.emoji = emoji;
- }
- else {
- switch (color) {
- case "red":
- this.emoji = "π΄";
- break;
- case "green":
- this.emoji = "π’";
- break;
- case "blue":
- this.emoji = "π΅";
- break;
- case "yellow":
- this.emoji = "π‘";
- this.background = "black";
- break;
- case "purple":
- this.emoji = "π£";
- break;
- case "black":
- default:
- this.emoji = "β«";
- break;
- }
- }
- if (prefix) {
- this.prefix = `[ENgrid ${prefix}]`;
- }
- if (color) {
- this.color = color;
- }
- if (background) {
- this.background = background;
- }
- }
- get log() {
- if (!engrid_ENGrid.debug && engrid_ENGrid.getUrlParameter("debug") !== "log") {
- return () => { };
- }
- return console.log.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
- }
- get success() {
- if (!engrid_ENGrid.debug) {
- return () => { };
- }
- return console.log.bind(window.console, "%c β
" + this.prefix + " %s", `color: green; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+class BrandingHtml {
+ constructor() {
+ this.assetBaseUrl = "https://cdn.jsdelivr.net/gh/4site-interactive-studios/engrid@main/reference-materials/html/brand-guide-markup/";
+ this.brandingHtmlFiles = [
+ "html5-tags.html",
+ "en-common-fields.html",
+ "survey.html",
+ // "en-common-fields-with-errors.html",
+ // "en-common-fields-with-fancy-errors.html",
+ "donation-page.html",
+ "premium-donation.html",
+ "ecards.html",
+ "email-to-target.html",
+ "tweet-to-target.html",
+ // "click-to-call.html",
+ "petition.html",
+ "event.html",
+ // "ecommerce.html",
+ // "membership.html",
+ "styles.html",
+ ];
+ this.bodyMain = document.querySelector(".body-main");
+ this.htmlFetched = false;
}
- get danger() {
- if (!engrid_ENGrid.debug) {
- return () => { };
- }
- return console.log.bind(window.console, "%c βοΈ " + this.prefix + " %s", `color: red; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ fetchHtml() {
+ return branding_html_awaiter(this, void 0, void 0, function* () {
+ const htmlRequests = this.brandingHtmlFiles.map((file) => branding_html_awaiter(this, void 0, void 0, function* () {
+ const res = yield fetch(this.assetBaseUrl + file);
+ return res.text();
+ }));
+ const brandingHtmls = yield Promise.all(htmlRequests);
+ return brandingHtmls;
+ });
}
- get warn() {
- if (!engrid_ENGrid.debug) {
- return () => { };
- }
- return console.warn.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ appendHtml() {
+ this.fetchHtml().then((html) => html.forEach((h) => {
+ var _a;
+ const brandingSection = document.createElement("div");
+ brandingSection.classList.add("brand-guide-section");
+ brandingSection.innerHTML = h;
+ (_a = this.bodyMain) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement("beforeend", brandingSection);
+ }));
+ this.htmlFetched = true;
}
- get dir() {
- if (!engrid_ENGrid.debug) {
- return () => { };
+ show() {
+ if (!this.htmlFetched) {
+ this.appendHtml();
+ return;
}
- return console.dir.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ const guides = document.querySelectorAll(".brand-guide-section");
+ guides === null || guides === void 0 ? void 0 : guides.forEach((g) => (g.style.display = "block"));
}
- get error() {
- if (!engrid_ENGrid.debug) {
- return () => { };
+ hide() {
+ const guides = document.querySelectorAll(".brand-guide-section");
+ guides === null || guides === void 0 ? void 0 : guides.forEach((g) => (g.style.display = "none"));
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/country-disable.js
+// This class allows you to disable some countries from the country dropdown list.
+
+class CountryDisable {
+ constructor() {
+ this.logger = new logger_EngridLogger("CountryDisable", "#f0f0f0", "#333333", "π");
+ const countries = document.querySelectorAll('select[name="supporter.country"], select[name="transaction.shipcountry"], select[name="supporter.billingCountry"], select[name="transaction.infcountry"]');
+ const CountryDisable = engrid_ENGrid.getOption("CountryDisable");
+ // Remove the countries from the dropdown list
+ if (countries.length > 0 && CountryDisable.length > 0) {
+ const countriesLower = CountryDisable.map((country) => country.toLowerCase());
+ countries.forEach((country) => {
+ country.querySelectorAll("option").forEach((option) => {
+ if (countriesLower.includes(option.value.toLowerCase()) ||
+ countriesLower.includes(option.text.toLowerCase())) {
+ this.logger.log(`Removing ${option.text} from ${country.getAttribute("name")}`);
+ option.remove();
+ }
+ });
+ });
}
- return console.error.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/min-max-amount.js
-// This script adds an erros message to the page if the amount is greater than the max amount or less than the min amount.
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/premium-gift.js
+// Component to handle premium gift features
+// 1 - Add a class to body to indicate which premium gift is selected (data-engrid-premium-gift-name="item-name-slugged")
+// 2 - Add a class to body to indicate if the "maximize my impact" is selected (data-engrid-premium-gift-maximize="true|false")
+// 3 - Check the premium gift when click on the title or description
+// 4 - Create new {$PREMIUMTITLE} merge tag that's replaced with the premium gift name
+// 5 - Add aria-label to the radio inputs and alt tags to the images
-class MinMaxAmount {
+class PremiumGift {
constructor() {
- var _a, _b;
- this._form = en_form_EnForm.getInstance();
- this._amount = DonationAmount.getInstance();
+ this.logger = new logger_EngridLogger("PremiumGift", "#232323", "#f7b500", "π");
+ this.enElements = new Array();
this._frequency = DonationFrequency.getInstance();
- this.minAmount = (_a = engrid_ENGrid.getOption("MinAmount")) !== null && _a !== void 0 ? _a : 1;
- this.maxAmount = (_b = engrid_ENGrid.getOption("MaxAmount")) !== null && _b !== void 0 ? _b : 100000;
- this.minAmountMessage = engrid_ENGrid.getOption("MinAmountMessage");
- this.maxAmountMessage = engrid_ENGrid.getOption("MaxAmountMessage");
- this.enAmountValidator = null;
- this.logger = new logger_EngridLogger("MinMaxAmount", "white", "purple", "π’");
- if (!this.shouldRun()) {
- // If we're not on a Donation Page, get out
+ this._amount = DonationAmount.getInstance();
+ if (!this.shoudRun())
return;
- }
- this.setValidationConfigFromEN();
- this._amount.onAmountChange.subscribe((s) => window.setTimeout(this.liveValidate.bind(this), 1000) // Wait 1 second for the amount to be updated
- );
- this._form.onValidate.subscribe(this.enOnValidate.bind(this));
+ this.searchElements();
+ this.addEventListeners();
+ this.checkPremiumGift();
+ window.setTimeout(() => {
+ this.altsAndArias();
+ this.maxDonationAria();
+ }, 1000);
}
- // Should we run the script?
- shouldRun() {
- return engrid_ENGrid.getPageType() === "DONATION";
+ shoudRun() {
+ return ("pageJson" in window &&
+ "pageType" in window.pageJson &&
+ window.pageJson.pageType === "premiumgift");
}
- // Don't submit the form if the amount is not valid
- enOnValidate() {
- if (!this._form.validate)
- return;
- const otherAmount = document.querySelector("[name='transaction.donationAmt.other']");
- if (this._amount.amount < this.minAmount) {
- this.logger.log("Amount is less than min amount: " + this.minAmount);
- if (otherAmount) {
- otherAmount.focus();
- }
- this._form.validate = false;
+ addEventListeners() {
+ ["click", "change"].forEach((event) => {
+ document.addEventListener(event, (e) => {
+ const element = e.target;
+ const premiumGift = element.closest(".en__pg__body");
+ if (premiumGift) {
+ const premiumGiftInput = premiumGift.querySelector('[name="en__pg"]');
+ if ("type" in element === false) {
+ const premiumGiftValue = premiumGiftInput.value;
+ window.setTimeout(() => {
+ const newPremiumGift = document.querySelector('[name="en__pg"][value="' + premiumGiftValue + '"]');
+ if (newPremiumGift) {
+ newPremiumGift.checked = true;
+ newPremiumGift.dispatchEvent(new Event("change"));
+ }
+ }, 100);
+ }
+ window.setTimeout(() => {
+ this.checkPremiumGift();
+ }, 110);
+ }
+ });
+ });
+ // Check when visibility of the Premium Gift Block changes.
+ // EN will add "display: none" to this element when the supporter does not qualify for a premium
+ const premiumGiftsBlock = document.querySelector(".en__component--premiumgiftblock");
+ if (premiumGiftsBlock) {
+ const observer = new MutationObserver((mutationsList) => {
+ for (const mutation of mutationsList) {
+ if (mutation.type === "attributes" &&
+ mutation.attributeName === "style") {
+ if (premiumGiftsBlock.style.display === "none") {
+ this.logger.log("Premium Gift Section hidden - removing premium gift body data attributes and premium title.");
+ engrid_ENGrid.setBodyData("premium-gift-maximize", false);
+ engrid_ENGrid.setBodyData("premium-gift-name", false);
+ this.setPremiumTitle("");
+ }
+ }
+ }
+ });
+ observer.observe(premiumGiftsBlock, { attributes: true });
}
- else if (this._amount.amount > this.maxAmount) {
- this.logger.log("Amount is greater than max amount: " + this.maxAmount);
- if (otherAmount) {
- otherAmount.focus();
+ this._frequency.onFrequencyChange.subscribe(() => {
+ window.setTimeout(() => {
+ this.altsAndArias();
+ }, 1000);
+ });
+ this._amount.onAmountChange.subscribe(() => {
+ window.setTimeout(() => {
+ this.altsAndArias();
+ }, 1000);
+ });
+ }
+ checkPremiumGift() {
+ const premiumGift = document.querySelector('[name="en__pg"]:checked');
+ if (premiumGift) {
+ const premiumGiftValue = premiumGift.value;
+ this.logger.log("Premium Gift Value: " + premiumGiftValue);
+ const premiumGiftContainer = premiumGift.closest(".en__pg");
+ if (premiumGiftValue !== "0") {
+ const premiumGiftName = premiumGiftContainer.querySelector(".en__pg__name");
+ engrid_ENGrid.setBodyData("premium-gift-maximize", "false");
+ engrid_ENGrid.setBodyData("premium-gift-name", engrid_ENGrid.slugify(premiumGiftName.innerText));
+ this.setPremiumTitle(premiumGiftName.innerText);
+ }
+ else {
+ engrid_ENGrid.setBodyData("premium-gift-maximize", "true");
+ engrid_ENGrid.setBodyData("premium-gift-name", false);
+ this.setPremiumTitle("");
+ }
+ if (!premiumGiftContainer.classList.contains("en__pg--selected")) {
+ const checkedPremiumGift = document.querySelector(".en__pg--selected");
+ if (checkedPremiumGift) {
+ checkedPremiumGift.classList.remove("en__pg--selected");
+ }
+ premiumGiftContainer.classList.add("en__pg--selected");
}
- this._form.validate = false;
}
- window.setTimeout(this.liveValidate.bind(this), 300);
}
- // Disable Submit Button if the amount is not valid
- liveValidate() {
- const amount = engrid_ENGrid.cleanAmount(this._amount.amount.toString());
- const activeElement = document.activeElement;
- if (activeElement &&
- activeElement.tagName === "INPUT" &&
- "name" in activeElement &&
- activeElement.name === "transaction.donationAmt.other" &&
- amount === 0) {
- // Don't validate if the other amount has focus and the amount is 0
- return;
- }
- this.logger.log(`Amount: ${amount}`);
- if (amount < this.minAmount) {
- this.logger.log("Amount is less than min amount: " + this.minAmount);
- engrid_ENGrid.setError(".en__field--withOther", this.minAmountMessage || "Invalid Amount");
- }
- else if (amount > this.maxAmount) {
- this.logger.log("Amount is greater than max amount: " + this.maxAmount);
- engrid_ENGrid.setError(".en__field--withOther", this.maxAmountMessage || "Invalid Amount");
- }
- else {
- engrid_ENGrid.removeError(".en__field--withOther");
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field
+ `);
+ if (enElements.length > 0) {
+ enElements.forEach((item) => {
+ if (item instanceof HTMLElement &&
+ item.innerHTML.includes("{$PREMIUMTITLE}")) {
+ item.innerHTML = item.innerHTML.replace("{$PREMIUMTITLE}", ` `);
+ this.enElements.push(item);
+ }
+ });
}
}
- setValidationConfigFromEN() {
- if (!engrid_ENGrid.getOption("UseAmountValidatorFromEN") ||
- !window.EngagingNetworks.validators) {
- this.logger.log("Not setting validation config from EN.");
- return;
- }
- // Find the amount validator for the donation amount field
- // It should be of type "AMNT" or "FAMNT" and have
- // a componentId that matches the donation amount field.
- this.enAmountValidator = window.EngagingNetworks.validators.find((validator) => {
- var _a;
- return ((validator.type === "FAMNT" || validator.type === "AMNT") &&
- ((_a = document
- .querySelector(".en__field--" + validator.componentId)) === null || _a === void 0 ? void 0 : _a.classList.contains("en__field--donationAmt")));
+ setPremiumTitle(title) {
+ this.enElements.forEach((item) => {
+ const premiumTitle = item.querySelector(".engrid_premium_title");
+ if (premiumTitle) {
+ premiumTitle.innerHTML = title;
+ }
});
- if (!this.enAmountValidator || !this.enAmountValidator.format) {
- return;
- }
- this.logger.log(`Detected an amount validator for donation amount on the page:`, this.enAmountValidator);
- // Static amount validator
- if (this.enAmountValidator.type === "AMNT") {
- this.minAmount = Number(this.enAmountValidator.format.split("~")[0]);
- this.maxAmount = Number(this.enAmountValidator.format.split("~")[1]);
- this.minAmountMessage = this.enAmountValidator.errorMessage;
- this.maxAmountMessage = this.enAmountValidator.errorMessage;
- this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`);
- }
- // Frequency-based amount validator
- if (this.enAmountValidator.type === "FAMNT") {
- this._frequency.onFrequencyChange.subscribe((freq) => {
- if (!this.enAmountValidator || !this.enAmountValidator.format)
- return;
- // In the validator, "onetime" is written as "SINGLE"
- // Validator format for FAMNT is like SINGLE:10~100000|MONTHLY:5~100000|QUARTERLY:25~100000|ANNUAL:25~100000
- const frequency = freq === "onetime" ? "SINGLE" : freq.toUpperCase();
- const validationRange = this.enAmountValidator.format
- .split("|")
- .find((range) => range.startsWith(frequency));
- if (!validationRange) {
- this.logger.log(`No validation range found for frequency: ${frequency}`);
- return;
+ }
+ // Sets alt tags for premium gift images and aria tags for premium gift radio inputs
+ altsAndArias() {
+ const premiumTitle = document.querySelectorAll(".en__pg__detail h2.en__pg__name");
+ const multistepBackButton = document.querySelectorAll(".multistep-button-container button.btn-back");
+ premiumTitle.forEach((item) => {
+ if (item) {
+ const titleText = item.innerHTML;
+ const parent = item.parentElement;
+ const prevSibling = parent === null || parent === void 0 ? void 0 : parent.previousElementSibling;
+ const radioInputSibling = prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.previousElementSibling;
+ if (prevSibling) {
+ const imageDiv = prevSibling.querySelector(".en__pg__images");
+ if (imageDiv) {
+ const img = imageDiv.querySelector("img");
+ if (img) {
+ img.setAttribute("alt", titleText);
+ img.style.width = "125px";
+ img.style.height = "100px";
+ }
+ }
}
- const amounts = validationRange.split(":")[1].split("~");
- this.minAmount = Number(amounts[0]);
- this.maxAmount = Number(amounts[1]);
- this.minAmountMessage = this.enAmountValidator.errorMessage;
- this.maxAmountMessage = this.enAmountValidator.errorMessage;
- this.logger.log(`Frequency changed to ${frequency}, updating min and max amounts`, validationRange);
- this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`);
+ if (radioInputSibling) {
+ const radioInput = radioInputSibling.querySelector('input[type="radio"]');
+ if (radioInput) {
+ radioInput.setAttribute("aria-label", titleText);
+ }
+ }
+ }
+ multistepBackButton.forEach((item) => {
+ item.setAttribute("aria-label", "Back");
});
- }
+ });
+ }
+ // This is for the Maximize My Donation aria-label - the tree structure for it is slightly different.
+ maxDonationAria() {
+ const maxDonationTitle = Array.from(document.querySelectorAll(".en__pg__detail")).filter((el) => !el.querySelector("h2"));
+ maxDonationTitle.forEach((item) => {
+ var _a;
+ if (item) {
+ const titleText = ((_a = item.querySelector(".en__pg__description")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "";
+ const prevSibling = item.previousElementSibling;
+ const radioInputSibling = prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.previousElementSibling;
+ if (radioInputSibling) {
+ const radioInput = radioInputSibling.querySelector('input[type="radio"]');
+ if (radioInput) {
+ radioInput.setAttribute("aria-label", titleText);
+ }
+ }
+ }
+ });
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/ticker.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/custom-premium.js
+// ENgrid component: CustomPremium
+// Filters premium gifts based on window.EngridPageOptions.CustomPremium configuration
+// Rules:
+// - Config shape: window.EngridPageOptions.CustomPremium[frequency][productId] = minimumAmount
+// - On frequency or amount change, wait 500ms (allow EN to re-render), then:
+// - Show only gifts whose minimumAmount <= current amount; hide others
+// - If none visible, hide entire .en__component--premiumgiftblock
+// - If current selection becomes invalid, select default; if default not visible, select "No Premium" and clear transaction.selprodvariantid
+// - Run once 500ms after page load
+// - Add EnForm onSubmit hook to clear transaction.selprodvariantid when no visible premium items
-class Ticker {
+class CustomPremium {
constructor() {
- this.shuffleSeed = __webpack_require__(3184);
- this.items = [];
- this.tickerElement = document.querySelector(".engrid-ticker");
- this.logger = new logger_EngridLogger("Ticker", "black", "beige", "π");
- if (!this.shouldRun()) {
- this.logger.log("Not running");
- // If we don't find a ticker, get out
+ this.logger = new logger_EngridLogger("CustomPremium", "teal", "white", "π§©");
+ this._amount = DonationAmount.getInstance();
+ this._frequency = DonationFrequency.getInstance();
+ this._enForm = en_form_EnForm.getInstance();
+ this.stylesInjected = false;
+ this.pendingFrequencyChange = false;
+ if (!this.shouldRun())
return;
- }
- const tickerList = document.querySelectorAll(".engrid-ticker li");
- if (tickerList.length > 0) {
- for (let i = 0; i < tickerList.length; i++) {
- this.items.push(tickerList[i].innerText);
+ this.injectStyles();
+ // Initial run: execute once after 500ms
+ window.setTimeout(() => this.run(), 500);
+ // On changes, schedule processing and fade out immediately
+ this._amount.onAmountChange.subscribe(() => this.scheduleRun());
+ this._frequency.onFrequencyChange.subscribe(() => {
+ this.pendingFrequencyChange = true;
+ this.scheduleRun();
+ });
+ // Clear hidden variant field on submit if there are no visible premium items
+ this._enForm.onSubmit.subscribe(() => {
+ if (!this.hasVisiblePremiumItems()) {
+ this.clearVariantField();
}
- }
- this.render();
- return;
+ });
}
- // Should we run the script?
shouldRun() {
- return this.tickerElement !== null;
+ const isPremiumPage = "pageJson" in window &&
+ "pageType" in window.pageJson &&
+ window.pageJson.pageType === "premiumgift";
+ const hasConfig = !!engrid_ENGrid.getOption("CustomPremium");
+ return isPremiumPage && hasConfig;
}
- getSeed() {
- return new Date().getDate() + engrid_ENGrid.getPageID();
+ get config() {
+ const cfg = engrid_ENGrid.getOption("CustomPremium");
+ return cfg || null;
}
- // Get Items
- getItems() {
- const total = this.tickerElement.getAttribute("data-total") || "50";
- this.logger.log("Getting " + total + " items");
- const seed = this.getSeed();
- const items = this.shuffleSeed.shuffle(this.items, seed);
- const now = new Date();
- const hour = now.getHours();
- const minute = now.getMinutes();
- let pointer = Math.round((hour * 60 + minute) / 5);
- if (pointer >= items.length) {
- pointer = 0;
- }
- const ret = items.slice(pointer, pointer + total).reverse();
- return ret;
+ get premiumContainer() {
+ return document.querySelector(".en__component--premiumgiftblock");
}
- // Render
- render() {
- var _a, _b, _c;
- this.logger.log("Rendering");
- const items = this.getItems();
- let ticker = document.createElement("div");
- ticker.classList.add("en__component");
- ticker.classList.add("en__component--ticker");
- let str = ``;
- for (let i = 0; i < items.length; i++) {
- str += '
' + items[i] + "
";
- }
- str = '
' + str + "
";
- ticker.innerHTML = str;
- (_b = (_a = this.tickerElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(ticker, this.tickerElement);
- (_c = this.tickerElement) === null || _c === void 0 ? void 0 : _c.remove();
- const tickerWidth = document.querySelector(".ticker").offsetWidth.toString();
- ticker.style.setProperty("--ticker-size", tickerWidth);
- this.logger.log("Ticker Size: " + ticker.style.getPropertyValue("--ticker-size"));
- this.logger.log("Ticker Width: " + tickerWidth);
+ get giftItems() {
+ return Array.from(document.querySelectorAll(".en__pg"));
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-layer.js
-// DataLayer: singleton helper for pushing structured analytics events/vars to window.dataLayer.
-// On load it emits one aggregated event `pageJsonVariablesReady` with:
-// EN_PAGEJSON_* (normalized pageJson), EN_URLPARAM_*, EN_RECURRING_FREQUENCIES (donation pages),
-// and EN_SUBMISSION_SUCCESS_{PAGETYPE} when on the final page.
-// User actions emit: EN_FORM_VALUE_UPDATED (field changes) and submission optβin/out events.
-// Queued endβofβgift events/variables (via addEndOfGiftProcessEvent / addEndOfGiftProcessVariable)
-// are replayed after a successful gift process load.
-// Sensitive payment/bank fields are excluded; selected PII fields are Base64 βhashedβ (btoa β not cryptographic).
-// Replace with a real hash (e.g., SHAβ256) if required.
-var data_layer_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-
-class DataLayer {
- constructor() {
- this.logger = new logger_EngridLogger("DataLayer", "#f1e5bc", "#009cdc", "π");
- this.dataLayer = window.dataLayer || [];
- this._form = en_form_EnForm.getInstance();
- this.encoder = new TextEncoder();
- this.endOfGiftProcessStorageKey = "ENGRID_END_OF_GIFT_PROCESS_EVENTS";
- // pageJson entries related to the gift process
- this.giftFields = [
- "amount",
- "currency",
- "donationLogId",
- "feeCover",
- "giftProcess",
- "paymentType",
- "receiptNumber",
- "recurring",
- "transactionId",
- "transactionType",
- ];
- this.excludedFields = [
- // Credit Card
- "transaction.ccnumber",
- "transaction.ccexpire.delimiter",
- "transaction.ccexpire",
- "transaction.ccvv",
- "supporter.creditCardHolderName",
- // Bank Account
- "supporter.bankAccountNumber",
- "supporter.bankAccountType",
- "transaction.bankname",
- "supporter.bankRoutingNumber",
- ];
- this.hashedFields = [
- // Supporter Address, Phone Numbers, and Address
- "supporter.emailAddress",
- "supporter.phoneNumber",
- "supporter.phoneNumber2",
- "supporter.address1",
- "supporter.address2",
- "supporter.address3",
- // In Honor/Memory Inform Email and Address
- "transaction.infemail",
- "transaction.infadd1",
- "transaction.infadd2",
- "transaction.infadd3",
- // Billing Address
- "supporter.billingAddress1",
- "supporter.billingAddress2",
- "supporter.billingAddress3",
- ];
- this.retainedEmailField = "supporter.emailAddress";
- this.retainedAddressFields = [
- "supporter.address1",
- "supporter.address2",
- "supporter.address3",
- ];
- this.retainedPhoneFields = [
- "supporter.phoneNumber2",
- "supporter.phoneNumber",
- ];
- if (engrid_ENGrid.getOption("RememberMe")) {
- RememberMeEvents.getInstance().onLoad.subscribe((hasData) => {
- this.logger.log("Remember me - onLoad", hasData);
- this.onLoad();
+ getFrequencyConfig(frequency) {
+ const customPremiumConfig = this.config;
+ if (!customPremiumConfig)
+ return null;
+ const frequencyConfig = customPremiumConfig[frequency];
+ if (frequencyConfig && typeof frequencyConfig === "object")
+ return frequencyConfig;
+ return null;
+ }
+ getProductsMap(frequency) {
+ const frequencyConfig = this.getFrequencyConfig(frequency);
+ const productsMap = {};
+ if (!frequencyConfig)
+ return productsMap;
+ // If explicit products object exists, use it
+ if (frequencyConfig.products &&
+ typeof frequencyConfig.products === "object") {
+ Object.entries(frequencyConfig.products).forEach(([productId, min]) => {
+ const id = String(productId);
+ const minAmount = Number(min);
+ if (!isNaN(minAmount))
+ productsMap[id] = minAmount;
});
+ return productsMap;
}
- else {
- this.onLoad();
+ // Otherwise, treat own numeric-value keys as products, ignore 'default'
+ Object.entries(frequencyConfig).forEach(([key, value]) => {
+ if (key === "default")
+ return;
+ const minAmount = Number(value);
+ if (!isNaN(minAmount))
+ productsMap[String(key)] = minAmount;
+ });
+ return productsMap;
+ }
+ getConfiguredDefaultPid(frequency) {
+ const frequencyConfig = this.getFrequencyConfig(frequency);
+ if (!frequencyConfig)
+ return null;
+ const defaultValue = frequencyConfig.default;
+ if (defaultValue === undefined || defaultValue === null)
+ return "0"; // not set => No Premium by spec
+ const id = String(defaultValue);
+ return id;
+ }
+ injectStyles() {
+ if (this.stylesInjected)
+ return;
+ const id = "engrid-custom-premium-style";
+ if (document.getElementById(id)) {
+ this.stylesInjected = true;
+ return;
}
- this._form.onSubmit.subscribe(() => this.onSubmit());
+ const style = document.createElement("style");
+ style.id = id;
+ style.innerHTML = `
+ .en__component--premiumgiftblock { transition: opacity 200ms ease-in-out; }
+ .en__component--premiumgiftblock.engrid-premium-processing { opacity: 0; pointer-events: none; }
+ .en__component--premiumgiftblock.engrid-premium-hidden { display: none !important; }
+ .en__component--premiumgiftblock.engrid-premium-ready { opacity: 1; }
+ `;
+ document.head.appendChild(style);
+ this.stylesInjected = true;
}
- static getInstance() {
- if (!DataLayer.instance) {
- DataLayer.instance = new DataLayer();
- window._dataLayer = DataLayer.instance;
+ startProcessingVisual() {
+ const container = this.premiumContainer;
+ if (container) {
+ container.classList.add("engrid-premium-processing");
+ container.classList.remove("engrid-premium-ready");
}
- return DataLayer.instance;
}
- transformJSON(value) {
- if (typeof value === "string") {
- return value
- .toUpperCase()
- .trim()
- .replace(/\s+/g, "-")
- .replace(/:-/g, "-");
+ endProcessingVisual(hasVisible) {
+ const container = this.premiumContainer;
+ if (!container)
+ return;
+ container.classList.remove("engrid-premium-processing");
+ if (hasVisible) {
+ container.classList.remove("engrid-premium-hidden");
+ container.classList.add("engrid-premium-ready");
}
- if (typeof value === "boolean") {
- return value ? "TRUE" : "FALSE";
+ else {
+ container.classList.add("engrid-premium-hidden");
+ container.classList.remove("engrid-premium-ready");
}
- if (typeof value === "number") {
- return value; // Preserve numeric type for analytics platforms that infer number vs string
+ }
+ scheduleRun() {
+ // Immediately fade out while we wait for EN to re-render
+ this.startProcessingVisual();
+ if (this.debounceTimer)
+ window.clearTimeout(this.debounceTimer);
+ this.debounceTimer = window.setTimeout(() => this.run(), 500);
+ }
+ getCurrentFreq() {
+ return (this._frequency.frequency || "onetime").toLowerCase();
+ }
+ getCurrentAmount() {
+ return this._amount.amount || 0;
+ }
+ getAllowedProductIds(freq, amount) {
+ const cfg = this.config;
+ const allowed = new Set();
+ if (!cfg)
+ return allowed;
+ const products = this.getProductsMap(freq);
+ Object.keys(products).forEach((pid) => {
+ const min = Number(products[pid]);
+ if (!isNaN(min) && amount >= min)
+ allowed.add(String(pid));
+ });
+ return allowed;
+ }
+ getProductId(item) {
+ const input = item.querySelector('input[name="en__pg"]');
+ return input ? input.value : null;
+ }
+ showItem(item, show) {
+ item.style.display = show ? "" : "none";
+ }
+ selectByProductId(productId) {
+ const radio = document.querySelector('input[name="en__pg"][value="' + productId + '"]');
+ if (radio) {
+ radio.checked = true;
+ radio.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
+ // Update EN's selected class if necessary
+ const prev = document.querySelector(".en__pg--selected");
+ const pg = radio.closest(".en__pg");
+ if (prev && prev !== pg)
+ prev.classList.remove("en__pg--selected");
+ if (pg)
+ pg.classList.add("en__pg--selected");
}
- return "";
}
- onLoad() {
- // Collect all data layer variables to push at once
- const dataLayerData = {};
- const suppressEcardData = engrid_ENGrid.getPageType() === "ECARD" &&
- engrid_ENGrid.getOption("SuppressPurchaseEcard");
- if (engrid_ENGrid.getGiftProcess()) {
- // EN will chain together gift process data on the page json when redirecting from a completed donation to an ecard.
- // Since the ecard page can be embedded on the thank you page of a donation, this can cause confusion in the data layer with events
- // firing for both the donation and the ecard on the same page.
- if (suppressEcardData) {
- this.logger.log("β Gift process was detected BUT suppressing EN_SUCCESSFUL_DONATION event due to SuppressPurchaseEcard option enabled");
- window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
+ clearVariantField() {
+ engrid_ENGrid.setFieldValue("transaction.selprodvariantid", "");
+ }
+ hasVisiblePremiumItems() {
+ // Exclude the "No Premium" (value 0) from count
+ return this.giftItems.some((item) => {
+ const pid = this.getProductId(item);
+ const visible = engrid_ENGrid.isVisible(item);
+ return visible && pid !== "0";
+ });
+ }
+ run() {
+ const container = this.premiumContainer;
+ if (!container)
+ return this.logger.log("No premium container found.");
+ const frequency = this.getCurrentFreq();
+ const amount = this.getCurrentAmount();
+ const allowedProductIds = this.getAllowedProductIds(frequency, amount);
+ // Iterate items and toggle visibility
+ let anyVisible = false;
+ const items = this.giftItems;
+ const noPremiumItems = [];
+ items.forEach((item) => {
+ const productId = this.getProductId(item);
+ if (!productId)
+ return;
+ if (productId === "0") {
+ // track no-premium items but don't decide visibility here β it's always available
+ noPremiumItems.push(item);
+ this.showItem(item, true);
+ return;
+ }
+ const visible = allowedProductIds.has(productId);
+ this.showItem(item, visible);
+ if (visible)
+ anyVisible = true;
+ });
+ // If nothing visible (besides no-premium), hide whole container
+ const hasVisibleGifts = anyVisible;
+ this.endProcessingVisual(hasVisibleGifts);
+ // Selection handling
+ const current = document.querySelector('input[name="en__pg"]:checked');
+ const currentProductId = (current === null || current === void 0 ? void 0 : current.value) || null;
+ const defaultProductId = this.getConfiguredDefaultPid(frequency); // may be "0"
+ // If current selection is invalid after filtering, apply default logic
+ const currentIsValid = currentProductId === "0" ||
+ (currentProductId ? allowedProductIds.has(currentProductId) : false);
+ if (!currentIsValid) {
+ if (defaultProductId &&
+ defaultProductId !== "0" &&
+ allowedProductIds.has(defaultProductId)) {
+ this.selectByProductId(defaultProductId);
}
else {
- this.logger.log("EN_SUCCESSFUL_DONATION");
- this.addEndOfGiftProcessEventsToDataLayer();
+ this.selectByProductId("0");
+ this.clearVariantField();
}
}
- if (window.pageJson) {
- const pageJson = window.pageJson;
- for (const property in pageJson) {
- if (suppressEcardData && this.giftFields.includes(property)) {
- continue;
+ else {
+ // Current selection is valid; only force No Premium if frequency changed and default is 0/missing
+ if (this.pendingFrequencyChange &&
+ (!defaultProductId || defaultProductId === "0")) {
+ if (currentProductId !== "0") {
+ this.selectByProductId("0");
+ this.clearVariantField();
}
- const key = `EN_PAGEJSON_${property.toUpperCase()}`;
- const value = pageJson[property];
- dataLayerData[key] = this.transformJSON(value);
}
- if (engrid_ENGrid.getPageCount() === engrid_ENGrid.getPageNumber()) {
- dataLayerData[`EN_SUBMISSION_SUCCESS_${pageJson.pageType.toUpperCase()}`] = "TRUE";
- }
- }
- const urlParams = new URLSearchParams(window.location.search);
- urlParams.forEach((value, key) => {
- dataLayerData[`EN_URLPARAM_${key.toUpperCase()}`] =
- this.transformJSON(value);
- });
- this.addRetainedHashesToDataLayer(dataLayerData);
- if (engrid_ENGrid.getPageType() === "DONATION") {
- const recurrFreqEls = document.querySelectorAll('[name="transaction.recurrfreq"]');
- const recurrValues = [...recurrFreqEls].map((el) => el.value);
- dataLayerData[`EN_RECURRING_FREQUENCIES`] = recurrValues;
}
- // Push all collected variables at once
- if (Object.keys(dataLayerData).length > 0) {
- dataLayerData.event = "pageJsonVariablesReady";
- this.dataLayer.push(dataLayerData);
+ // If container hidden (no visible gifts), select No Premium and clear hidden
+ if (!hasVisibleGifts) {
+ this.selectByProductId("0");
+ this.clearVariantField();
}
- this.attachEventListeners();
+ this.logger.log(`Processed gifts for freq=${frequency}, amount=${amount}. Visible gifts: ${hasVisibleGifts ? "yes" : "no"}`);
+ // Reset frequency-change flag after processing
+ this.pendingFrequencyChange = false;
}
- addRetainedHashesToDataLayer(dataLayerData) {
- if (typeof window === "undefined" || !window.localStorage) {
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/digital-wallets.js
+
+
+
+class DigitalWallets {
+ constructor() {
+ this.logger = new logger_EngridLogger("DigitalWallets", "#fff", "#333", "π");
+ this._form = en_form_EnForm.getInstance();
+ //digital wallets not enabled.
+ if (!document.getElementById("en__digitalWallet")) {
+ engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-google-pay", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-venmo", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-daf", "false");
+ this.logger.log("No digital wallet container found, skipping digital wallet setup.");
return;
}
- ["EMAIL", "ADDRESS", "PHONE"].forEach((suffix) => {
- const storageKey = `EN_HASH_${suffix}`;
- const storedValue = window.localStorage.getItem(storageKey);
- if (storedValue) {
- dataLayerData[storageKey] = storedValue;
- }
- });
- }
- onSubmit() {
- const optIn = document.querySelector(".en__field__item:not(.en__field--question) input[name^='supporter.questions'][type='checkbox']:checked");
- if (optIn) {
- this.logger.log("EN_SUBMISSION_WITH_EMAIL_OPTIN");
- this.dataLayer.push({
- event: "EN_SUBMISSION_WITH_EMAIL_OPTIN",
- });
+ // Add giveBySelect classes to the separate wallet containers
+ // and hide them on load.
+ const stripeButtons = document.getElementById("en__digitalWallet__stripeButtons__container");
+ if (stripeButtons) {
+ stripeButtons.classList.add("giveBySelect-stripedigitalwallet");
+ stripeButtons.classList.add("showif-stripedigitalwallet-selected");
+ // stripeButtons.style.display = "none";
}
- else {
- this.logger.log("EN_SUBMISSION_WITHOUT_EMAIL_OPTIN");
- this.dataLayer.push({
- event: "EN_SUBMISSION_WITHOUT_EMAIL_OPTIN",
- });
+ const paypalTouchButtons = document.getElementById("en__digitalWallet__paypalTouch__container");
+ if (paypalTouchButtons) {
+ paypalTouchButtons.classList.add("giveBySelect-paypaltouch");
+ paypalTouchButtons.classList.add("showif-paypaltouch-selected");
+ // paypalTouchButtons.style.display = "none";
}
- }
- attachEventListeners() {
- const textInputs = document.querySelectorAll(".en__component--advrow input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=hidden]):not([unhidden]), .en__component--advrow textarea");
- textInputs.forEach((el) => {
- el.addEventListener("blur", (e) => {
- this.handleFieldValueChange(e.target);
- });
- });
- const radioAndCheckboxInputs = document.querySelectorAll(".en__component--advrow input[type=checkbox], .en__component--advrow input[type=radio]");
- radioAndCheckboxInputs.forEach((el) => {
- el.addEventListener("change", (e) => {
- this.handleFieldValueChange(e.target);
- });
- });
- const selectInputs = document.querySelectorAll(".en__component--advrow select");
- selectInputs.forEach((el) => {
- el.addEventListener("change", (e) => {
- this.handleFieldValueChange(e.target);
- });
- });
- }
- handleFieldValueChange(el) {
- var _a, _b, _c;
- return data_layer_awaiter(this, void 0, void 0, function* () {
- if (el.value === "" || this.excludedFields.includes(el.name))
- return;
- const value = this.hashedFields.includes(el.name)
- ? yield this.hash(el.value)
- : el.value;
- if (["checkbox", "radio"].includes(el.type)) {
- if (el.checked) {
- if (el.name === "en__pg") {
- //Premium gift handling
- this.dataLayer.push({
- event: "EN_FORM_VALUE_UPDATED",
- enFieldName: el.name,
- enFieldLabel: "Premium Gift",
- enFieldValue: (_b = (_a = el
- .closest(".en__pg__body")) === null || _a === void 0 ? void 0 : _a.querySelector(".en__pg__name")) === null || _b === void 0 ? void 0 : _b.textContent,
- enProductId: (_c = document.querySelector('[name="transaction.selprodvariantid"]')) === null || _c === void 0 ? void 0 : _c.value,
- });
- }
- else {
- this.dataLayer.push({
- event: "EN_FORM_VALUE_UPDATED",
- enFieldName: el.name,
- enFieldLabel: this.getFieldLabel(el),
- enFieldValue: value,
- });
- }
- }
- return;
+ const donorAdvisedFundButtonContainer = document.getElementById("en__digitalWallet__chariot__container");
+ if (donorAdvisedFundButtonContainer) {
+ donorAdvisedFundButtonContainer.classList.add("giveBySelect-daf");
+ donorAdvisedFundButtonContainer.classList.add("showif-daf-selected");
+ }
+ /**
+ * Check for presence of elements that indicated Stripe digital wallets
+ * (Google Pay, Apple Pay) have loaded, and add functionality for them.
+ * If they haven't yet loaded, set up a Mutation Observer to check for
+ * when they do.
+ */
+ if (document.querySelector("#en__digitalWallet__stripeButtons__container > *")) {
+ this.addStripeDigitalWallets();
+ }
+ else {
+ engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-google-pay", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
+ const stripeContainer = document.getElementById("en__digitalWallet__stripeButtons__container");
+ if (stripeContainer) {
+ this.checkForWalletsBeingAdded(stripeContainer, "stripe");
}
- if (el.name === this.retainedEmailField) {
- const retainedEmailValue = this.geRetainedFieldsValue("email");
- const sha256value = yield this.hash(retainedEmailValue);
- localStorage.setItem(`EN_HASH_EMAIL`, sha256value);
- this.dataLayer.push({
- event: "EN_HASH_VALUE_UPDATED",
- enFieldName: "email",
- enFieldLabel: this.getFieldLabel(el),
- enFieldValue: sha256value,
- });
- return;
+ // If the default payment type is Stripe Digital Wallet and the page doesnt support it, set the payment type to Card
+ const paymentType = engrid_ENGrid.getPaymentType();
+ if (paymentType.toLowerCase() === "stripedigitalwallet") {
+ engrid_ENGrid.setPaymentType("card");
}
- else if (this.retainedAddressFields.includes(el.name)) {
- const retainedAddressValue = this.geRetainedFieldsValue("address");
- const sha256value = yield this.hash(retainedAddressValue);
- localStorage.setItem(`EN_HASH_ADDRESS`, sha256value);
- this.dataLayer.push({
- event: "EN_HASH_VALUE_UPDATED",
- enFieldName: "address",
- enFieldLabel: "Supporter Address",
- enFieldValue: sha256value,
- });
+ }
+ /**
+ * Check for presence of elements that indicated Paypal digital wallets
+ * (Paypal One Touch, Venmo, Etc) have loaded, and add functionality for them.
+ * If they haven't yet loaded, set up a Mutation Observer to check for
+ * when they do.
+ */
+ if (document.querySelector("#en__digitalWallet__paypalTouch__container > *")) {
+ this.addPaypalTouchDigitalWallets();
+ }
+ else {
+ engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
+ engrid_ENGrid.setBodyData("payment-type-option-venmo", "false");
+ const paypalContainer = document.getElementById("en__digitalWallet__paypalTouch__container");
+ if (paypalContainer) {
+ this.checkForWalletsBeingAdded(paypalContainer, "paypalTouch");
}
- else if (this.retainedPhoneFields.includes(el.name)) {
- const retainedPhoneValue = this.geRetainedFieldsValue("phone");
- const sha256value = yield this.hash(retainedPhoneValue);
- localStorage.setItem(`EN_HASH_PHONE`, sha256value);
- this.dataLayer.push({
- event: "EN_HASH_VALUE_UPDATED",
- enFieldName: "phone",
- enFieldLabel: "Supporter Phone",
- enFieldValue: sha256value,
- });
+ }
+ /**
+ * Check for presence of elements that indicate DAF is present, and add functionality for it.
+ * If it hasn't loaded yet, set up a Mutation Observer to check for when it does.
+ */
+ if (document.querySelector("#en__digitalWallet__chariot__container > *")) {
+ this.addDAF();
+ }
+ else {
+ engrid_ENGrid.setBodyData("payment-type-option-daf", "false");
+ const donorAdvisedFundButtonContainer = document.getElementById("en__digitalWallet__chariot__container");
+ if (donorAdvisedFundButtonContainer) {
+ this.checkForWalletsBeingAdded(donorAdvisedFundButtonContainer, "daf");
}
- this.dataLayer.push({
- event: "EN_FORM_VALUE_UPDATED",
- enFieldName: el.name,
- enFieldLabel: this.getFieldLabel(el),
- enFieldValue: value,
+ }
+ }
+ addStripeDigitalWallets() {
+ this.logger.log("Stripe Digital Wallets detected");
+ this.addOptionToPaymentTypeField("stripedigitalwallet", "GooglePay / ApplePay");
+ // ENGrid.setBodyData(
+ // "payment-type-option-apple-pay",
+ // DigitalWallets.isApplePayAvailable.toString()
+ // );
+ // ENGrid.setBodyData(
+ // "payment-type-option-google-pay",
+ // !DigitalWallets.isApplePayAvailable.toString()
+ // );
+ // TODO: Change to trustworthy detection of Google Pay & Apple Pay availability
+ engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "true");
+ engrid_ENGrid.setBodyData("payment-type-option-google-pay", "true");
+ engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "true");
+ this.addStripeDigitalWalletListener()
+ ? this.logger.log("Stripe Digital Wallet listener added successfully")
+ : this.logger.log("Failed to add Stripe Digital Wallet listener");
+ }
+ addPaypalTouchDigitalWallets() {
+ this.logger.log("Paypal Touch Digital Wallets detected");
+ this.addOptionToPaymentTypeField("paypaltouch", "Paypal / Venmo");
+ engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "true");
+ engrid_ENGrid.setBodyData("payment-type-option-venmo", "true");
+ this.addPaypalOneTouchListener()
+ ? this.logger.log("Paypal Touch listener added successfully")
+ : this.logger.log("Failed to add Paypal Touch listener");
+ }
+ addDAF() {
+ this.logger.log("DAF Digital Wallet detected");
+ this.addOptionToPaymentTypeField("daf", "Donor Advised Fund");
+ engrid_ENGrid.setBodyData("payment-type-option-daf", "true");
+ this.addDAFListener()
+ ? this.logger.log("DAF listener added successfully")
+ : this.logger.log("Failed to add DAF listener");
+ }
+ addOptionToPaymentTypeField(value, label) {
+ const paymentTypeField = document.querySelector('[name="transaction.paymenttype"]');
+ if (paymentTypeField &&
+ !paymentTypeField.querySelector(`[value=${value}]`)) {
+ const walletOption = document.createElement("option");
+ walletOption.value = value;
+ walletOption.innerText = label;
+ paymentTypeField.appendChild(walletOption);
+ }
+ // If this payment type is set as the default on GiveBySelect, set the payment type to this value
+ // We need to do this here because the digital wallets are sometimes slow to load
+ const giveBySelect = document.querySelector('input[name="transaction.giveBySelect"][value="' + value + '"]');
+ if (giveBySelect && giveBySelect.dataset.default === "true") {
+ giveBySelect.checked = true;
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true,
});
- });
+ giveBySelect.dispatchEvent(event);
+ }
}
- geRetainedFieldsValue(kind) {
- switch (kind) {
- case "email":
- return engrid_ENGrid.getFieldValue(this.retainedEmailField);
- case "address":
- return this.retainedAddressFields
- .map((field) => engrid_ENGrid.getFieldValue(field))
- .filter((value) => value !== "")
- .join("")
- .toLocaleLowerCase()
- .replace(/\s+/g, "");
- case "phone":
- // Only return the first phone number found - prioritize phoneNumber2 over phoneNumber and remove non-numeric characters
- for (const field of this.retainedPhoneFields) {
- const value = engrid_ENGrid.getFieldValue(field);
- if (value !== "") {
- return value.replace(/\D/g, "");
+ checkForWalletsBeingAdded(node, walletType) {
+ const callback = (mutationList, observer) => {
+ for (const mutation of mutationList) {
+ //Once a child node has been added, set up the appropriate digital wallet
+ if (mutation.type === "childList" && mutation.addedNodes.length) {
+ if (walletType === "stripe") {
+ this.addStripeDigitalWallets();
+ }
+ else if (walletType === "paypalTouch") {
+ this.addPaypalTouchDigitalWallets();
+ }
+ else if (walletType === "daf") {
+ this.addDAF();
}
+ //Disconnect observer and break loop to prevent multiple additions
+ observer.disconnect();
+ break;
}
- return "";
- default:
- return "";
+ }
+ };
+ const observer = new MutationObserver(callback);
+ observer.observe(node, { childList: true, subtree: true });
+ }
+ addPaypalOneTouchListener() {
+ var _a, _b, _c, _d, _e;
+ const paypalTouch = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enPaypalTouch) === null || _d === void 0 ? void 0 : _d.paypalTouch;
+ if (!((_e = paypalTouch === null || paypalTouch === void 0 ? void 0 : paypalTouch.library) === null || _e === void 0 ? void 0 : _e.Buttons)) {
+ this.logger.log("Paypal Touch library not found, cannot add listener");
+ return false;
}
+ const buttons = paypalTouch.library.Buttons.bind(paypalTouch.library);
+ paypalTouch.library.Buttons = (o) => buttons(Object.assign(Object.assign({}, o), { onClick: (d, a) => (this._form.dispatchIntentSubmit(),
+ o.onClick && o.onClick(d, a)) }));
+ paypalTouch.unloadButton && paypalTouch.unloadButton();
+ paypalTouch.loadButton && paypalTouch.loadButton();
+ return true;
}
- hash(value) {
- return data_layer_awaiter(this, void 0, void 0, function* () {
- const data = this.encoder.encode(value);
- const hashBuffer = yield crypto.subtle.digest("SHA-256", data);
- return Array.from(new Uint8Array(hashBuffer))
- .map((byte) => {
- const hex = byte.toString(16);
- return hex.length === 1 ? "0" + hex : hex;
- })
- .join("");
- });
+ addStripeDigitalWalletListener() {
+ var _a, _b, _c, _d, _e, _f;
+ return !!((_f = (_e = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enStripeButtons) === null || _d === void 0 ? void 0 : _d.stripeButtons) === null || _e === void 0 ? void 0 : _e.paymentRequest) === null || _f === void 0 ? void 0 : _f.on("paymentmethod", this._form.dispatchIntentSubmit.bind(this._form)));
}
- getFieldLabel(el) {
- var _a, _b;
- return ((_b = (_a = el.closest(".en__field")) === null || _a === void 0 ? void 0 : _a.querySelector("label")) === null || _b === void 0 ? void 0 : _b.textContent) || "";
+ addDAFListener() {
+ const chariotButton = document.getElementById("chariot-button");
+ chariotButton === null || chariotButton === void 0 ? void 0 : chariotButton.addEventListener("click", this._form.dispatchIntentSubmit.bind(this._form));
+ return !!chariotButton;
}
- addEndOfGiftProcessEvent(eventName, eventProperties = {}) {
- this.storeEndOfGiftProcessData(Object.assign({ event: eventName }, eventProperties));
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/mobile-cta.js
+// This component adds a floating CTA button to the page, which can be used to scroll to the top of the form
+
+class MobileCTA {
+ constructor() {
+ var _a;
+ // Initialize options with the MobileCTA value or false
+ this.options = (_a = engrid_ENGrid.getOption("MobileCTA")) !== null && _a !== void 0 ? _a : false;
+ this.buttonLabel = "";
+ // Return early if the options object is falsy or the current page type is not in the options.pages array
+ if (!this.options || engrid_ENGrid.getPageNumber() !== 1) {
+ return;
+ }
+ const labelForPageType = this.options.find((option) => option.pageType === engrid_ENGrid.getPageType());
+ if (!labelForPageType)
+ return;
+ // Set the button label to the window.mobileCTAButtonLabel value or the label for the current page type
+ this.buttonLabel = window.mobileCTAButtonLabel || labelForPageType.label;
+ this.renderButton();
+ this.addEventListeners();
}
- addEndOfGiftProcessVariable(variableName, variableValue = "") {
- this.storeEndOfGiftProcessData({
- [variableName.toUpperCase()]: variableValue,
+ renderButton() {
+ const engridDiv = document.querySelector("#engrid");
+ const formBlock = document.querySelector(".body-main .en__component--widgetblock:first-child, .en__component--formblock");
+ // Return early if engridDiv or formBlock are not found
+ if (!engridDiv || !formBlock)
+ return;
+ const buttonContainer = document.createElement("div");
+ const button = document.createElement("button");
+ // Add necessary classes and set the initial display style for the button container
+ buttonContainer.classList.add("engrid-mobile-cta-container", "hide-cta");
+ button.classList.add("primary");
+ // Set the button's innerHTML and add a click event listener
+ button.innerHTML =
+ this.buttonLabel +
+ ' ';
+ button.addEventListener("click", () => {
+ formBlock.scrollIntoView({ behavior: "smooth" });
});
+ // Append the button to the button container and the container to engridDiv
+ buttonContainer.appendChild(button);
+ engridDiv.appendChild(buttonContainer);
}
- storeEndOfGiftProcessData(data) {
- const events = this.getEndOfGiftProcessData();
- events.push(data);
- window.sessionStorage.setItem(this.endOfGiftProcessStorageKey, JSON.stringify(events));
+ addEventListeners() {
+ const bodyMain = document.querySelector(".body-main");
+ // Return early if formBlock is not found
+ if (!bodyMain)
+ return;
+ // Define a function to toggle the button visibility based on the bodyMain position
+ const toggleButton = () => {
+ if (bodyMain.getBoundingClientRect().top <= window.innerHeight - 100) {
+ this.hideButton();
+ }
+ else {
+ this.showButton();
+ }
+ };
+ toggleButton();
+ // Add event listeners for load, resize, and scroll events to toggle the button visibility
+ window.addEventListener("load", toggleButton);
+ window.addEventListener("resize", toggleButton);
+ window.addEventListener("scroll", toggleButton);
}
- addEndOfGiftProcessEventsToDataLayer() {
- this.getEndOfGiftProcessData().forEach((event) => {
- this.dataLayer.push(event);
- });
- window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
+ // Hide the button by setting the container's display style to "none"
+ hideButton() {
+ const buttonContainer = document.querySelector(".engrid-mobile-cta-container");
+ if (buttonContainer)
+ buttonContainer.classList.add("hide-cta");
}
- getEndOfGiftProcessData() {
- let eventsData = window.sessionStorage.getItem(this.endOfGiftProcessStorageKey);
- return !eventsData ? [] : JSON.parse(eventsData);
+ // Show the button by setting the container's display style to "block"
+ showButton() {
+ const buttonContainer = document.querySelector(".engrid-mobile-cta-container");
+ if (buttonContainer)
+ buttonContainer.classList.remove("hide-cta");
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-replace.js
-// This script is used to replace merge tags in the EN Blocks of the page.
-// It searches for HTML elements containing the data to be replaced and replaces it.
-// The data to be replaced is passed as URL parameters, example: ?engrid_data[key]=value.
-// The merge tag, if found, is replaced with the value from the URL parameter.
-// If no value is found, the default value is used.
-// The default value is the value inside the merge tag, example: {engrid_data~key~default}.
-// If no default value is set, an empty string is used.
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/live-frequency.js
+// This script creates merge tags: [[frequency]], [[Frequency]], or [[FREQUENCY]]
+// that gets replaced with the donation frequency
+// and can be used on any Code Block, Text Block, or Form Block
-class DataReplace {
+class LiveFrequency {
constructor() {
- this.logger = new logger_EngridLogger("DataReplace", "#333333", "#00f3ff", "‡οΈ");
- this.enElements = new Array();
+ this.logger = new logger_EngridLogger("LiveFrequency", "#00ff00", "#000000", "π§Ύ");
+ this.elementsFound = false;
+ this._amount = DonationAmount.getInstance();
+ this._frequency = DonationFrequency.getInstance();
this.searchElements();
if (!this.shouldRun())
return;
- this.logger.log("Elements Found:", this.enElements);
- this.replaceAll();
+ this.updateFrequency();
+ this.addEventListeners();
}
- /**
- * Searches for HTML elements containing the data to be replaced.
- */
searchElements() {
const enElements = document.querySelectorAll(`
.en__component--copyblock,
.en__component--codeblock,
- .en__field
+ .en__field label,
+ .en__submit
`);
if (enElements.length > 0) {
+ const pattern = /\[\[(frequency)\]\]/gi;
+ let totalFound = 0;
enElements.forEach((item) => {
- if (item instanceof HTMLElement &&
- item.innerHTML.includes("{engrid_data~")) {
- this.enElements.push(item);
+ const match = item.innerHTML.match(pattern);
+ if (item instanceof HTMLElement && match) {
+ this.elementsFound = true;
+ match.forEach((matchedSubstring) => {
+ totalFound++;
+ this.replaceMergeTags(matchedSubstring, item);
+ });
}
});
+ if (totalFound > 0) {
+ this.logger.log(`Found ${totalFound} merge tag${totalFound > 1 ? "s" : ""} in the page.`);
+ }
}
}
- /**
- * Checks if there are elements to be replaced.
- * @returns True if there are elements to be replaced, false otherwise.
- */
shouldRun() {
- return this.enElements.length > 0;
- }
- /**
- * Replaces all occurrences of data in the HTML elements.
- */
- replaceAll() {
- const regEx = /{engrid_data~\[([\w-]+)\]~?\[?(.+?)?\]?}/g;
- this.enElements.forEach((item) => {
- const array = item.innerHTML.matchAll(regEx);
- for (const match of array) {
- this.replaceItem(item, match);
- }
- });
- engrid_ENGrid.setBodyData("merge-tags-processed", "");
- }
- /**
- * Replaces a specific data item in the given HTML element.
- * @param where The HTML element where the replacement should occur.
- * @param item The matched data item.
- * @param key The key of the data item.
- * @param defaultValue The default value to use if the data item is not found.
- */
- replaceItem(where, [item, key, defaultValue]) {
- var _a;
- let value = (_a = engrid_ENGrid.getUrlParameter(`engrid_data[${key}]`)) !== null && _a !== void 0 ? _a : defaultValue;
- if (typeof value === "string") {
- value = value.replace(/\r?\\n|\n|\r/g, " ");
- }
- else {
- value = "";
+ if (!this.elementsFound) {
+ this.logger.log("No merge tags found. Skipping.");
+ return false;
}
- this.logger.log("Replacing", key, value);
- where.innerHTML = where.innerHTML.replace(item, value);
+ return true;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/data-hide.js
-// Hides elements based on URL arguments.
-//
-// The DataHide class is used to hide elements based on URL arguments.
-// It retrieves the elements to hide from the URL arguments and hides them.
-// If no elements are found, the constructor returns early.
-// Otherwise, it logs the found elements and hides them.
-
-class DataHide {
- constructor() {
- this.logger = new logger_EngridLogger("DataHide", "#333333", "#f0f0f0", "π");
- this.enElements = new Array();
- this.logger.log("Constructor");
- this.enElements = engrid_ENGrid.getUrlParameter("engrid_hide[]");
- if (!this.enElements || this.enElements.length === 0) {
- this.logger.log("No Elements Found");
- return;
- }
- this.logger.log("Elements Found:", this.enElements);
- this.hideAll();
+ addEventListeners() {
+ this._amount.onAmountChange.subscribe(() => {
+ setTimeout(() => {
+ this.updateFrequency();
+ }, 10);
+ });
+ this._frequency.onFrequencyChange.subscribe(() => {
+ setTimeout(() => {
+ this.searchElements();
+ this.updateFrequency();
+ }, 10);
+ });
}
- /**
- * Hides all the elements based on the URL arguments.
- */
- hideAll() {
- this.enElements.forEach((element) => {
- const item = Object.keys(element)[0];
- const type = Object.values(element)[0];
- this.hideItem(item, type);
+ updateFrequency() {
+ const frequency = this._frequency.frequency === "onetime"
+ ? "one-time"
+ : this._frequency.frequency;
+ const elemenst = document.querySelectorAll(".engrid-frequency");
+ elemenst.forEach((item) => {
+ if (item.classList.contains("engrid-frequency--lowercase")) {
+ item.innerHTML = frequency.toLowerCase();
+ }
+ else if (item.classList.contains("engrid-frequency--capitalized")) {
+ item.innerHTML = frequency.charAt(0).toUpperCase() + frequency.slice(1);
+ }
+ else if (item.classList.contains("engrid-frequency--uppercase")) {
+ item.innerHTML = frequency.toUpperCase();
+ }
+ else {
+ item.innerHTML = frequency;
+ }
});
- return;
}
- /**
- * Hides a specific element based on the item and type.
- * @param item - The item to hide (ID or class name).
- * @param type - The type of the item (either "id" or "class").
- */
- hideItem(item, type) {
- const regEx = /engrid_hide\[([\w-]+)\]/g;
- const itemData = [...item.matchAll(regEx)].map((match) => match[1])[0];
- switch (type) {
- case "id":
- const element = document.getElementById(itemData);
- if (element) {
- this.logger.log("Hiding By ID", itemData, element);
- element.setAttribute("hidden-via-url-argument", "");
- }
- else {
- this.logger.error("Element Not Found By ID", itemData);
- }
+ replaceMergeTags(tag, element) {
+ const frequency = this._frequency.frequency === "onetime"
+ ? "one-time"
+ : this._frequency.frequency;
+ const frequencyElement = document.createElement("span");
+ frequencyElement.classList.add("engrid-frequency");
+ frequencyElement.innerHTML = frequency;
+ switch (tag) {
+ case "[[frequency]]":
+ frequencyElement.classList.add("engrid-frequency--lowercase");
+ frequencyElement.innerHTML = frequencyElement.innerHTML.toLowerCase();
+ element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
break;
- case "class":
- default:
- const elements = document.getElementsByClassName(itemData);
- if (elements.length > 0) {
- for (let i = 0; i < elements.length; i++) {
- this.logger.log("Hiding By Class", itemData, elements[i]);
- elements[i].setAttribute("hidden-via-url-argument", "");
- }
- }
- else {
- this.logger.log("No Elements Found By Class", itemData);
- }
+ case "[[Frequency]]":
+ frequencyElement.classList.add("engrid-frequency--capitalized");
+ frequencyElement.innerHTML =
+ frequencyElement.innerHTML.charAt(0).toUpperCase() +
+ frequencyElement.innerHTML.slice(1);
+ element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
+ break;
+ case "[[FREQUENCY]]":
+ frequencyElement.classList.add("engrid-frequency--uppercase");
+ frequencyElement.innerHTML = frequencyElement.innerHTML.toUpperCase();
+ element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
break;
}
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/add-name-to-message.js
-/*
- Adds first and last name when First Name and Last Name fields lose focus if name shortcodes aren't present
-*/
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/universal-opt-in.js
+/**
+ * This class will add event listeners to every yes/no radio button or checkbox
+ * inside a universal opt-in element (any form block with the CSS class universal-opt-in). When the user clicks on a radio/checkbox
+ * button, we will search for every other radio/checkbox button inside the same
+ * universal opt-in element and mirror the user's selection.
+ * If instead of universal-opt-in you use universal-opt-in_null, the class will
+ * not mirror the user's selection when a radio "No" option is selected. Instead,
+ * it will unset all other radio buttons.
+ */
-class AddNameToMessage {
+class UniversalOptIn {
constructor() {
- if (!this.shouldRun()) {
- // Don't run the script if the page isn't email to target
+ this.logger = new logger_EngridLogger("UniversalOptIn", "#f0f0f0", "#d2691e", "πͺ");
+ this._elements = document.querySelectorAll(".universal-opt-in, .universal-opt-in_null");
+ if (!this.shouldRun())
return;
- }
- this.replaceNameShortcode("#en__field_supporter_firstName", "#en__field_supporter_lastName");
+ this.addEventListeners();
}
shouldRun() {
- return engrid_ENGrid.getPageType() === "EMAILTOTARGET";
+ if (this._elements.length === 0) {
+ this.logger.log("No universal opt-in elements found. Skipping.");
+ return false;
+ }
+ this.logger.log(`Found ${this._elements.length} universal opt-in elements.`);
+ return true;
}
- replaceNameShortcode(fName, lName) {
- const firstName = document.querySelector(fName);
- const lastName = document.querySelector(lName);
- let message = document.querySelector('[name="contact.message"]');
- let addedFirstName = false;
- let addedLastName = false;
- if (message) {
- if (message.value.includes("{user_data~First Name") ||
- message.value.includes("{user_data~Last Name")) {
- return;
- }
- else {
- if (!message.value.includes("{user_data~First Name") && firstName) {
- firstName.addEventListener("blur", (e) => {
- const target = e.target;
- if (message && !addedFirstName) {
- addedFirstName = true;
- message.value = message.value.concat("\n" + target.value);
+ addEventListeners() {
+ this._elements.forEach((element) => {
+ const yesNoElements = element.querySelectorAll(".en__field__input--radio, .en__field__input--checkbox");
+ if (yesNoElements.length > 0) {
+ yesNoElements.forEach((yesNoElement) => {
+ yesNoElement.addEventListener("click", () => {
+ if (yesNoElement instanceof HTMLInputElement &&
+ yesNoElement.getAttribute("type") === "checkbox") {
+ const yesNoValue = yesNoElement.checked;
+ if (yesNoValue) {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is checked");
+ yesNoElements.forEach((yesNoElement2) => {
+ if (yesNoElement === yesNoElement2)
+ return;
+ if (yesNoElement2 instanceof HTMLInputElement &&
+ yesNoElement2.getAttribute("type") === "checkbox")
+ yesNoElement2.checked = true;
+ });
+ }
+ else {
+ this.logger.log("Yes/No " +
+ yesNoElement.getAttribute("type") +
+ " is unchecked");
+ yesNoElements.forEach((yesNoElement2) => {
+ if (yesNoElement === yesNoElement2)
+ return;
+ if (yesNoElement2 instanceof HTMLInputElement &&
+ yesNoElement2.getAttribute("type") === "checkbox")
+ yesNoElement2.checked = false;
+ });
+ }
+ return;
}
- });
- }
- if (!message.value.includes("{user_data~Last Name") && lastName) {
- lastName.addEventListener("blur", (e) => {
- const target = e.target;
- if (message && !addedLastName) {
- addedLastName = true;
- message.value = message.value.concat(" " + target.value);
+ const yesNoValue = yesNoElement.getAttribute("value");
+ if (yesNoValue === "Y") {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is checked");
+ yesNoElements.forEach((yesNoElement2) => {
+ const fieldName = yesNoElement2.getAttribute("name");
+ const clickedFieldName = yesNoElement.getAttribute("name");
+ if (!fieldName || fieldName === clickedFieldName)
+ return;
+ engrid_ENGrid.setFieldValue(fieldName, "Y");
+ });
+ }
+ else {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is unchecked");
+ yesNoElements.forEach((yesNoElement2) => {
+ const fieldName = yesNoElement2.getAttribute("name");
+ const clickedFieldName = yesNoElement.getAttribute("name");
+ if (!fieldName || fieldName === clickedFieldName)
+ return;
+ if (element.classList.contains("universal-opt-in")) {
+ engrid_ENGrid.setFieldValue(fieldName, "N");
+ }
+ else {
+ yesNoElement2.checked = false;
+ }
+ });
}
});
- }
+ });
}
- }
+ });
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/expand-region-name.js
-// Populates hidden supporter field "Region Long Format" with expanded name (e.g FL becomes Florida)
-
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/stripe-financial-connections.js
+/**
+ * This component improves EN's implementation of Stripe Financial Connections.
+ * Enhancements:
+ * - When the modal is closed, it re-enables the submit button.
+ */
-class ExpandRegionName {
+class StripeFinancialConnections {
constructor() {
- this._form = en_form_EnForm.getInstance();
- this.logger = new logger_EngridLogger("ExpandRegionName", "#333333", "#00eb65", "π");
- if (this.shouldRun()) {
- const expandedRegionField = engrid_ENGrid.getOption("RegionLongFormat");
- console.log("expandedRegionField", expandedRegionField);
- const hiddenRegion = document.querySelector(`[name="${expandedRegionField}"]`);
- if (!hiddenRegion) {
- this.logger.log(`CREATED field ${expandedRegionField}`);
- engrid_ENGrid.createHiddenInput(expandedRegionField);
- }
- this._form.onValidate.subscribe(() => this.expandRegion());
- }
+ this.stripeModalOpen = false;
+ this.logger = new logger_EngridLogger("Stripe Financial Connections", "black", "pink", "ποΈ");
+ const observer = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ mutation.addedNodes.forEach((node) => {
+ if (!this.stripeModalOpen && this.isStripeModalNodeWIthIframe(node)) {
+ this.logger.log("Stripe Financial Connections modal opened.");
+ this.onStripeModalOpen();
+ }
+ });
+ mutation.removedNodes.forEach((node) => {
+ if (this.stripeModalOpen && this.isStripeModalNode(node)) {
+ this.logger.log("Stripe Financial Connections modal closed.");
+ this.onStripeModalClose();
+ }
+ });
+ });
+ });
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ });
}
- shouldRun() {
- return !!engrid_ENGrid.getOption("RegionLongFormat");
+ isStripeModalNode(node) {
+ return (node instanceof HTMLElement &&
+ node.hasAttribute("data-react-aria-top-layer"));
+ }
+ isStripeModalNodeWIthIframe(node) {
+ return !!(this.isStripeModalNode(node) &&
+ node instanceof HTMLElement &&
+ node.querySelector('iframe[src*="js.stripe.com"]'));
+ }
+ onStripeModalOpen() {
+ this.stripeModalOpen = true;
}
- expandRegion() {
- if (!this._form.validate)
- return;
- const userRegion = document.querySelector('[name="supporter.region"]'); // User entered region on the page
- const expandedRegionField = engrid_ENGrid.getOption("RegionLongFormat");
- const hiddenRegion = document.querySelector(`[name="${expandedRegionField}"]`); // Hidden region long form field
- if (!userRegion) {
- this.logger.log("No region field to populate the hidden region field with");
- return; // Don't populate hidden region field if user region field isn't on page
- }
- if (userRegion.tagName === "SELECT" && "options" in userRegion) {
- const regionValue = userRegion.options[userRegion.selectedIndex].innerText;
- hiddenRegion.value = regionValue;
- this.logger.log("Populated field", hiddenRegion.value);
- }
- else if (userRegion.tagName === "INPUT") {
- const regionValue = userRegion.value;
- hiddenRegion.value = regionValue;
- this.logger.log("Populated field", hiddenRegion.value);
- }
- return true;
+ onStripeModalClose() {
+ this.stripeModalOpen = false;
+ engrid_ENGrid.enableSubmit();
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/url-to-form.js
-// Component that allows to set a field value from URL parameters
-// Workflow:
-// 1. Loop through all the URL parameters
-// 2. Check if there's a match with the field name
-// 3. If there's a match AND the field is empty, set the value
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/give-by-select.js
-class UrlToForm {
+class GiveBySelect {
constructor() {
- this.logger = new logger_EngridLogger("UrlToForm", "white", "magenta", "π");
- this.urlParams = new URLSearchParams(document.location.search);
- if (!this.shouldRun())
+ this.logger = new logger_EngridLogger("GiveBySelect", "#FFF", "#333", "π");
+ this.transactionGiveBySelect = document.getElementsByName("transaction.giveBySelect");
+ this._frequency = DonationFrequency.getInstance();
+ if (!this.transactionGiveBySelect)
return;
- this.urlParams.forEach((value, key) => {
- const field = document.getElementsByName(key)[0];
- if (field) {
- if (field.type === "checkbox") {
- field.checked = value === "true" || value === "Y" || value === "1";
- engrid_ENGrid.setFieldValue(key, field.checked);
- this.logger.log(`Set: ${key} to ${field.checked}`);
+ this._frequency.onFrequencyChange.subscribe(() => this.checkPaymentTypeVisibility());
+ this.transactionGiveBySelect.forEach((giveBySelect) => {
+ giveBySelect.addEventListener("change", () => {
+ this.logger.log("Changed to " + giveBySelect.value);
+ engrid_ENGrid.setPaymentType(giveBySelect.value);
+ });
+ });
+ // Set the initial value of giveBySelect to the transaction.paymenttype field
+ const paymentType = engrid_ENGrid.getPaymentType();
+ if (paymentType) {
+ this.logger.log("Setting giveBySelect to " + paymentType);
+ const isCard = [
+ "card",
+ "visa",
+ "mastercard",
+ "amex",
+ "discover",
+ "diners",
+ "jcb",
+ "vi",
+ "mc",
+ "ax",
+ "dc",
+ "di",
+ "jc",
+ ].includes(paymentType.toLowerCase());
+ this.transactionGiveBySelect.forEach((giveBySelect) => {
+ if (isCard && giveBySelect.value.toLowerCase() === "card") {
+ giveBySelect.checked = true;
}
- else if (!["text", "textarea", "email"].includes(field.type) ||
- !field.value) {
- engrid_ENGrid.setFieldValue(key, value);
- this.logger.log(`Set: ${key} to ${value}`);
+ else if (giveBySelect.value.toLowerCase() === paymentType.toLowerCase()) {
+ giveBySelect.checked = true;
}
+ });
+ }
+ }
+ // Returns true if the selected payment type is visible
+ // Returns false if the selected payment type is not visible
+ isSelectedPaymentVisible() {
+ let visible = true;
+ this.transactionGiveBySelect.forEach((giveBySelect) => {
+ const container = giveBySelect.parentElement;
+ if (giveBySelect.checked && !engrid_ENGrid.isVisible(container)) {
+ this.logger.log(`Selected Payment Type is not visible: ${giveBySelect.value}`);
+ visible = false;
}
});
+ return visible;
}
- shouldRun() {
- return !!document.location.search && this.hasFields();
- }
- hasFields() {
- const ret = [...this.urlParams.keys()].map((key) => {
- return document.getElementsByName(key).length > 0;
- });
- return ret.includes(true);
+ // Checks if the selected payment type is visible
+ // If the selected payment type is not visible, it sets the payment type to the first visible option
+ checkPaymentTypeVisibility() {
+ window.setTimeout(() => {
+ var _a;
+ if (!this.isSelectedPaymentVisible()) {
+ this.logger.log("Setting payment type to first visible option");
+ const firstVisible = Array.from(this.transactionGiveBySelect).find((giveBySelect) => {
+ const container = giveBySelect.parentElement;
+ return engrid_ENGrid.isVisible(container);
+ });
+ if (firstVisible) {
+ this.logger.log("Setting payment type to ", firstVisible.value);
+ const container = firstVisible.parentElement;
+ (_a = container.querySelector("label")) === null || _a === void 0 ? void 0 : _a.click();
+ engrid_ENGrid.setPaymentType(firstVisible.value);
+ }
+ }
+ else {
+ this.logger.log("Selected Payment Type is visible");
+ }
+ }, 300);
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/required-if-visible.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/url-params-to-body-attrs.js
+//This component adds any url parameters that begin with "data-engrid-" to the body as attributes.
-class RequiredIfVisible {
+class UrlParamsToBodyAttrs {
constructor() {
- this.logger = new logger_EngridLogger("RequiredIfVisible", "#FFFFFF", "#811212", "π₯");
- this._form = en_form_EnForm.getInstance();
- this.requiredIfVisibleElements = document.querySelectorAll(`
- .i-required .en__field,
- .i1-required .en__field:nth-of-type(1),
- .i2-required .en__field:nth-of-type(2),
- .i3-required .en__field:nth-of-type(3),
- .i4-required .en__field:nth-of-type(4),
- .i5-required .en__field:nth-of-type(5),
- .i6-required .en__field:nth-of-type(6),
- .i7-required .en__field:nth-of-type(7),
- .i8-required .en__field:nth-of-type(8),
- .i9-required .en__field:nth-of-type(9),
- .i10-required .en__field:nth-of-type(10),
- .i11-required .en__field:nth-of-type(11)
- `);
- if (!this.shouldRun())
- return;
- this._form.onValidate.subscribe(this.validate.bind(this));
- }
- shouldRun() {
- return this.requiredIfVisibleElements.length > 0;
- }
- validate() {
- // We're converting the NodeListOf to an Array
- // because we need to reverse the order of the elements so the last error
- // is the highest element to get focus()
- Array.from(this.requiredIfVisibleElements)
- .reverse()
- .forEach((field) => {
- engrid_ENGrid.removeError(field);
- if (engrid_ENGrid.isVisible(field)) {
- this.logger.log(`${field.getAttribute("class")} is visible`);
- const fieldElement = field.querySelector("input:not([type=hidden]) , select, textarea");
- if (fieldElement &&
- fieldElement.closest("[data-unhidden]") === null &&
- !engrid_ENGrid.getFieldValue(fieldElement.getAttribute("name"))) {
- const fieldLabel = field.querySelector(".en__field__label");
- if (fieldLabel) {
- this.logger.log(`${fieldLabel.innerText} is required`);
- window.setTimeout(() => {
- engrid_ENGrid.setError(field, `${fieldLabel.innerText} is required`);
- }, 100);
- }
- else {
- this.logger.log(`${fieldElement.getAttribute("name")} is required`);
- window.setTimeout(() => {
- engrid_ENGrid.setError(field, `This field is required`);
- }, 100);
- }
- fieldElement.focus();
- this._form.validate = false;
- }
+ this.logger = new logger_EngridLogger("UrlParamsToBodyAttrs", "white", "magenta", "π");
+ this.urlParams = new URLSearchParams(document.location.search);
+ this.urlParams.forEach((value, key) => {
+ if (key.startsWith("data-engrid-")) {
+ engrid_ENGrid.setBodyData(key.split("data-engrid-")[1], value);
+ this.logger.log(`Set "${key}" on body to "${value}" from URL params`);
}
});
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/tidycontact.js
-var tidycontact_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/exit-intent-lightbox.js
-class TidyContact {
+
+class ExitIntentLightbox {
constructor() {
- var _a, _b, _c, _d, _e;
- this.logger = new logger_EngridLogger("TidyContact", "#FFFFFF", "#4d9068", "π§");
- this.endpoint = "https://api.tidycontact.io";
- this.wasCalled = false; // True if the API endpoint was called
- this.httpStatus = 0;
- this.timeout = 5; // Seconds to API Timeout
- this.isDirty = false; // True if the address was changed by the user
- this._form = en_form_EnForm.getInstance();
- this.countries_list = [
- ["Afghanistan", "af", "93", "070 123 4567"],
- ["Albania", "al", "355", "067 212 3456"],
- ["Algeria", "dz", "213", "0551 23 45 67"],
- ["American Samoa", "as", "1", "(684) 733-1234"],
- ["Andorra", "ad", "376", "312 345"],
- ["Angola", "ao", "244", "923 123 456"],
- ["Anguilla", "ai", "1", "(264) 235-1234"],
- ["Antigua and Barbuda", "ag", "1", "(268) 464-1234"],
- ["Argentina", "ar", "54", "011 15-2345-6789"],
- ["Armenia", "am", "374", "077 123456"],
- ["Aruba", "aw", "297", "560 1234"],
- ["Australia", "au", "61", "0412 345 678"],
- ["Austria", "at", "43", "0664 123456"],
- ["Azerbaijan", "az", "994", "040 123 45 67"],
- ["Bahamas", "bs", "1", "(242) 359-1234"],
- ["Bahrain", "bh", "973", "3600 1234"],
- ["Bangladesh", "bd", "880", "01812-345678"],
- ["Barbados", "bb", "1", "(246) 250-1234"],
- ["Belarus", "by", "375", "8 029 491-19-11"],
- ["Belgium", "be", "32", "0470 12 34 56"],
- ["Belize", "bz", "501", "622-1234"],
- ["Benin", "bj", "229", "90 01 12 34"],
- ["Bermuda", "bm", "1", "(441) 370-1234"],
- ["Bhutan", "bt", "975", "17 12 34 56"],
- ["Bolivia", "bo", "591", "71234567"],
- ["Bosnia and Herzegovina", "ba", "387", "061 123 456"],
- ["Botswana", "bw", "267", "71 123 456"],
- ["Brazil", "br", "55", "(11) 96123-4567"],
- ["British Indian Ocean Territory", "io", "246", "380 1234"],
- ["British Virgin Islands", "vg", "1", "(284) 300-1234"],
- ["Brunei", "bn", "673", "712 3456"],
- ["Bulgaria", "bg", "359", "048 123 456"],
- ["Burkina Faso", "bf", "226", "70 12 34 56"],
- ["Burundi", "bi", "257", "79 56 12 34"],
- ["Cambodia", "kh", "855", "091 234 567"],
- ["Cameroon", "cm", "237", "6 71 23 45 67"],
- ["Canada", "ca", "1", "(506) 234-5678"],
- ["Cape Verde", "cv", "238", "991 12 34"],
- ["Caribbean Netherlands", "bq", "599", "318 1234"],
- ["Cayman Islands", "ky", "1", "(345) 323-1234"],
- ["Central African Republic", "cf", "236", "70 01 23 45"],
- ["Chad", "td", "235", "63 01 23 45"],
- ["Chile", "cl", "56", "(2) 2123 4567"],
- ["China", "cn", "86", "131 2345 6789"],
- ["Christmas Island", "cx", "61", "0412 345 678"],
- ["Cocos Islands", "cc", "61", "0412 345 678"],
- ["Colombia", "co", "57", "321 1234567"],
- ["Comoros", "km", "269", "321 23 45"],
- ["Congo", "cd", "243", "0991 234 567"],
- ["Congo", "cg", "242", "06 123 4567"],
- ["Cook Islands", "ck", "682", "71 234"],
- ["Costa Rica", "cr", "506", "8312 3456"],
- ["CΓ΄te dβIvoire", "ci", "225", "01 23 45 6789"],
- ["Croatia", "hr", "385", "092 123 4567"],
- ["Cuba", "cu", "53", "05 1234567"],
- ["CuraΓ§ao", "cw", "599", "9 518 1234"],
- ["Cyprus", "cy", "357", "96 123456"],
- ["Czech Republic", "cz", "420", "601 123 456"],
- ["Denmark", "dk", "45", "32 12 34 56"],
- ["Djibouti", "dj", "253", "77 83 10 01"],
- ["Dominica", "dm", "1", "(767) 225-1234"],
- ["Dominican Republic", "do", "1", "(809) 234-5678"],
- ["Ecuador", "ec", "593", "099 123 4567"],
- ["Egypt", "eg", "20", "0100 123 4567"],
- ["El Salvador", "sv", "503", "7012 3456"],
- ["Equatorial Guinea", "gq", "240", "222 123 456"],
- ["Eritrea", "er", "291", "07 123 456"],
- ["Estonia", "ee", "372", "5123 4567"],
- ["Eswatini", "sz", "268", "7612 3456"],
- ["Ethiopia", "et", "251", "091 123 4567"],
- ["Falkland Islands", "fk", "500", "51234"],
- ["Faroe Islands", "fo", "298", "211234"],
- ["Fiji", "fj", "679", "701 2345"],
- ["Finland", "fi", "358", "041 2345678"],
- ["France", "fr", "33", "06 12 34 56 78"],
- ["French Guiana", "gf", "594", "0694 20 12 34"],
- ["French Polynesia", "pf", "689", "87 12 34 56"],
- ["Gabon", "ga", "241", "06 03 12 34"],
- ["Gambia", "gm", "220", "301 2345"],
- ["Georgia", "ge", "995", "555 12 34 56"],
- ["Germany", "de", "49", "01512 3456789"],
- ["Ghana", "gh", "233", "023 123 4567"],
- ["Gibraltar", "gi", "350", "57123456"],
- ["Greece", "gr", "30", "691 234 5678"],
- ["Greenland", "gl", "299", "22 12 34"],
- ["Grenada", "gd", "1", "(473) 403-1234"],
- ["Guadeloupe", "gp", "590", "0690 00 12 34"],
- ["Guam", "gu", "1", "(671) 300-1234"],
- ["Guatemala", "gt", "502", "5123 4567"],
- ["Guernsey", "gg", "44", "07781 123456"],
- ["Guinea", "gn", "224", "601 12 34 56"],
- ["Guinea-Bissau", "gw", "245", "955 012 345"],
- ["Guyana", "gy", "592", "609 1234"],
- ["Haiti", "ht", "509", "34 10 1234"],
- ["Honduras", "hn", "504", "9123-4567"],
- ["Hong Kong", "hk", "852", "5123 4567"],
- ["Hungary", "hu", "36", "06 20 123 4567"],
- ["Iceland", "is", "354", "611 1234"],
- ["India", "in", "91", "081234 56789"],
- ["Indonesia", "id", "62", "0812-345-678"],
- ["Iran", "ir", "98", "0912 345 6789"],
- ["Iraq", "iq", "964", "0791 234 5678"],
- ["Ireland", "ie", "353", "085 012 3456"],
- ["Isle of Man", "im", "44", "07924 123456"],
- ["Israel", "il", "972", "050-234-5678"],
- ["Italy", "it", "39", "312 345 6789"],
- ["Jamaica", "jm", "1", "(876) 210-1234"],
- ["Japan", "jp", "81", "090-1234-5678"],
- ["Jersey", "je", "44", "07797 712345"],
- ["Jordan", "jo", "962", "07 9012 3456"],
- ["Kazakhstan", "kz", "7", "8 (771) 000 9998"],
- ["Kenya", "ke", "254", "0712 123456"],
- ["Kiribati", "ki", "686", "72001234"],
- ["Kosovo", "xk", "383", "043 201 234"],
- ["Kuwait", "kw", "965", "500 12345"],
- ["Kyrgyzstan", "kg", "996", "0700 123 456"],
- ["Laos", "la", "856", "020 23 123 456"],
- ["Latvia", "lv", "371", "21 234 567"],
- ["Lebanon", "lb", "961", "71 123 456"],
- ["Lesotho", "ls", "266", "5012 3456"],
- ["Liberia", "lr", "231", "077 012 3456"],
- ["Libya", "ly", "218", "091-2345678"],
- ["Liechtenstein", "li", "423", "660 234 567"],
- ["Lithuania", "lt", "370", "(8-612) 34567"],
- ["Luxembourg", "lu", "352", "628 123 456"],
- ["Macau", "mo", "853", "6612 3456"],
- ["North Macedonia", "mk", "389", "072 345 678"],
- ["Madagascar", "mg", "261", "032 12 345 67"],
- ["Malawi", "mw", "265", "0991 23 45 67"],
- ["Malaysia", "my", "60", "012-345 6789"],
- ["Maldives", "mv", "960", "771-2345"],
- ["Mali", "ml", "223", "65 01 23 45"],
- ["Malta", "mt", "356", "9696 1234"],
- ["Marshall Islands", "mh", "692", "235-1234"],
- ["Martinique", "mq", "596", "0696 20 12 34"],
- ["Mauritania", "mr", "222", "22 12 34 56"],
- ["Mauritius", "mu", "230", "5251 2345"],
- ["Mayotte", "yt", "262", "0639 01 23 45"],
- ["Mexico", "mx", "52", "222 123 4567"],
- ["Micronesia", "fm", "691", "350 1234"],
- ["Moldova", "md", "373", "0621 12 345"],
- ["Monaco", "mc", "377", "06 12 34 56 78"],
- ["Mongolia", "mn", "976", "8812 3456"],
- ["Montenegro", "me", "382", "067 622 901"],
- ["Montserrat", "ms", "1", "(664) 492-3456"],
- ["Morocco", "ma", "212", "0650-123456"],
- ["Mozambique", "mz", "258", "82 123 4567"],
- ["Myanmar", "mm", "95", "09 212 3456"],
- ["Namibia", "na", "264", "081 123 4567"],
- ["Nauru", "nr", "674", "555 1234"],
- ["Nepal", "np", "977", "984-1234567"],
- ["Netherlands", "nl", "31", "06 12345678"],
- ["New Caledonia", "nc", "687", "75.12.34"],
- ["New Zealand", "nz", "64", "021 123 4567"],
- ["Nicaragua", "ni", "505", "8123 4567"],
- ["Niger", "ne", "227", "93 12 34 56"],
- ["Nigeria", "ng", "234", "0802 123 4567"],
- ["Niue", "nu", "683", "888 4012"],
- ["Norfolk Island", "nf", "672", "3 81234"],
- ["North Korea", "kp", "850", "0192 123 4567"],
- ["Northern Mariana Islands", "mp", "1", "(670) 234-5678"],
- ["Norway", "no", "47", "406 12 345"],
- ["Oman", "om", "968", "9212 3456"],
- ["Pakistan", "pk", "92", "0301 2345678"],
- ["Palau", "pw", "680", "620 1234"],
- ["Palestine", "ps", "970", "0599 123 456"],
- ["Panama", "pa", "507", "6123-4567"],
- ["Papua New Guinea", "pg", "675", "7012 3456"],
- ["Paraguay", "py", "595", "0961 456789"],
- ["Peru", "pe", "51", "912 345 678"],
- ["Philippines", "ph", "63", "0905 123 4567"],
- ["Poland", "pl", "48", "512 345 678"],
- ["Portugal", "pt", "351", "912 345 678"],
- ["Puerto Rico", "pr", "1", "(787) 234-5678"],
- ["Qatar", "qa", "974", "3312 3456"],
- ["RΓ©union", "re", "262", "0692 12 34 56"],
- ["Romania", "ro", "40", "0712 034 567"],
- ["Russia", "ru", "7", "8 (912) 345-67-89"],
- ["Rwanda", "rw", "250", "0720 123 456"],
- ["Saint BarthΓ©lemy", "bl", "590", "0690 00 12 34"],
- ["Saint Helena", "sh", "290", "51234"],
- ["Saint Kitts and Nevis", "kn", "1", "(869) 765-2917"],
- ["Saint Lucia", "lc", "1", "(758) 284-5678"],
- ["Saint Martin", "mf", "590", "0690 00 12 34"],
- ["Saint Pierre and Miquelon", "pm", "508", "055 12 34"],
- ["Saint Vincent and the Grenadines", "vc", "1", "(784) 430-1234"],
- ["Samoa", "ws", "685", "72 12345"],
- ["San Marino", "sm", "378", "66 66 12 12"],
- ["SΓ£o TomΓ© and PrΓncipe", "st", "239", "981 2345"],
- ["Saudi Arabia", "sa", "966", "051 234 5678"],
- ["Senegal", "sn", "221", "70 123 45 67"],
- ["Serbia", "rs", "381", "060 1234567"],
- ["Seychelles", "sc", "248", "2 510 123"],
- ["Sierra Leone", "sl", "232", "(025) 123456"],
- ["Singapore", "sg", "65", "8123 4567"],
- ["Sint Maarten", "sx", "1", "(721) 520-5678"],
- ["Slovakia", "sk", "421", "0912 123 456"],
- ["Slovenia", "si", "386", "031 234 567"],
- ["Solomon Islands", "sb", "677", "74 21234"],
- ["Somalia", "so", "252", "7 1123456"],
- ["South Africa", "za", "27", "071 123 4567"],
- ["South Korea", "kr", "82", "010-2000-0000"],
- ["South Sudan", "ss", "211", "0977 123 456"],
- ["Spain", "es", "34", "612 34 56 78"],
- ["Sri Lanka", "lk", "94", "071 234 5678"],
- ["Sudan", "sd", "249", "091 123 1234"],
- ["Suriname", "sr", "597", "741-2345"],
- ["Svalbard and Jan Mayen", "sj", "47", "412 34 567"],
- ["Sweden", "se", "46", "070-123 45 67"],
- ["Switzerland", "ch", "41", "078 123 45 67"],
- ["Syria", "sy", "963", "0944 567 890"],
- ["Taiwan", "tw", "886", "0912 345 678"],
- ["Tajikistan", "tj", "992", "917 12 3456"],
- ["Tanzania", "tz", "255", "0621 234 567"],
- ["Thailand", "th", "66", "081 234 5678"],
- ["Timor-Leste", "tl", "670", "7721 2345"],
- ["Togo", "tg", "228", "90 11 23 45"],
- ["Tokelau", "tk", "690", "7290"],
- ["Tonga", "to", "676", "771 5123"],
- ["Trinidad and Tobago", "tt", "1", "(868) 291-1234"],
- ["Tunisia", "tn", "216", "20 123 456"],
- ["Turkey", "tr", "90", "0501 234 56 78"],
- ["Turkmenistan", "tm", "993", "8 66 123456"],
- ["Turks and Caicos Islands", "tc", "1", "(649) 231-1234"],
- ["Tuvalu", "tv", "688", "90 1234"],
- ["U.S. Virgin Islands", "vi", "1", "(340) 642-1234"],
- ["Uganda", "ug", "256", "0712 345678"],
- ["Ukraine", "ua", "380", "050 123 4567"],
- ["United Arab Emirates", "ae", "971", "050 123 4567"],
- ["United Kingdom", "gb", "44", "07400 123456"],
- ["United States", "us", "1", "(201) 555-0123"],
- ["Uruguay", "uy", "598", "094 231 234"],
- ["Uzbekistan", "uz", "998", "8 91 234 56 78"],
- ["Vanuatu", "vu", "678", "591 2345"],
- ["Vatican City", "va", "39", "312 345 6789"],
- ["Venezuela", "ve", "58", "0412-1234567"],
- ["Vietnam", "vn", "84", "091 234 56 78"],
- ["Wallis and Futuna", "wf", "681", "82 12 34"],
- ["Western Sahara", "eh", "212", "0650-123456"],
- ["Yemen", "ye", "967", "0712 345 678"],
- ["Zambia", "zm", "260", "095 5123456"],
- ["Zimbabwe", "zw", "263", "071 234 5678"],
- ["Γ
land Islands", "ax", "358", "041 2345678"],
- ];
- this.countries_dropdown = null;
- this.country_ip = null;
- this.options = engrid_ENGrid.getOption("TidyContact");
- if (this.options === false || !((_a = this.options) === null || _a === void 0 ? void 0 : _a.cid))
- return;
- if (!this.shouldRun()) {
- this.logger.log("TidyContact is disabled on this page type");
+ this.opened = false;
+ this.dataLayer = window.dataLayer || [];
+ this.logger = new logger_EngridLogger("ExitIntentLightbox", "yellow", "black", "πͺ");
+ this.triggerDelay = 1000; // Don't run the exit intent lightbox until at least 1 second has passed after page load
+ this.triggerTimeout = null;
+ let options = "EngridExitIntent" in window ? window.EngridExitIntent : {};
+ this.options = Object.assign(Object.assign({}, ExitIntentOptionsDefaults), options);
+ if (!this.options.enabled) {
+ this.logger.log("Not enabled");
return;
}
- this.loadOptions();
- if (!this.hasAddressFields() && !this.phoneEnabled()) {
- this.logger.log("No address fields found");
+ if (get(this.options.cookieName)) {
+ this.logger.log("Not showing - cookie found.");
return;
}
- this.createFields();
- this.addEventListeners();
- if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
- !window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed() &&
- engrid_ENGrid.getFieldValue((_c = (_b = this.options) === null || _b === void 0 ? void 0 : _b.address_fields) === null || _c === void 0 ? void 0 : _c.address1) !=
- "") {
- this.logger.log("Address Field is not empty");
- this.isDirty = true;
- }
- if (this.phoneEnabled()) {
- this.createPhoneFields();
- this.createPhoneMarginVariable();
- this.logger.log("Phone Standardization is enabled");
- if (this.countryDropDownEnabled()) {
- this.renderFlagsDropDown();
+ const activeTriggers = Object.keys(this.options.triggers)
+ .filter((t) => this.options.triggers[t])
+ .join(", ");
+ this.logger.log("Enabled, waiting for trigger. Active triggers: " + activeTriggers);
+ this.watchForTriggers();
+ }
+ watchForTriggers() {
+ window.addEventListener("load", () => {
+ setTimeout(() => {
+ if (this.options.triggers.mousePosition) {
+ this.watchMouse();
+ }
+ if (this.options.triggers.visibilityState) {
+ this.watchDocumentVisibility();
+ }
+ }, this.triggerDelay); // Delay activation of triggers
+ });
+ }
+ watchMouse() {
+ document.addEventListener("mouseout", (e) => {
+ // If this is an autocomplete element.
+ if (e.target.tagName.toLowerCase() == "input")
+ return;
+ // Get the current viewport width.
+ const vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
+ // If the current mouse X position is within 50px of the right edge
+ // of the viewport, return.
+ if (e.clientX >= vpWidth - 50)
+ return;
+ // If the current mouse Y position is not within 50px of the top
+ // edge of the viewport, return.
+ if (e.clientY >= 50)
+ return;
+ // Reliable, works on mouse exiting window and
+ // user switching active program
+ const from = e.relatedTarget;
+ if (!from) {
+ this.logger.log("Triggered by mouse position");
+ this.open();
}
- const phoneField = engrid_ENGrid.getField((_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.address_fields) === null || _e === void 0 ? void 0 : _e.phone);
- if (phoneField) {
- phoneField.addEventListener("keyup", (e) => {
- this.handlePhoneInputKeydown(e);
- });
- this.setDefaultPhoneCountry();
+ if (!this.triggerTimeout) {
+ this.triggerTimeout = window.setTimeout(() => {
+ if (!from) {
+ this.logger.log("Triggered by mouse position");
+ this.open();
+ }
+ this.triggerTimeout = null;
+ }, this.triggerDelay);
}
- }
+ });
}
- shouldRun() {
- if (this.options &&
- this.options.page_types &&
- this.options.page_types.length > 0) {
- return this.options.page_types.includes(engrid_ENGrid.getPageType());
- }
- return true;
+ watchDocumentVisibility() {
+ const visibilityListener = () => {
+ if (document.visibilityState === "hidden") {
+ if (!this.triggerTimeout) {
+ this.triggerTimeout = window.setTimeout(() => {
+ this.logger.log("Triggered by visibilityState is hidden");
+ this.open();
+ document.removeEventListener("visibilitychange", visibilityListener);
+ this.triggerTimeout = null;
+ }, this.triggerDelay);
+ }
+ }
+ };
+ document.addEventListener("visibilitychange", visibilityListener);
}
- loadOptions() {
- var _a, _b, _c, _d;
- if (this.options) {
- if (!this.options.address_fields) {
- this.options.address_fields = {
- address1: "supporter.address1",
- address2: "supporter.address2",
- address3: "supporter.address3",
- city: "supporter.city",
- region: "supporter.region",
- postalCode: "supporter.postcode",
- country: "supporter.country",
- phone: "supporter.phoneNumber2", // Phone field
- };
+ open() {
+ var _a, _b, _c;
+ if (this.opened)
+ return;
+ engrid_ENGrid.setBodyData("exit-intent-lightbox", "open");
+ set(this.options.cookieName, "1", {
+ expires: this.options.cookieDuration,
+ });
+ document.body.insertAdjacentHTML("beforeend", `
+
+
+
+
X
+
+
${this.options.title}
+
${this.options.text}
+
+ ${this.options.buttonText}
+
+
+
+
+
+ `);
+ this.opened = true;
+ this.dataLayer.push({ event: "exit_intent_lightbox_shown" });
+ (_a = document
+ .querySelector(".ExitIntent__close")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
+ this.dataLayer.push({ event: "exit_intent_lightbox_closed" });
+ this.close();
+ });
+ (_b = document
+ .querySelector(".ExitIntent__overlay")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", (event) => {
+ if (event.target === event.currentTarget) {
+ this.dataLayer.push({ event: "exit_intent_lightbox_closed" });
+ this.close();
}
- this.options.address_enable = (_a = this.options.address_enable) !== null && _a !== void 0 ? _a : true;
- if (this.options.phone_enable) {
- this.options.phone_flags = (_b = this.options.phone_flags) !== null && _b !== void 0 ? _b : true;
- this.options.phone_country_from_ip =
- (_c = this.options.phone_country_from_ip) !== null && _c !== void 0 ? _c : true;
- this.options.phone_preferred_countries =
- (_d = this.options.phone_preferred_countries) !== null && _d !== void 0 ? _d : [];
+ });
+ (_c = document
+ .querySelector(".ExitIntent__button")) === null || _c === void 0 ? void 0 : _c.addEventListener("click", () => {
+ this.dataLayer.push({ event: "exit_intent_lightbox_cta_clicked" });
+ this.close();
+ const target = this.options.buttonLink;
+ if (target.startsWith(".") || target.startsWith("#")) {
+ const targetEl = document.querySelector(target);
+ if (targetEl) {
+ targetEl.scrollIntoView({ behavior: "smooth" });
+ }
}
- }
+ else {
+ window.open(target, "_blank");
+ }
+ });
}
- createFields() {
- var _a, _b, _c, _d, _e, _f;
- if (!this.options || !this.hasAddressFields())
+ close() {
+ var _a;
+ (_a = document.querySelector(".ExitIntent")) === null || _a === void 0 ? void 0 : _a.remove();
+ engrid_ENGrid.setBodyData("exit-intent-lightbox", "closed");
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/supporter-hub.js
+// Component that adds 4Site Special Features to the Supporter Hub Page
+
+class SupporterHub {
+ constructor() {
+ this.logger = new logger_EngridLogger("SupporterHub", "black", "pink", "π");
+ this._form = en_form_EnForm.getInstance();
+ if (!this.shoudRun())
return;
- // Creating Latitude and Longitude fields
- const latitudeField = engrid_ENGrid.getField("supporter.geo.latitude");
- const longitudeField = engrid_ENGrid.getField("supporter.geo.longitude");
- if (!latitudeField) {
- engrid_ENGrid.createHiddenInput("supporter.geo.latitude", "");
- this.logger.log("Creating Hidden Field: supporter.geo.latitude");
- }
- if (!longitudeField) {
- engrid_ENGrid.createHiddenInput("supporter.geo.longitude", "");
- this.logger.log("Creating Hidden Field: supporter.geo.longitude");
+ this.logger.log("Enabled");
+ this.watch();
+ this.preventDuplicateSubmits();
+ }
+ shoudRun() {
+ return ("pageJson" in window &&
+ "pageType" in window.pageJson &&
+ window.pageJson.pageType === "supporterhub");
+ }
+ watch() {
+ const form = engrid_ENGrid.enForm;
+ // Create a observer to watch the Form for overlays
+ const observer = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ if (mutation.type === "childList") {
+ mutation.addedNodes.forEach((node) => {
+ if (node.nodeName === "DIV") {
+ const overlay = node;
+ if (overlay.classList.contains("en__hubOverlay") ||
+ overlay.classList.contains("en__hubPledge__panels")) {
+ this.logger.log("Overlay found");
+ this.creditCardUpdate(node);
+ this.amountLabelUpdate(node);
+ }
+ }
+ });
+ }
+ });
+ });
+ // Start observing the Link ID
+ observer.observe(form, {
+ childList: true,
+ subtree: true,
+ });
+ // Run the Credit Card Update function in case the overlay is already present on page load
+ const hubOverlay = document.querySelector(".en__hubOverlay");
+ if (hubOverlay) {
+ this.creditCardUpdate(hubOverlay);
+ this.amountLabelUpdate(hubOverlay);
}
- if (this.options.record_field) {
- const recordField = engrid_ENGrid.getField(this.options.record_field);
- if (!recordField) {
- engrid_ENGrid.createHiddenInput(this.options.record_field, "");
- this.logger.log("Creating Hidden Field: " + this.options.record_field);
+ }
+ creditCardUpdate(overlay) {
+ window.setTimeout(() => {
+ // Check if the overlay has Credit Card field and Update Button
+ const ccField = overlay.querySelector("#en__hubPledge__field--ccnumber"), updateButton = overlay.querySelector(".en__hubUpdateCC__toggle");
+ if (ccField && updateButton) {
+ // When field gets focus, click the update button
+ ccField.addEventListener("focus", () => {
+ this.logger.log("Credit Card field focused");
+ updateButton.click();
+ });
}
- }
- if (this.options.date_field) {
- const dateField = engrid_ENGrid.getField(this.options.date_field);
- if (!dateField) {
- engrid_ENGrid.createHiddenInput(this.options.date_field, "");
- this.logger.log("Creating Hidden Field: " + this.options.date_field);
+ }, 300);
+ }
+ amountLabelUpdate(overlay) {
+ window.setTimeout(() => {
+ // Check if the overlay has Amounts, and set the currency symbol updated attribute
+ const amountContainer = overlay.querySelector(".en__field--donationAmt");
+ if (amountContainer) {
+ amountContainer
+ .querySelectorAll(".en__field__element--radio .en__field__item")
+ .forEach((node) => {
+ node.setAttribute("data-engrid-currency-symbol-updated", "true");
+ });
}
- }
- if (this.options.status_field) {
- const statusField = engrid_ENGrid.getField(this.options.status_field);
- if (!statusField) {
- engrid_ENGrid.createHiddenInput(this.options.status_field, "");
- this.logger.log("Creating Hidden Field: " + this.options.status_field);
+ }, 300);
+ }
+ // The supporter hub does not properly handle or prevent duplicate submits, so we add a listener to prevent this.
+ preventDuplicateSubmits() {
+ document.addEventListener("click", (e) => {
+ const btn = e.target.closest(".en__submit button");
+ if (!btn)
+ return;
+ if (btn.dataset.busy) {
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ return;
}
+ btn.dataset.busy = "true";
+ setTimeout(() => delete btn.dataset.busy, 10000);
+ }, true);
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/fast-form-fill.js
+/**
+ * This class adds body data attributes if all mandatory inputs, on specific form blocks, are filled.
+ * Related styling (to hide elements) can be found in "fast-form-fill.scss".
+ *
+ * To activate: add the custom class "fast-personal-details" or "fast-address-details"
+ * to the relevant form block.
+ */
+
+class FastFormFill {
+ constructor() {
+ this.logger = new logger_EngridLogger("FastFormFill", "white", "magenta", "π");
+ this.rememberMeEvents = RememberMeEvents.getInstance();
+ if (engrid_ENGrid.getOption("RememberMe")) {
+ this.rememberMeEvents.onLoad.subscribe((hasData) => {
+ this.logger.log("Remember me - onLoad", hasData);
+ this.run();
+ });
+ this.rememberMeEvents.onClear.subscribe(() => {
+ // This is a test for the onClear event
+ this.logger.log("Remember me - onClear");
+ });
}
- // If there's no Address 2 or Address 3 field, create them
- if (!engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address2)) {
- engrid_ENGrid.createHiddenInput((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2, "");
- this.logger.log("Creating Hidden Field: " + ((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.address2));
- }
- if (!engrid_ENGrid.getField((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.address3)) {
- engrid_ENGrid.createHiddenInput((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.address3, "");
- this.logger.log("Creating Hidden Field: " + ((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.address3));
+ else {
+ this.run();
}
}
- createPhoneFields() {
- if (!this.options)
- return;
- engrid_ENGrid.createHiddenInput("tc.phone.country", "");
- this.logger.log("Creating hidden field: tc.phone.country");
- if (this.options.phone_record_field) {
- const recordField = engrid_ENGrid.getField(this.options.phone_record_field);
- if (!recordField) {
- engrid_ENGrid.createHiddenInput(this.options.phone_record_field, "");
- this.logger.log("Creating hidden field: " + this.options.phone_record_field);
+ run() {
+ const fastPersonalDetailsFormBlocks = document.querySelectorAll(".en__component--formblock.fast-personal-details");
+ if (fastPersonalDetailsFormBlocks.length > 0) {
+ if ([...fastPersonalDetailsFormBlocks].every((formBlock) => FastFormFill.allMandatoryInputsAreFilled(formBlock))) {
+ this.logger.log("Personal details - All mandatory inputs are filled");
+ engrid_ENGrid.setBodyData("hide-fast-personal-details", "true");
+ }
+ else {
+ this.logger.log("Personal details - Not all mandatory inputs are filled");
+ engrid_ENGrid.setBodyData("hide-fast-personal-details", "false");
}
}
- if (this.options.phone_date_field) {
- const dateField = engrid_ENGrid.getField(this.options.phone_date_field);
- if (!dateField) {
- engrid_ENGrid.createHiddenInput(this.options.phone_date_field, "");
- this.logger.log("Creating hidden field: " + this.options.phone_date_field);
+ const fastAddressDetailsFormBlocks = document.querySelectorAll(".en__component--formblock.fast-address-details");
+ if (fastAddressDetailsFormBlocks.length > 0) {
+ if ([...fastAddressDetailsFormBlocks].every((formBlock) => FastFormFill.allMandatoryInputsAreFilled(formBlock))) {
+ this.logger.log("Address details - All mandatory inputs are filled");
+ engrid_ENGrid.setBodyData("hide-fast-address-details", "true");
+ }
+ else {
+ this.logger.log("Address details - Not all mandatory inputs are filled");
+ engrid_ENGrid.setBodyData("hide-fast-address-details", "false");
}
}
- if (this.options.phone_status_field) {
- const statusField = engrid_ENGrid.getField(this.options.phone_status_field);
- if (!statusField) {
- engrid_ENGrid.createHiddenInput(this.options.phone_status_field, "");
- this.logger.log("Creating hidden field: " + this.options.phone_status_field);
+ }
+ static allMandatoryInputsAreFilled(formBlock) {
+ const fields = formBlock.querySelectorAll(".en__mandatory input, .en__mandatory select, .en__mandatory textarea");
+ return [...fields].every((input) => {
+ if (input.type === "radio" || input.type === "checkbox") {
+ const inputs = document.querySelectorAll('[name="' + input.name + '"]');
+ return [...inputs].some((radioOrCheckbox) => radioOrCheckbox.checked);
+ }
+ else {
+ return input.value !== null && input.value.trim() !== "";
+ }
+ });
+ }
+ static someMandatoryInputsAreFilled(formBlock) {
+ const fields = formBlock.querySelectorAll(".en__mandatory input, .en__mandatory select, .en__mandatory textarea");
+ return [...fields].some((input) => {
+ if (input.type === "radio" || input.type === "checkbox") {
+ const inputs = document.querySelectorAll('[name="' + input.name + '"]');
+ return [...inputs].some((radioOrCheckbox) => radioOrCheckbox.checked);
}
+ else {
+ return input.value !== null && input.value.trim() !== "";
+ }
+ });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/set-attr.js
+/*+
+ The class is used to set body attributes via click handlers.
+ The format is "setattr--{attribute}--{value}".
+ e.g. setattr--data-engrid-hide-fast-address-details--true
+ */
+
+class SetAttr {
+ constructor() {
+ this.logger = new logger_EngridLogger("SetAttr", "black", "yellow", "π");
+ const enGrid = document.getElementById("engrid");
+ if (enGrid) {
+ enGrid.addEventListener("click", (e) => {
+ const clickedEl = e.target;
+ if (typeof clickedEl.className !== "string") {
+ return;
+ }
+ const clickedElClassNames = clickedEl.className.split(" ");
+ if (clickedElClassNames.some((className) => className.startsWith("setattr--"))) {
+ clickedEl.classList.forEach((className) => {
+ //Check element has class with format "setattr--attribute--value"
+ const match = className.match(/^setattr--(.+)--(.+)$/i);
+ if (match && match[1] && match[2]) {
+ this.logger.log(`Clicked element with class "${className}". Setting body attribute "${match[1]}" to "${match[2]}"`);
+ engrid_ENGrid.setBodyData(match[1].replace("data-engrid-", ""), match[2]);
+ }
+ });
+ }
+ });
}
}
- createPhoneMarginVariable() {
- var _a;
- if (!this.options)
- return;
- const phone = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
- if (phone) {
- const phoneStyle = window.getComputedStyle(phone);
- const marginTop = phoneStyle.marginTop;
- const marginBottom = phoneStyle.marginBottom;
- document.documentElement.style.setProperty("--tc-phone-margin-top", marginTop);
- document.documentElement.style.setProperty("--tc-phone-margin-bottom", marginBottom);
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/show-if-present.js
+/**
+ * This class contains the logic for special classes that can be used to hide elements if
+ * certain supporter questions are present or absent.
+ * Typically, this can be used to hide elements when an opt in question is not rendered on the page
+ * because the supporter came from a campaign link and is already opted in, so EN doesn't render
+ * the question on the page.
+ *
+ * The class names are of the format:
+ * engrid__supporterquestions{id}-present -- show this element when the supporter question is present
+ * engrid__supporterquestions{id}-absent -- show this element when the supporter question is absent
+ *
+ * The {id} is the id of the supporter question. This can be found by inspecting the element on the page.
+ *
+ * It's also possible to combine multiple questions using the following format. These examples show 2 questions,
+ * but you can use as many as you like:
+ * engrid__supporterquestions{id1}__supporterquestions{id2}-present -- show this element when EITHER question is present
+ * engrid__supporterquestions{id1}__supporterquestions{id2}-absent -- show this element when EITHER question is absent
+ */
+
+class ShowIfPresent {
+ constructor() {
+ this.logger = new logger_EngridLogger("ShowIfPresent", "yellow", "black", "π");
+ this.elements = [];
+ if (this.shouldRun()) {
+ this.run();
}
}
- addEventListeners() {
- if (!this.options)
- return;
- // Add event listeners to fields
- if (this.options.address_fields) {
- for (const [key, value] of Object.entries(this.options.address_fields)) {
- const field = engrid_ENGrid.getField(value);
- if (!field)
- continue;
- field.addEventListener("change", () => {
- this.logger.log("Changed " + field.name, true);
- this.isDirty = true;
+ shouldRun() {
+ // Check if we have any elements on the page that match the pattern for this functionality
+ // e.g. engrid__supporterquestions{id}__supporterquestions{id}-present, etc.
+ this.elements = [
+ ...document.querySelectorAll('[class*="engrid__supporterquestions"]'),
+ ].filter((el) => {
+ const classNames = el.className.split(" ");
+ return classNames.some((className) => /^engrid__supporterquestions\d+(__supporterquestions\d+)*-(present|absent)$/.test(className));
+ });
+ return this.elements.length > 0;
+ }
+ run() {
+ const actions = [];
+ // Create an array of actions for each element we have
+ this.elements.forEach((el) => {
+ // Mapping to an object with the class name, field name(s), and type
+ const classNames = el.className.split(" ");
+ const matchingClass = classNames.find((className) => /^engrid__supporterquestions\d+(__supporterquestions\d+)*-(present|absent)$/.test(className));
+ if (!matchingClass)
+ return null;
+ const typeIndex = matchingClass.lastIndexOf("-");
+ const type = matchingClass.substring(typeIndex + 1);
+ // Getting an array of the matching input names
+ // e.g. engrid__supporterquestions12345-present => ['supporter.questions.12345']
+ // e.g. engrid__supporterquestions12345__supporterquestions67890-present => ['supporter.questions.12345', 'supporter.questions.67890']
+ const inputIds = matchingClass
+ .substring(8, typeIndex)
+ .split("__")
+ .map((id) => `supporter.questions.${id.substring(18)}`);
+ actions.push({
+ class: matchingClass,
+ fieldNames: inputIds,
+ type: type,
+ });
+ });
+ //Process the actions
+ actions.forEach((action) => {
+ const inputElements = action.fieldNames.map((fieldName) => document.getElementsByName(fieldName)[0]);
+ const elements = document.querySelectorAll(`.${action.class}`);
+ const areAllInputsPresent = inputElements.every((input) => !!input);
+ const areAllInputsAbsent = inputElements.every((input) => !input);
+ // Hide the elements based on AND conditions
+ if ((action.type === "present" && areAllInputsAbsent) ||
+ (action.type === "absent" && areAllInputsPresent)) {
+ this.logger.log(`Conditions not met, hiding elements with class ${action.class}`);
+ elements.forEach((el) => {
+ el.style.display = "none";
});
}
+ });
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/en-validators.js
+// This component uses EN's Custom Validators on the client side to validate form fields.
+// It's currently behind a feature flag, so it's not enabled by default.
+// To enable it, add the following to your options:
+// ENValidators: true
+
+class ENValidators {
+ constructor() {
+ this._form = en_form_EnForm.getInstance();
+ this._enElements = null;
+ this.logger = new logger_EngridLogger("ENValidators", "white", "darkolivegreen", "π§");
+ if (!this.loadValidators()) {
+ // This is an error to flag a racing condition. If the script is loaded before the validators are loaded, it will not work.
+ this.logger.error("Not Loaded");
+ return;
}
- // Add event listener to submit
- this._form.onSubmit.subscribe(this.callAPI.bind(this));
- // Attach the API call event to the Give By Select to anticipate the use of Digital Wallets
- const transactionGiveBySelect = document.getElementsByName("transaction.giveBySelect");
- if (transactionGiveBySelect) {
- transactionGiveBySelect.forEach((giveBySelect) => {
- giveBySelect.addEventListener("change", () => {
- if (["stripedigitalwallet", "paypaltouch"].includes(giveBySelect.value.toLowerCase())) {
- this.logger.log("Clicked Digital Wallet Button");
- window.setTimeout(() => {
- this.callAPI();
- }, 500);
- }
- });
- });
- }
- }
- checkSum(str) {
- return tidycontact_awaiter(this, void 0, void 0, function* () {
- // encode as UTF-8
- const msgBuffer = new TextEncoder().encode(str);
- // hash the message
- const hashBuffer = yield crypto.subtle.digest("SHA-256", msgBuffer);
- // convert ArrayBuffer to Array
- const hashArray = Array.from(new Uint8Array(hashBuffer));
- // convert bytes to hex string
- const hashHex = hashArray
- .map((b) => ("00" + b.toString(16)).slice(-2))
- .join("");
- return hashHex;
- });
- }
- todaysDate() {
- return new Date()
- .toLocaleString("en-ZA", {
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- })
- .replace(/\/+/g, ""); // Format date as YYYYMMDD
+ if (!this.shouldRun()) {
+ // If there's no custom validators, get out
+ this.logger.log("Not Needed");
+ return;
+ }
+ this._form.onValidate.subscribe(this.enOnValidate.bind(this));
}
- countryAllowed(country) {
- var _a;
- if (!this.options)
+ loadValidators() {
+ if (!engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enValidation", "validation", "validators")) {
return false;
- // If the country list is empty, allow all countries
- if (!this.options.countries || this.options.countries.length === 0) {
- return true;
}
- return !!((_a = this.options.countries) === null || _a === void 0 ? void 0 : _a.includes(country.toLowerCase()));
+ // Loop through the array validators and add them to this._enElements
+ const validators = window.EngagingNetworks.require._defined.enValidation.validation
+ .validators;
+ this._enElements = validators.reduce((acc, validator) => {
+ if ("type" in validator && validator.type === "CUST") {
+ const container = document.querySelector(".en__field--" + validator.field);
+ const field = container
+ ? container.querySelector("input, select, textarea")
+ : null;
+ if (field) {
+ field.addEventListener("input", this.liveValidate.bind(this, container, field, validator.regex, validator.message));
+ acc.push({
+ container: container,
+ field: field,
+ regex: validator.regex,
+ message: validator.message,
+ });
+ }
+ }
+ return acc;
+ }, []);
+ return true;
}
- fetchTimeOut(url, params) {
- const abort = new AbortController();
- const signal = abort.signal;
- params = Object.assign(Object.assign({}, params), { signal });
- const promise = fetch(url, params);
- if (signal)
- signal.addEventListener("abort", () => abort.abort());
- const timeout = setTimeout(() => abort.abort(), this.timeout * 1000);
- return promise.finally(() => clearTimeout(timeout));
+ // Should we run the script?
+ shouldRun() {
+ return (engrid_ENGrid.getOption("ENValidators") &&
+ this._enElements &&
+ this._enElements.length > 0);
}
- writeError(error) {
- if (!this.options)
+ // Don't submit the form if any of the fields are invalid
+ enOnValidate() {
+ if (!this._enElements || this._form.validate === false) {
return;
- const recordField = engrid_ENGrid.getField(this.options.record_field);
- const dateField = engrid_ENGrid.getField(this.options.date_field);
- const statusField = engrid_ENGrid.getField(this.options.status_field);
- if (recordField) {
- let errorType = "";
- switch (this.httpStatus) {
- case 400:
- errorType = "Bad Request";
- break;
- case 401:
- errorType = "Unauthorized";
- break;
- case 403:
- errorType = "Forbidden";
- break;
- case 404:
- errorType = "Not Found";
- break;
- case 408:
- errorType = "API Request Timeout";
- break;
- case 500:
- errorType = "Internal Server Error";
- break;
- case 503:
- errorType = "Service Unavailable";
- break;
- default:
- errorType = "Unknown Error";
- break;
- }
- const errorData = {
- status: this.httpStatus,
- error: typeof error === "string" ? error : errorType.toUpperCase(),
- };
- recordField.value = JSON.stringify(errorData);
}
- if (dateField) {
- dateField.value = this.todaysDate();
+ this._enElements.forEach((element) => {
+ const fieldValidation = this.liveValidate(element.container, element.field, element.regex, element.message);
+ if (!fieldValidation) {
+ this._form.validate = false;
+ element.field.focus();
+ return;
+ }
+ });
+ this._form.validate = true;
+ }
+ // Validate the field on the fly
+ liveValidate(container, field, regex, message) {
+ const value = engrid_ENGrid.getFieldValue(field.getAttribute("name") || "");
+ // Do not validate empty fields, that's the job of the required validator
+ if (value === "") {
+ return true;
}
- if (statusField) {
- statusField.value = "ERROR-API";
+ this.logger.log(`Live Validate ${field.getAttribute("name")} with ${regex}`);
+ // compare the value of the field with the regex
+ if (!value.match(regex)) {
+ // If the value is not valid, add the error message
+ engrid_ENGrid.setError(container, message);
+ return false;
}
+ // If the value is valid, remove the error message
+ engrid_ENGrid.removeError(container);
+ return true;
}
- setFields(data) {
- var _a, _b, _c, _d, _e;
- if (!this.options || !this.options.address_enable)
- return {};
- let response = {};
- const country = this.getCountry();
- const postalCodeValue = engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.postalCode);
- const zipDivider = (_b = this.options.us_zip_divider) !== null && _b !== void 0 ? _b : "+";
- // Check if there's no address2 field
- const address2Field = engrid_ENGrid.getField((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.address2);
- if ("address2" in data && !address2Field) {
- const address = engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.address1);
- if (address == data.address1 + " " + data.address2) {
- delete data.address1;
- delete data.address2;
- }
- else {
- data.address1 = data.address1 + " " + data.address2;
- delete data.address2;
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/modal.js
+
+class Modal {
+ constructor(options) {
+ this.modal = null;
+ this.defaultOptions = {
+ onClickOutside: "close",
+ addCloseButton: false,
+ closeButtonLabel: "Okay!",
+ customClass: "",
+ showCloseX: true,
+ };
+ this.focusTrapHandler = (e) => {
+ const modalElement = this.modal;
+ const focusableElements = [
+ ...modalElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),
+ ];
+ const firstFocusable = focusableElements[0];
+ const lastFocusable = focusableElements[focusableElements.length - 1];
+ const isTabPressed = e.key === "Tab";
+ if (!isTabPressed) {
+ return;
}
- }
- if ("postalCode" in data &&
- postalCodeValue.replace("+", zipDivider) ===
- data.postalCode.replace("+", zipDivider)) {
- // Postal code is the same
- delete data.postalCode;
- }
- // Set the fields
- for (const key in data) {
- const fieldKey = this.options.address_fields &&
- Object.keys(this.options.address_fields).includes(key)
- ? this.options.address_fields[key]
- : key;
- const field = engrid_ENGrid.getField(fieldKey);
- if (field) {
- let value = data[key];
- if (key === "postalCode" &&
- ["US", "USA", "United States"].includes(country)) {
- value = (_e = value.replace("+", zipDivider)) !== null && _e !== void 0 ? _e : ""; // Replace the "+" with the zip divider
+ if (e.shiftKey) {
+ if (document.activeElement === firstFocusable) {
+ e.preventDefault();
+ lastFocusable.focus();
}
- response[key] = { from: field.value, to: value };
- this.logger.log(`Set ${field.name} to ${value} (${field.value})`);
- engrid_ENGrid.setFieldValue(fieldKey, value, false);
}
else {
- this.logger.log(`Field ${key} not found`);
+ if (document.activeElement === lastFocusable) {
+ e.preventDefault();
+ firstFocusable.focus();
+ }
}
+ };
+ this.options = Object.assign(Object.assign({}, this.defaultOptions), options);
+ this.modalContent = this.getModalContent();
+ this.createModal();
+ }
+ createModal() {
+ var _a;
+ this.modal = document.createElement("div");
+ this.modal.classList.add("engrid-modal", "modal--hidden");
+ if (this.options.customClass && this.options.customClass !== "") {
+ this.options.customClass.split(" ").forEach((customClass) => {
+ if (!customClass)
+ return;
+ this.modal.classList.add(customClass);
+ });
}
- return response;
+ if (this.options.showCloseX) {
+ this.modal.classList.add("engrid-modal--close-x");
+ }
+ this.modal.setAttribute("aria-hidden", "true");
+ this.modal.setAttribute("role", "dialog");
+ this.modal.setAttribute("aria-modal", "true");
+ this.modal.setAttribute("tabindex", "-1");
+ this.modal.innerHTML = `
+
+ `;
+ (_a = document.getElementById("engrid")) === null || _a === void 0 ? void 0 : _a.appendChild(this.modal);
+ const modalBody = this.modal.querySelector(".engrid-modal__body");
+ if (this.modalContent instanceof NodeList) {
+ this.modalContent.forEach((content) => {
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(content);
+ });
+ }
+ else if (typeof this.modalContent === "string") {
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.insertAdjacentHTML("beforeend", this.modalContent);
+ }
+ else {
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(this.modalContent);
+ }
+ if (this.options.addCloseButton) {
+ const button = document.createElement("button");
+ button.classList.add("engrid-modal__button");
+ button.textContent = this.options.closeButtonLabel;
+ button.addEventListener("click", () => {
+ this.close();
+ });
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(button);
+ }
+ this.addEventListeners();
}
- hasAddressFields() {
- var _a, _b, _c, _d, _e, _f;
- if (!this.options || !this.options.address_enable)
- return false;
- const address1 = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
- const address2 = engrid_ENGrid.getField((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2);
- const city = engrid_ENGrid.getField((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.city);
- const region = engrid_ENGrid.getField((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.region);
- const postalCode = engrid_ENGrid.getField((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.postalCode);
- const country = engrid_ENGrid.getField((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.country);
- return !!(address1 || address2 || city || region || postalCode || country);
+ addEventListeners() {
+ var _a, _b, _c, _d, _e;
+ // Close event on top X
+ (_b = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector(".engrid-modal__close")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", () => {
+ this.close();
+ });
+ // Bounce scale when clicking outside of modal
+ (_d = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector(".engrid-modal__overlay")) === null || _d === void 0 ? void 0 : _d.addEventListener("click", (event) => {
+ if (event.target === event.currentTarget) {
+ if (this.options.onClickOutside === "close") {
+ this.close();
+ }
+ else if (this.options.onClickOutside === "bounce") {
+ const modal = document.querySelector(".engrid-modal");
+ if (modal) {
+ modal.classList.remove("engrid-modal--scale");
+ void modal.clientWidth;
+ modal.classList.add("engrid-modal--scale");
+ }
+ }
+ }
+ });
+ // Close on "modal__close" click
+ const closeEls = (_e = this.modal) === null || _e === void 0 ? void 0 : _e.querySelectorAll(".modal__close");
+ closeEls === null || closeEls === void 0 ? void 0 : closeEls.forEach((el) => {
+ el.addEventListener("click", () => {
+ this.close();
+ });
+ });
}
- canUseAPI() {
+ open() {
var _a, _b, _c, _d;
- if (!this.options || !this.hasAddressFields())
- return false;
- const country = !!this.getCountry();
- const address1 = !!engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
- const city = !!engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.city);
- const region = !!engrid_ENGrid.getFieldValue((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.region);
- const postalCode = !!engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.postalCode);
- if (country && address1) {
- return (city && region) || postalCode;
- }
- this.logger.log("API cannot be used");
- return false;
+ engrid_ENGrid.setBodyData("has-lightbox", "true");
+ (_a = this.modal) === null || _a === void 0 ? void 0 : _a.classList.remove("modal--hidden");
+ (_b = this.modal) === null || _b === void 0 ? void 0 : _b.removeAttribute("aria-hidden");
+ const container = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector(".engrid-modal__container");
+ container === null || container === void 0 ? void 0 : container.focus({ preventScroll: true });
+ (_d = this.modal) === null || _d === void 0 ? void 0 : _d.addEventListener("keydown", this.focusTrapHandler);
}
- canUsePhoneAPI() {
- var _a;
- if (!this.options)
- return false;
- if (this.phoneEnabled()) {
- const phone = !!engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
- const countryPhone = !!engrid_ENGrid.getFieldValue("tc.phone.country");
- return phone && countryPhone;
- }
- this.logger.log("Phone API is not enabled");
- return false;
+ close() {
+ var _a, _b, _c;
+ engrid_ENGrid.setBodyData("has-lightbox", false);
+ (_a = this.modal) === null || _a === void 0 ? void 0 : _a.classList.add("modal--hidden");
+ (_b = this.modal) === null || _b === void 0 ? void 0 : _b.setAttribute("aria-hidden", "true");
+ (_c = this.modal) === null || _c === void 0 ? void 0 : _c.removeEventListener("keydown", this.focusTrapHandler);
}
- getCountry() {
- var _a, _b;
- if (!this.options)
- return "";
- const countryFallback = (_a = this.options.country_fallback) !== null && _a !== void 0 ? _a : "";
- const country = engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.country);
- return country || countryFallback.toUpperCase();
+ getModalContent() {
+ return "Default Modal Content ";
}
- getCountryByCode(code) {
- var _a;
- const countryItem = (_a = this.countries_list.find((country) => country.includes(code))) !== null && _a !== void 0 ? _a : "";
- if (countryItem) {
- return {
- name: countryItem[0],
- code: countryItem[1],
- dialCode: countryItem[2],
- placeholder: countryItem[3],
- };
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/postal-code-validator.js
+
+
+
+// Conditionally validates the postcode field for a US format zip code
+// If US is selected as the country, a country has not been selected yet
+// or if there is no country field
+// Allows blank zip code if zip code is not required.
+class PostalCodeValidator {
+ constructor() {
+ var _a, _b;
+ this.postalCodeField = engrid_ENGrid.getField("supporter.postcode");
+ this._form = en_form_EnForm.getInstance();
+ this.logger = new logger_EngridLogger("Postal Code Validator", "white", "red", "π¬");
+ this.supportedSeparators = ["+", "-", " "];
+ this.separator = this.getSeparator();
+ this.regexSeparator = this.getRegexSeparator(this.separator);
+ if (this.shouldRun()) {
+ (_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.addEventListener("blur", () => this.validate());
+ (_b = this.postalCodeField) === null || _b === void 0 ? void 0 : _b.addEventListener("input", () => this.liveValidate());
+ this._form.onValidate.subscribe(() => {
+ if (!this._form.validate)
+ return;
+ this.liveValidate();
+ // It seems like we need some delay or EN removes our error message.
+ setTimeout(() => {
+ this.validate();
+ }, 100);
+ // We dont need to validate the zip code, or it is valid
+ const postalCodeValid = !this.shouldValidateUSZipCode() || this.isValidUSZipCode();
+ this._form.validate = postalCodeValid;
+ if (!postalCodeValid) {
+ this.logger.log(`Invalid Zip Code ${this.postalCodeField.value}`);
+ this.postalCodeField.scrollIntoView({ behavior: "smooth" });
+ }
+ return postalCodeValid;
+ });
}
- return null;
}
- phoneEnabled() {
- return !!(this.options && this.options.phone_enable);
+ shouldRun() {
+ return !!(engrid_ENGrid.getOption("PostalCodeValidator") && this.postalCodeField);
}
- countryDropDownEnabled() {
- return !!(this.options && this.options.phone_flags);
+ validate() {
+ if (this.shouldValidateUSZipCode() && !this.isValidUSZipCode()) {
+ engrid_ENGrid.setError(".en__field--postcode", `Please enter a valid ZIP Code of ##### or #####${this.separator}####`);
+ }
+ else {
+ engrid_ENGrid.removeError(".en__field--postcode");
+ }
}
- getCountryFromIP() {
- return tidycontact_awaiter(this, void 0, void 0, function* () {
- return fetch(`https://${window.location.hostname}/cdn-cgi/trace`)
- .then((res) => res.text())
- .then((t) => {
- let data = t.replace(/[\r\n]+/g, '","').replace(/\=+/g, '":"');
- data = '{"' + data.slice(0, data.lastIndexOf('","')) + '"}';
- const jsondata = JSON.parse(data);
- this.country_ip = jsondata.loc;
- return this.country_ip;
- });
- });
+ isValidUSZipCode() {
+ var _a, _b;
+ const zipCodeRequired = !!document.querySelector(".en__field--postcode.en__mandatory");
+ // If zip code is not required in EN Form Block and the field is empty, it is valid
+ if (!zipCodeRequired && ((_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.value) === "") {
+ return true;
+ }
+ const postalCodeRegex = new RegExp(`^\\d{5}(${this.regexSeparator}\\d{4})?$`);
+ return !!((_b = this.postalCodeField) === null || _b === void 0 ? void 0 : _b.value.match(postalCodeRegex));
}
- renderFlagsDropDown() {
+ /**
+ * Formats the zip code to #####-#### as the user inputs it
+ * The separator is determined by the TidyContact option, but defaults to "-"
+ */
+ liveValidate() {
var _a;
- if (!this.options)
- return;
- const phoneInput = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
- if (!phoneInput)
+ if (!this.shouldValidateUSZipCode())
return;
- this.countries_dropdown = document.createElement("div");
- this.countries_dropdown.classList.add("tc-flags-container");
- const selectedFlag = document.createElement("div");
- selectedFlag.classList.add("tc-selected-flag");
- selectedFlag.setAttribute("role", "combobox");
- selectedFlag.setAttribute("aria-haspopup", "listbox");
- selectedFlag.setAttribute("aria-expanded", "false");
- selectedFlag.setAttribute("aria-owns", "tc-flags-list");
- selectedFlag.setAttribute("aria-label", "Select Country");
- selectedFlag.setAttribute("tabindex", "0");
- const seletedFlagInner = document.createElement("div");
- seletedFlagInner.classList.add("tc-flag");
- // seletedFlagInner.innerHTML = this.getFlagImage("us", "United States");
- const flagArrow = document.createElement("div");
- flagArrow.classList.add("tc-flag-arrow");
- // flagArrow.innerHTML = "▼";
- selectedFlag.appendChild(seletedFlagInner);
- selectedFlag.appendChild(flagArrow);
- selectedFlag.addEventListener("click", (e) => {
- e.preventDefault();
- e.stopPropagation();
- if (selectedFlag.classList.contains("tc-open")) {
- this.closeCountryDropDown();
- }
- else {
- this.openCountryDropDown();
- }
- });
- const countryList = document.createElement("ul");
- countryList.classList.add("tc-country-list");
- countryList.classList.add("tc-hide");
- countryList.setAttribute("id", "tc-country-list");
- countryList.setAttribute("role", "listbox");
- countryList.setAttribute("aria-label", "List of Countries");
- countryList.setAttribute("aria-hidden", "true");
- if (this.options.phone_preferred_countries.length > 0) {
- const preferredCountries = [];
- this.options.phone_preferred_countries.forEach((country) => {
- const countryItem = this.getCountryByCode(country);
- if (countryItem) {
- preferredCountries.push(countryItem);
- }
- });
- this.appendCountryItems(countryList, preferredCountries, "tc-country-list-item", true);
- const divider = document.createElement("li");
- divider.classList.add("tc-divider");
- divider.setAttribute("role", "separator");
- divider.setAttribute("aria-disabled", "true");
- countryList.appendChild(divider);
- this.logger.log("Rendering preferred countries", JSON.stringify(preferredCountries));
+ let value = (_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.value;
+ // If the value is 5 characters or less, remove all non-numeric characters
+ if (value.length <= 5) {
+ value = value.replace(/\D/g, "");
+ }
+ // If one of the supported separators is endered as the 6th character, replace it with the official separator
+ else if (value.length === 6 &&
+ this.supportedSeparators.includes(value[5])) {
+ // Removing all non-numeric characters
+ value = value.replace(/\D/g, "") + this.separator;
}
- const countryListItems = [];
- this.countries_list.forEach((country) => {
- countryListItems.push({
- name: country[0],
- code: country[1],
- dialCode: country[2],
- placeholder: country[3],
- });
- });
- this.appendCountryItems(countryList, countryListItems, "tc-country-list-item");
- countryList.addEventListener("click", (e) => {
- e.preventDefault();
- e.stopPropagation();
- const target = e.target.closest("li");
- if (target.classList.contains("tc-country-list-item")) {
- const countryItem = this.getCountryByCode(target.getAttribute("data-country-code"));
- if (countryItem) {
- this.setPhoneCountry(countryItem);
+ else {
+ // Removing all non-numeric characters
+ value = value.replace(/\D/g, "");
+ // Adding the separator after the 5th character
+ value = value.replace(/(\d{5})(\d)/, `$1${this.separator}$2`);
+ }
+ //set field value with max 10 characters
+ this.postalCodeField.value = value.slice(0, 10);
+ }
+ shouldValidateUSZipCode() {
+ // Validating US zip code only if country is US, country has not yet been selected
+ // or if there is no country field
+ const country = engrid_ENGrid.getField("supporter.country")
+ ? engrid_ENGrid.getFieldValue("supporter.country")
+ : "US";
+ return ["us", "united states", "usa", ""].includes(country.toLowerCase());
+ }
+ getSeparator() {
+ const tidyContact = engrid_ENGrid.getOption("TidyContact");
+ if (tidyContact &&
+ tidyContact.us_zip_divider &&
+ this.supportedSeparators.includes(tidyContact.us_zip_divider)) {
+ return tidyContact.us_zip_divider;
+ }
+ return "-";
+ }
+ getRegexSeparator(separator) {
+ switch (separator) {
+ case "+":
+ return "\\+";
+ case "-":
+ return "-";
+ case " ":
+ return "\\s";
+ default:
+ this.logger.log(`Invalid separator "${separator}" provided to PostalCodeValidator, falling back to "-".`);
+ return "-";
+ }
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/vgs.js
+// This component allows you to customize the VGS theme options
+//
+// It is used in the following way:
+//
+// VGS: {
+// "transaction.ccnumber": {
+// showCardIcon: true,
+// placeholder: "β’β’β’β’ β’β’β’β’ β’β’β’β’ β’β’β’β’",
+// icons: {
+// (icons can't be urls, they have to be base64 encoded images)
+// cardPlaceholder: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%233BBF45'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z'/%3E%3C/svg%3E"
+// visa: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath fill='%233BBF45' d='M384 32H0v448h384V32z'/%3E%3Cpath fill='white' d='M128.5 352.5l-32-192h-32l32 192zm96-192l-32 192h-32l32-192z'/%3E%3C/svg%3E",
+// },
+// },
+// "transaction.ccvv": {
+// showCardIcon: false,
+// placeholder: "CVV",
+// hideValue: false,
+// },
+// },
+//
+// The VGS component can also be set at the page level, if necessary
+//
+
+class VGS {
+ constructor() {
+ this.logger = new logger_EngridLogger("VGS", "black", "pink", "π³");
+ this.vgsField = document.querySelector(".en__field--vgs");
+ this.options = engrid_ENGrid.getOption("VGS");
+ this.paymentTypeField = document.querySelector("#en__field_transaction_paymenttype");
+ this._form = en_form_EnForm.getInstance();
+ this.field_expiration_month = null;
+ this.field_expiration_year = null;
+ this.handleExpUpdate = (e) => {
+ if (!this.field_expiration_month || !this.field_expiration_year)
+ return;
+ const current_date = new Date();
+ const current_month = current_date.getMonth() + 1;
+ const current_year = parseInt(this.field_expiration_year[this.field_expiration_year.length - 1].value) > 2000
+ ? current_date.getFullYear()
+ : current_date.getFullYear() - 2000;
+ // handle if year is changed to current year (disable all months less than current month)
+ // handle if month is changed to less than current month (disable current year)
+ if (e == "month") {
+ let selected_month = parseInt(this.field_expiration_month.value);
+ let disable = selected_month < current_month;
+ this.logger.log(`month disable ${disable}`);
+ this.logger.log(`selected_month ${selected_month}`);
+ for (let i = 0; i < this.field_expiration_year.options.length; i++) {
+ // disable or enable current year
+ if (parseInt(this.field_expiration_year.options[i].value) <= current_year) {
+ if (disable) {
+ this.field_expiration_year.options[i].setAttribute("disabled", "disabled");
+ }
+ else {
+ this.field_expiration_year.options[i].disabled = false;
+ }
+ }
}
}
- });
- countryList.addEventListener("mouseover", (e) => {
- e.preventDefault();
- e.stopPropagation();
- const target = e.target.closest("li.tc-country-list-item");
- if (target) {
- this.highlightCountry(target.getAttribute("data-country-code"));
- }
- });
- this.countries_dropdown.appendChild(selectedFlag);
- this.countries_dropdown.appendChild(countryList);
- phoneInput.parentNode.insertBefore(this.countries_dropdown, phoneInput);
- phoneInput.parentNode.classList.add("tc-has-country-flags");
- this.countries_dropdown.addEventListener("keydown", (e) => {
- var _a, _b;
- const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
- if (isDropdownHidden &&
- ["ArrowUp", "Up", "ArrowDown", "Down", " ", "Enter"].indexOf(e.key) !==
- -1) {
- // prevent form from being submitted if "ENTER" was pressed
- e.preventDefault();
- // prevent event from being handled again by document
- e.stopPropagation();
- this.openCountryDropDown();
- }
- // allow navigation from dropdown to input on TAB
- if (e.key === "Tab")
- this.closeCountryDropDown();
- });
- document.addEventListener("keydown", (e) => {
- var _a, _b;
- const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
- if (!isDropdownHidden) {
- // prevent down key from scrolling the whole page,
- // and enter key from submitting a form etc
- e.preventDefault();
- // up and down to navigate
- if (e.key === "ArrowUp" ||
- e.key === "Up" ||
- e.key === "ArrowDown" ||
- e.key === "Down")
- this.handleUpDownKey(e.key);
- // enter to select
- else if (e.key === "Enter")
- this.handleEnterKey();
- // esc to close
- else if (e.key === "Escape")
- this.closeCountryDropDown();
+ else if (e == "year") {
+ let selected_year = parseInt(this.field_expiration_year.value);
+ let disable = selected_year == current_year;
+ this.logger.log(`year disable ${disable}`);
+ this.logger.log(`selected_year ${selected_year}`);
+ for (let i = 0; i < this.field_expiration_month.options.length; i++) {
+ // disable or enable all months less than current month
+ if (parseInt(this.field_expiration_month.options[i].value) < current_month) {
+ if (disable) {
+ this.field_expiration_month.options[i].setAttribute("disabled", "disabled");
+ }
+ else {
+ this.field_expiration_month.options[i].disabled = false;
+ }
+ }
+ }
}
- });
- document.addEventListener("click", (e) => {
- var _a, _b;
- const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
- if (!isDropdownHidden &&
- !e.target.closest(".tc-country-list")) {
- this.closeCountryDropDown();
+ };
+ if (!this.shouldRun())
+ return;
+ this.setPaymentType();
+ this.setDefaults();
+ this.dumpGlobalVar();
+ const expireFiels = document.getElementsByName("transaction.ccexpire");
+ if (expireFiels) {
+ this.field_expiration_month = expireFiels[0];
+ this.field_expiration_year = expireFiels[1];
+ }
+ // Add event listeners to the expiration fields
+ if (this.field_expiration_month && this.field_expiration_year) {
+ ["change"].forEach((event) => {
+ var _a, _b;
+ (_a = this.field_expiration_month) === null || _a === void 0 ? void 0 : _a.addEventListener(event, () => {
+ this.handleExpUpdate("month");
+ });
+ (_b = this.field_expiration_year) === null || _b === void 0 ? void 0 : _b.addEventListener(event, () => {
+ this.handleExpUpdate("year");
+ });
+ });
+ }
+ this._form.onValidate.subscribe(() => {
+ if (this._form.validate) {
+ const isValid = this.validate();
+ this.logger.log(`Form Validation: ${isValid}`);
+ this._form.validate = isValid;
}
});
}
- handleUpDownKey(key) {
- var _a;
- const highlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
- if (highlightedCountry) {
- let next = key === "ArrowUp" || key === "Up"
- ? highlightedCountry.previousElementSibling
- : highlightedCountry.nextElementSibling;
- if (next) {
- if (next.classList.contains("tc-divider")) {
- next =
- key === "ArrowUp" || key === "Up"
- ? next.previousElementSibling
- : next.nextElementSibling;
- }
- this.highlightCountry(next === null || next === void 0 ? void 0 : next.getAttribute("data-country-code"));
- }
+ shouldRun() {
+ // Only run if the vgs field is present
+ if (!this.vgsField)
+ return false;
+ return true;
+ }
+ setDefaults() {
+ //EN attempts to define a few default styles for VGS fields based on our text field styling
+ //This does not always work, so we will provide our own defaults
+ const bodyStyles = getComputedStyle(document.body);
+ const styles = {
+ fontFamily: bodyStyles.getPropertyValue("--input_font-family") ||
+ "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'",
+ fontSize: bodyStyles.getPropertyValue("--input_font-size") || "16px",
+ color: bodyStyles.getPropertyValue("--input_color") || "#000",
+ padding: bodyStyles.getPropertyValue("--input_padding") || "10px",
+ "&::placeholder": {
+ color: bodyStyles.getPropertyValue("--input_placeholder-color") || "#a9a9a9",
+ opacity: bodyStyles.getPropertyValue("--input_placeholder-opacity") || "1",
+ fontWeight: bodyStyles.getPropertyValue("--input_placeholder-font-weight") ||
+ "normal",
+ },
+ };
+ const options = this.options;
+ const defaultOptions = {
+ "transaction.ccnumber": {
+ showCardIcon: true,
+ placeholder: "β’β’β’β’ β’β’β’β’ β’β’β’β’ β’β’β’β’",
+ icons: {
+ cardPlaceholder: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAYAAADHl1ErAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB8ElEQVR4nO2c4W3CMBBGz1H/NyNkAzoCo2SDrkI3YJSOABt0g9IJXBnOqUkMyifUqkrek04RlvMjT2c7sc6EGKPBfBpcaSBMBGEiCBNBmAjCRBAmgjARhIkgTARhIggTQZhK2q0Yh5l1ZrYzs0PqsrI4+LN3VTeThkvntUm6Fbuxn2E/LITQmtm7mW08Sb/MbO9tpxhjui6WEMLWzJKDdO3N7Nmf9ZjaYoyn8y8X1o6GXxLV1lJyDeE+9oWPQ/ZRG4b9WkVVpqe+8LLLo7ErM6t248qllZnWBc+uV5+zumGsQjm3f/ic9tb4JGeeXcga4U723rptilVx0avgg2Q3m/JNn+y6zeAm+GSWUi/c7L5yfB77RJhACOHs6WnuLfmGpTI3YditEEGYCMJEECaCMJHZqySvHRfIMBGEiSBMBGEiCBNBmAjCRBAmgjARhIkgTGT2t+R/59EdYXZcfwmEiSBMBGEiCBNZzCr5VzvCZJjIIMxrPKFC6abMsHbaFcZuGq8StqKwDqZkN8emKBbrvawHCtxJ7y1nVxQF34lxUXBupOy8EtWy88jBhknUDjbkPhyd+Xn2l9lHZ8rgcNZVTA5nTYRFjv/dPf7HvzuJ8C0pgjARhIkgTARhIggTQZgIwkQQJoIwEYSJIEwEYQpm9g2Ro5zhLcuLBwAAAABJRU5ErkJggg==",
+ },
+ css: styles,
+ // Autocomplete is not customizable
+ autoComplete: "cc-number",
+ validations: ["required", "validCardNumber"],
+ validCardBrands: null
+ },
+ "transaction.ccvv": {
+ showCardIcon: false,
+ placeholder: "CVV",
+ hideValue: false,
+ // Autocomplete is not customizable
+ autoComplete: "cc-csc",
+ validations: ["required", "validCardSecurityCode"],
+ css: styles,
+ },
+ "transaction.ccexpire": {
+ placeholder: "MM/YY",
+ autoComplete: "cc-exp",
+ validations: ["required", "validCardExpirationDate"],
+ css: styles,
+ },
+ };
+ // Override the validCardBrands if set in the theme options, as this should not be deep merged.
+ if (options &&
+ options["transaction.ccnumber"] &&
+ options["transaction.ccnumber"].validCardBrands) {
+ defaultOptions["transaction.ccnumber"].validCardBrands = options["transaction.ccnumber"].validCardBrands;
}
+ // Deep merge the default options with the options set in the theme
+ this.options = engrid_ENGrid.deepMerge(defaultOptions, options);
+ this.logger.log("Options", this.options);
}
- handleEnterKey() {
- var _a;
- const highlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
- if (highlightedCountry) {
- const countryItem = this.getCountryByCode(highlightedCountry === null || highlightedCountry === void 0 ? void 0 : highlightedCountry.getAttribute("data-country-code"));
- this.setPhoneCountry(countryItem);
+ setPaymentType() {
+ // If there's no default payment type, set the default to card
+ if (engrid_ENGrid.getPaymentType() === "") {
+ engrid_ENGrid.setPaymentType("card");
}
}
- handlePhoneInputKeydown(e) {
- const phoneInput = e.target;
- const phoneNumber = phoneInput.value;
- if (phoneNumber.charAt(0) === "+") {
- if (phoneNumber.length > 2) {
- const countryItem = this.getCountryByCode(phoneNumber.substring(1, 3));
- if (countryItem) {
- this.setPhoneCountry(countryItem);
+ dumpGlobalVar() {
+ // Dump the global variable for the VGS options
+ window.enVGSFields = this.options;
+ // EN is not reading the global variable because their JS file loads before ENgrid, so we're going to HACK TOWN
+ // Clean up the VGS iFrames
+ window.setTimeout(() => {
+ const vgsIElements = document.querySelectorAll(".en__field__input--vgs");
+ if (vgsIElements.length > 0) {
+ // Create a mutation observer that cleans the VGS Elements before anything is rendered
+ const observer = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ var _a;
+ if (mutation.type === "childList" &&
+ mutation.addedNodes.length > 0) {
+ mutation.addedNodes.forEach((node) => {
+ if (node.nodeName === "IFRAME" &&
+ mutation.previousSibling &&
+ mutation.previousSibling.nodeName === "IFRAME") {
+ // Delete the previous sibling
+ mutation.previousSibling.remove();
+ }
+ });
+ }
+ // Check if the VGS Element is valid, and remove any validation classes and errors
+ if (mutation.type === "attributes" &&
+ mutation.attributeName === "class") {
+ const target = mutation.target;
+ if (target.classList.contains("vgs-collect-container__valid")) {
+ const fieldWrapper = target.closest(".en__field--vgs");
+ fieldWrapper === null || fieldWrapper === void 0 ? void 0 : fieldWrapper.classList.remove("en__field--validationFailed");
+ (_a = fieldWrapper === null || fieldWrapper === void 0 ? void 0 : fieldWrapper.querySelector(".en__field__error")) === null || _a === void 0 ? void 0 : _a.remove();
+ }
+ }
+ });
+ });
+ // Observe the VGS Elements
+ vgsIElements.forEach((vgsIElement) => {
+ observer.observe(vgsIElement, {
+ childList: true,
+ attributeFilter: ["class"],
+ });
+ });
+ if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "vgs")) {
+ window.EngagingNetworks.require._defined.enjs.vgs.init();
}
else {
- this.setDefaultPhoneCountry();
+ this.logger.log("VGS is not defined");
}
}
- }
+ }, 1000);
}
- openCountryDropDown() {
- if (!this.countries_dropdown)
- return;
- const countryList = this.countries_dropdown.querySelector(".tc-country-list");
- const selectedFlag = this.countries_dropdown.querySelector(".tc-selected-flag");
- if (countryList && selectedFlag) {
- countryList.classList.remove("tc-hide");
- selectedFlag.setAttribute("aria-expanded", "true");
- selectedFlag.classList.add("tc-open");
+ validate() {
+ if (this.paymentTypeField.value.toLowerCase() === "card" ||
+ this.paymentTypeField.value.toLowerCase() === "visa" ||
+ this.paymentTypeField.value.toLowerCase() === "vi") {
+ const cardContainer = document.querySelector(".en__field--vgs.en__field--ccnumber");
+ const cardEmpty = cardContainer === null || cardContainer === void 0 ? void 0 : cardContainer.querySelector(".vgs-collect-container__empty");
+ const cvvContainer = document.querySelector(".en__field--vgs.en__field--ccvv");
+ const cvvEmpty = cvvContainer === null || cvvContainer === void 0 ? void 0 : cvvContainer.querySelector(".vgs-collect-container__empty");
+ if (cardContainer && cardEmpty) {
+ window.setTimeout(() => {
+ engrid_ENGrid.setError(cardContainer, "Please enter a valid card number");
+ // Scroll to the error
+ cardContainer.scrollIntoView({ behavior: "smooth" });
+ }, 100);
+ return false;
+ }
+ if (cvvContainer && cvvEmpty) {
+ window.setTimeout(() => {
+ engrid_ENGrid.setError(cvvContainer, "Please enter a valid CVV");
+ // Scroll to the error
+ cvvContainer.scrollIntoView({ behavior: "smooth" });
+ }, 100);
+ return false;
+ }
}
+ return true;
}
- closeCountryDropDown() {
- var _a;
- if (!this.options)
- return;
- if (!this.countries_dropdown)
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/country-redirect.js
+// This component allows you to redirect the user to a different page based on their country.
+// It works by checking the country field on the page and comparing it to the list of countries in the CountryRedirect option.
+// If the country matches one of the countries in the list, the user is redirected to the specified URL only if the URL is not the same as the current page.
+// The CountryRedirect option is an object with the country as the key and the URL as the value.
+// Example:
+//
+// CountryRedirect: {
+// US: "https://example.com/us",
+// CA: "https://example.com/ca",
+// GB: "https://example.com/gb",
+// },
+// The country codes must match the country codes in the country field
+// The CountryRedirect component can also be set at the page level. Useful for Regional Pages, with a Code Block like this:
+//
+//
+//
+// This will override the default CountryRedirect options for that page.
+//
+
+class CountryRedirect {
+ constructor() {
+ this.logger = new logger_EngridLogger("CountryRedirect", "white", "brown", "π«");
+ this._country = Country.getInstance();
+ if (!this.shouldRun())
return;
- const countryList = this.countries_dropdown.querySelector(".tc-country-list");
- const selectedFlag = this.countries_dropdown.querySelector(".tc-selected-flag");
- if (countryList && selectedFlag) {
- countryList.classList.add("tc-hide");
- selectedFlag.setAttribute("aria-expanded", "false");
- selectedFlag.classList.remove("tc-open");
- }
- const phoneInput = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
- phoneInput.focus();
+ this._country.onCountryChange.subscribe((country) => {
+ this.checkRedirect(country);
+ });
+ this.checkRedirect(this._country.country); // This will check the redirect when the page loads
}
- getFlagImage(code, name) {
- return `
-
-
-
- `;
+ shouldRun() {
+ // Only run if the CountryRedirect option is not false and the country field is present
+ if (!engrid_ENGrid.getOption("CountryRedirect") || !this._country.countryField) {
+ return false;
+ }
+ return true;
}
- appendCountryItems(countryContainer, countries, className, preferred = false) {
- let html = "";
- // for each country
- for (let i = 0; i < countries.length; i++) {
- const c = countries[i];
- const idSuffix = !!preferred ? "-preferred" : true && "" !== void 0 ? "" : "";
- // open the list item
- html += ``;
- // add the flag
- html += `${this.getFlagImage(c.code, c.name)}
`;
- // and the country name and dial code
- html += `${c.name} `;
- html += `+${c.dialCode} `;
- // close the list item
- html += " ";
+ checkRedirect(country) {
+ const countryRedirect = engrid_ENGrid.getOption("CountryRedirect");
+ // Check if the country is in the list and if the current URL is not the same as the redirect URL
+ // We are using includes because the URL might have query parameters
+ if (countryRedirect &&
+ country in countryRedirect &&
+ window.location.href.includes(countryRedirect[country]) === false) {
+ this.logger.log(`${country}: Redirecting to ${countryRedirect[country]}`);
+ let redirectUrl = new URL(countryRedirect[country]);
+ // If the redirect URL doesn't contain "?chain", add it
+ if (!redirectUrl.search.includes("chain")) {
+ redirectUrl.search += (redirectUrl.search ? "&" : "?") + "chain";
+ }
+ window.location.href = redirectUrl.href;
}
- countryContainer.insertAdjacentHTML("beforeend", html);
}
- setDefaultPhoneCountry() {
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/welcome-back.js
+/**
+ * This component adds a welcome back message and a personal details summary to the page.
+ * It depends on the "fast-personal-details" functionality from the FastFormFill component.
+ * The component will only run, when the "WelcomeBack" option is set,
+ * if the "fast-personal-details" class is present on the page and the FastFormFill conditions
+ * are met (all mandatory inputs in that block are filled).
+ *
+ * All the text content and positioning is configurable through the "WelcomeBack" option.
+ */
+
+
+class WelcomeBack {
+ constructor() {
var _a;
- if (!this.options)
+ this._form = en_form_EnForm.getInstance();
+ this.supporterDetails = {};
+ this.options = (_a = engrid_ENGrid.getOption("WelcomeBack")) !== null && _a !== void 0 ? _a : false;
+ this.rememberMeEvents = RememberMeEvents.getInstance();
+ this.hasRun = false;
+ if (!this.shouldRun())
return;
- // First, try to get the country from IP
- if (this.options.phone_country_from_ip) {
- this.getCountryFromIP()
- .then((country) => {
- this.logger.log("Country from IP:", country);
- this.setPhoneCountry(this.getCountryByCode((country !== null && country !== void 0 ? country : "us").toLowerCase()));
- })
- .catch((error) => {
- this.setPhoneCountry(this.getCountryByCode("us"));
+ if (engrid_ENGrid.getOption("RememberMe")) {
+ this.rememberMeEvents.onLoad.subscribe(() => {
+ this.run();
+ });
+ this.rememberMeEvents.onClear.subscribe(() => {
+ this.resetWelcomeBack();
});
- return;
}
- // Then, get the default country Text
- const countryField = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.country);
- if (countryField) {
- const countryText = countryField.options[countryField.selectedIndex].text;
- // Then, get the country code from the Text
- const countryData = this.getCountryByCode(countryText);
- if (countryData) {
- this.setPhoneCountry(countryData);
- return;
- }
- else if (this.options.phone_preferred_countries.length > 0) {
- // If no country code is found, use the first priority country
- this.setPhoneCountry(this.getCountryByCode(this.options.phone_preferred_countries[0]));
- return;
- }
+ else {
+ this.run();
}
- // If nothing works, GO USA!
- this.setPhoneCountry(this.getCountryByCode("us"));
}
- setPhoneCountry(country) {
- var _a, _b, _c, _d, _e, _f;
- if (!this.options || !country)
+ run() {
+ if (this.hasRun)
return;
- const countryInput = engrid_ENGrid.getField("tc.phone.country");
- if (countryInput.value === country.code)
+ this.hasRun = true;
+ this.supporterDetails = {
+ firstName: engrid_ENGrid.getFieldValue("supporter.firstName"),
+ lastName: engrid_ENGrid.getFieldValue("supporter.lastName"),
+ emailAddress: engrid_ENGrid.getFieldValue("supporter.emailAddress"),
+ address1: engrid_ENGrid.getFieldValue("supporter.address1"),
+ address2: engrid_ENGrid.getFieldValue("supporter.address2"),
+ city: engrid_ENGrid.getFieldValue("supporter.city"),
+ region: engrid_ENGrid.getFieldValue("supporter.region"),
+ postcode: engrid_ENGrid.getFieldValue("supporter.postcode"),
+ country: engrid_ENGrid.getFieldValue("supporter.country"),
+ mobilePhone: engrid_ENGrid.getFieldValue("supporter.phoneNumber2"),
+ };
+ this.addWelcomeBack();
+ this.addPersonalDetailsSummary();
+ this.addEventListeners();
+ }
+ shouldRun() {
+ return (!!document.querySelector(".fast-personal-details") &&
+ engrid_ENGrid.getBodyData("embedded") !== "thank-you-page-donation" &&
+ this.options !== false);
+ }
+ addWelcomeBack() {
+ var _a;
+ if (typeof this.options !== "object" ||
+ !this.options.welcomeBackMessage.display)
return;
- const phoneInput = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
- if (this.countryDropDownEnabled()) {
- const selectedFlag = (_b = this.countries_dropdown) === null || _b === void 0 ? void 0 : _b.querySelector(".tc-selected-flag");
- const flagElement = (_c = this.countries_dropdown) === null || _c === void 0 ? void 0 : _c.querySelector(".tc-flag");
- if (selectedFlag && flagElement) {
- flagElement.innerHTML = this.getFlagImage(country.code, country.name);
- selectedFlag.setAttribute("data-country", country.code);
- }
- const currentSelectedCountry = (_d = this.countries_dropdown) === null || _d === void 0 ? void 0 : _d.querySelector(".tc-country-list-item[aria-selected='true']");
- if (currentSelectedCountry) {
- currentSelectedCountry.classList.remove("tc-selected");
- currentSelectedCountry.setAttribute("aria-selected", "false");
- }
- const currentHighlightedCountry = (_e = this.countries_dropdown) === null || _e === void 0 ? void 0 : _e.querySelector(".tc-highlight");
- if (currentHighlightedCountry) {
- currentHighlightedCountry.classList.remove("tc-highlight");
+ const options = this.options.welcomeBackMessage;
+ const welcomeBack = document.createElement("div");
+ welcomeBack.classList.add("engrid-welcome-back", "showif-fast-personal-details");
+ const title = options.title.replace("{firstName}", this.supporterDetails["firstName"]);
+ welcomeBack.innerHTML = `
+ ${title}
+ ${options.editText}
+
`;
+ (_a = document
+ .querySelector(options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(options.placement, welcomeBack);
+ }
+ resetWelcomeBack() {
+ const inputs = document.querySelectorAll(".fast-personal-details .en__field__input");
+ inputs.forEach((input) => {
+ if (input.type === "checkbox" || input.type === "radio") {
+ input.checked = false;
}
- const countryListItem = (_f = this.countries_dropdown) === null || _f === void 0 ? void 0 : _f.querySelector(`.tc-country-list-item[data-country-code='${country.code}']`);
- if (countryListItem) {
- countryListItem.classList.add("tc-selected");
- countryListItem.setAttribute("aria-selected", "true");
- countryListItem.classList.add("tc-highlight");
+ else {
+ input.value = "";
}
- if (selectedFlag === null || selectedFlag === void 0 ? void 0 : selectedFlag.classList.contains("tc-open"))
- this.closeCountryDropDown();
- }
- phoneInput.setAttribute("placeholder", country.placeholder);
- countryInput.value = country.code;
- this.logger.log(`Setting phone country to ${country.code} - ${country.name}`);
+ });
+ this.supporterDetails = {};
+ engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ remove("engrid-autofill");
}
- highlightCountry(countryCode) {
- var _a, _b;
- if (!countryCode)
+ addPersonalDetailsSummary() {
+ var _a;
+ if (typeof this.options !== "object" ||
+ !this.options.personalDetailsSummary.display)
return;
- const currentHighlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
- if (currentHighlightedCountry) {
- currentHighlightedCountry.classList.remove("tc-highlight");
- }
- const countryList = (_b = this.countries_dropdown) === null || _b === void 0 ? void 0 : _b.querySelector(".tc-country-list");
- if (countryList) {
- const country = countryList.querySelector(`.tc-country[data-country-code='${countryCode}']`);
- if (country) {
- country.classList.add("tc-highlight");
- country.scrollIntoView({
- behavior: "smooth",
- block: "nearest",
- inline: "nearest",
- });
- }
+ let options = this.options.personalDetailsSummary;
+ const personalDetailsSummary = document.createElement("div");
+ personalDetailsSummary.classList.add("engrid-personal-details-summary", "showif-fast-personal-details");
+ personalDetailsSummary.innerHTML = `${options.title} `;
+ personalDetailsSummary.insertAdjacentHTML("beforeend", `
+
+ ${this.supporterDetails["firstName"]} ${this.supporterDetails["lastName"]}
+
+ ${this.supporterDetails["emailAddress"]}
+ ${this.supporterDetails["mobilePhone"] && options.showPhoneNumber
+ ? ` ${this.supporterDetails["mobilePhone"]}`
+ : ""}
+
+ `);
+ if (this.supporterDetails["address1"] &&
+ this.supporterDetails["city"] &&
+ this.supporterDetails["region"] &&
+ this.supporterDetails["postcode"]) {
+ personalDetailsSummary.insertAdjacentHTML("beforeend", `
+
+ ${this.supporterDetails["address1"]} ${this.supporterDetails["address2"]}
+
+ ${this.supporterDetails["city"]}, ${this.supporterDetails["region"]}
+ ${this.supporterDetails["postcode"]}
+
+ `);
}
+ personalDetailsSummary.insertAdjacentHTML("beforeend", `
+ ${options.editText}
+ `);
+ (_a = document
+ .querySelector(options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(options.placement, personalDetailsSummary);
}
- setPhoneDataFromAPI(data, id) {
- var _a;
- return tidycontact_awaiter(this, void 0, void 0, function* () {
- if (!this.options)
- return;
- const phoneField = engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
- const recordField = engrid_ENGrid.getField(this.options.phone_record_field);
- const dateField = engrid_ENGrid.getField(this.options.phone_date_field);
- const statusField = engrid_ENGrid.getField(this.options.phone_status_field);
- let record = {};
- record["formData"] = { [phoneField.name]: phoneField.value };
- record["formatted"] = data.formatted;
- record["number_type"] = data.number_type;
- if (data.valid === true) {
- if (phoneField.value !== data.formatted.e164) {
- record["phone"] = {
- from: phoneField.value,
- to: data.formatted.e164,
- };
- phoneField.value = data.formatted.e164;
- }
- yield this.checkSum(JSON.stringify(record)).then((checksum) => {
- this.logger.log("Phone Checksum", checksum);
- record["requestId"] = id; // We don't want to add the requestId to the checksum
- record["checksum"] = checksum;
- });
- if (recordField) {
- record = Object.assign({ date: this.todaysDate(), status: "SUCCESS" }, record);
- recordField.value = JSON.stringify(record);
- }
- if (dateField) {
- dateField.value = this.todaysDate();
- }
- if (statusField) {
- statusField.value = "SUCCESS";
- }
- }
- else {
- yield this.checkSum(JSON.stringify(record)).then((checksum) => {
- this.logger.log("Phone Checksum", checksum);
- record["requestId"] = id; // We don't want to add the requestId to the checksum
- record["checksum"] = checksum;
- });
- if (recordField) {
- record = Object.assign({ date: this.todaysDate(), status: "ERROR" }, record);
- recordField.value = JSON.stringify(record);
- }
- if (dateField) {
- dateField.value = this.todaysDate();
- }
- if (statusField) {
- statusField.value =
- "error" in data ? `ERROR: ` + data.error : "INVALIDPHONE";
- }
- }
+ addEventListeners() {
+ document
+ .querySelectorAll(".engrid-reset-welcome-back")
+ .forEach((element) => {
+ element.addEventListener("click", () => {
+ this.resetWelcomeBack();
+ });
+ });
+ this._form.onValidate.subscribe(this.enOnValidate.bind(this));
+ this._form.onValidate.subscribe(() => {
+ window.setTimeout(this.doubleCheckValidation.bind(this), 150);
});
}
- callAPI() {
- var _a, _b, _c, _d, _e, _f;
- if (!this.options)
+ enOnValidate() {
+ if (!this._form.validate) {
+ // Disable the fast personal details if the form is invalidated by other components running before
+ engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
return;
- if (!this.isDirty || this.wasCalled)
+ }
+ const regionField = engrid_ENGrid.getField("supporter.region");
+ const regionFieldValue = regionField ? regionField.value : "";
+ const regionFieldType = regionField === null || regionField === void 0 ? void 0 : regionField.tagName.toLowerCase();
+ const regionFieldLabel = document.querySelector(".en__field--region label");
+ if (regionFieldType === "select" &&
+ regionFieldLabel &&
+ regionFieldValue === "") {
+ engrid_ENGrid.setError(".en__field--region", `${regionFieldLabel.innerText} is required`);
+ engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ this._form.validate = false;
+ }
+ else {
+ // Remove the error message if the region field is filled
+ engrid_ENGrid.removeError(".en__field--region");
+ }
+ }
+ doubleCheckValidation() {
+ // Disable the fast personal details if the form is invalidated by other components running AFTER
+ // the fast personal details component
+ const validationError = document.querySelector(".fast-personal-details .en__field--validationFailed");
+ if (validationError) {
+ engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ validationError.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ });
+ }
+ return;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/ecard-to-target-options.js
+const EcardToTargetOptionsDefaults = {
+ targetName: "",
+ targetEmail: "",
+ hideSendDate: true,
+ hideTarget: true,
+ hideMessage: true,
+ addSupporterNameToMessage: false,
+ targets: [],
+};
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/ecard-to-target.js
+/**
+ * This component adjusts an ecard form to target a specific recipient,
+ * defined in a code block
+ */
+
+
+
+
+class EcardToTarget {
+ constructor() {
+ this.options = EcardToTargetOptionsDefaults;
+ this.logger = new logger_EngridLogger("EcardToTarget", "DarkBlue", "Azure", "π§");
+ this._form = en_form_EnForm.getInstance();
+ this.supporterNameAddedToMessage = false;
+ if (!this.shouldRun())
return;
- if (!this._form.submit) {
- this.logger.log("Form Submission Interrupted by Other Component");
+ this.options = Object.assign(Object.assign({}, this.options), window.EngridEcardToTarget);
+ this.logger.log("EcardToTarget running. Options:", this.options);
+ this.setTarget();
+ this.hideElements();
+ this.addSupporterNameToMessage();
+ }
+ shouldRun() {
+ return (window.hasOwnProperty("EngridEcardToTarget") &&
+ typeof window.EngridEcardToTarget === "object" &&
+ ((window.EngridEcardToTarget.hasOwnProperty("targetName") &&
+ window.EngridEcardToTarget.hasOwnProperty("targetEmail")) ||
+ (window.EngridEcardToTarget.hasOwnProperty("targets") &&
+ window.EngridEcardToTarget.targets.length > 0)));
+ }
+ setTarget() {
+ const targetNameField = document.querySelector(".en__ecardrecipients__name input");
+ const targetEmailField = document.querySelector(".en__ecardrecipients__email input");
+ const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
+ if (!targetNameField || !targetEmailField || !addRecipientButton) {
+ this.logger.error("Could not add recipient. Required elements not found.");
return;
}
- const recordField = engrid_ENGrid.getField(this.options.record_field);
- const dateField = engrid_ENGrid.getField(this.options.date_field);
- const statusField = engrid_ENGrid.getField(this.options.status_field);
- const latitudeField = engrid_ENGrid.getField("supporter.geo.latitude");
- const longitudeField = engrid_ENGrid.getField("supporter.geo.longitude");
- if (!this.canUseAPI() && !this.canUsePhoneAPI()) {
- this.logger.log("Not Enough Data to Call API");
- if (dateField) {
- dateField.value = this.todaysDate();
- }
- if (statusField) {
- statusField.value = "PARTIALADDRESS";
- }
- return true;
+ let targets = this.options.targets;
+ // BC support for targetName and targetEmail
+ if (this.options.targetName && this.options.targetEmail) {
+ targets.push({
+ targetName: this.options.targetName,
+ targetEmail: this.options.targetEmail,
+ });
}
- // Call the API
- const address1 = engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
- const address2 = engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2);
- const city = engrid_ENGrid.getFieldValue((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.city);
- const region = engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.region);
- const postalCode = engrid_ENGrid.getFieldValue((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.postalCode);
- const country = this.getCountry();
- if (!this.countryAllowed(country)) {
- this.logger.log("Country not allowed: " + country);
- if (recordField) {
- let record = {};
- record = Object.assign({ date: this.todaysDate(), status: "DISALLOWED" }, record);
- recordField.value = JSON.stringify(record);
- }
- if (dateField) {
- dateField.value = this.todaysDate();
- }
- if (statusField) {
- statusField.value = "DISALLOWED";
+ // Remove duplicates from targets array
+ targets = targets.filter((target, index, self) => index ===
+ self.findIndex((t) => t.targetName === target.targetName &&
+ t.targetEmail === target.targetEmail));
+ targets.forEach((target) => {
+ const targetName = target.targetName;
+ const targetEmail = target.targetEmail;
+ if (!targetName || !targetEmail) {
+ this.logger.error("Could not add recipient. Target name or email is empty.");
+ return;
}
- return true;
+ targetNameField.value = targetName;
+ targetEmailField.value = targetEmail;
+ addRecipientButton === null || addRecipientButton === void 0 ? void 0 : addRecipientButton.click();
+ this.logger.log("Added recipient", targetName, targetEmail);
+ });
+ }
+ hideElements() {
+ const messageBlock = document.querySelector(".en__ecardmessage");
+ const sendDateBlock = document.querySelector(".en__ecardrecipients__futureDelivery");
+ const targetBlock = document.querySelector(".en__ecardrecipients");
+ if (this.options.hideMessage && messageBlock) {
+ messageBlock.classList.add("hide");
}
- let formData = {
- url: window.location.href,
- cid: this.options.cid,
- };
- if (this.canUseAPI()) {
- formData = Object.assign(formData, {
- address1,
- address2,
- city,
- region,
- postalCode,
- country,
- });
+ if (this.options.hideSendDate && sendDateBlock) {
+ sendDateBlock.classList.add("hide");
}
- if (this.canUsePhoneAPI()) {
- formData.phone = engrid_ENGrid.getFieldValue((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.phone);
- formData.phoneCountry = engrid_ENGrid.getFieldValue("tc.phone.country");
+ if (this.options.hideTarget && targetBlock) {
+ targetBlock.classList.add("hide");
}
- this.wasCalled = true;
- this.logger.log("FormData", JSON.parse(JSON.stringify(formData)));
- const ret = this.fetchTimeOut(this.endpoint, {
- headers: { "Content-Type": "application/json; charset=utf-8" },
- method: "POST",
- body: JSON.stringify(formData),
- })
- .then((response) => {
- this.httpStatus = response.status;
- return response.json();
- })
- .then((data) => tidycontact_awaiter(this, void 0, void 0, function* () {
- this.logger.log("callAPI response", JSON.parse(JSON.stringify(data)));
- if (data.valid === true) {
- let record = {};
- if ("changed" in data) {
- record = this.setFields(data.changed);
- }
- record["formData"] = formData;
- yield this.checkSum(JSON.stringify(record)).then((checksum) => {
- this.logger.log("Checksum", checksum);
- record["requestId"] = data.requestId; // We don't want to add the requestId to the checksum
- record["checksum"] = checksum;
- });
- if ("latitude" in data) {
- latitudeField.value = data.latitude;
- record["latitude"] = data.latitude;
- }
- if ("longitude" in data) {
- longitudeField.value = data.longitude;
- record["longitude"] = data.longitude;
- }
- if (recordField) {
- record = Object.assign({ date: this.todaysDate(), status: "SUCCESS" }, record);
- recordField.value = JSON.stringify(record);
- }
- if (dateField) {
- dateField.value = this.todaysDate();
- }
- if (statusField) {
- statusField.value = "SUCCESS";
- }
- }
- else {
- let record = {};
- record["formData"] = formData;
- yield this.checkSum(JSON.stringify(record)).then((checksum) => {
- this.logger.log("Checksum", checksum);
- record["requestId"] = data.requestId; // We don't want to add the requestId to the checksum
- record["checksum"] = checksum;
- });
- if (recordField) {
- record = Object.assign({ date: this.todaysDate(), status: "ERROR" }, record);
- recordField.value = JSON.stringify(record);
- }
- if (dateField) {
- dateField.value = this.todaysDate();
- }
- if (statusField) {
- statusField.value =
- "error" in data ? `ERROR: ` + data.error : "INVALIDADDRESS";
- }
- }
- if (this.phoneEnabled() && "phone" in data) {
- yield this.setPhoneDataFromAPI(data.phone, data.requestId);
- }
- }))
- .catch((error) => {
- if (error.toString().includes("AbortError")) {
- // fetch aborted due to timeout
- this.logger.log("Fetch aborted");
- this.httpStatus = 408;
+ }
+ addSupporterNameToMessage() {
+ if (!this.options.addSupporterNameToMessage)
+ return;
+ this._form.onSubmit.subscribe(() => {
+ if (!this._form.submit)
+ return;
+ if (!this.supporterNameAddedToMessage) {
+ this.supporterNameAddedToMessage = true;
+ const supporterName = `${engrid_ENGrid.getFieldValue("supporter.firstName")} ${engrid_ENGrid.getFieldValue("supporter.lastName")}`;
+ const messageField = document.querySelector("[name='transaction.comments']");
+ if (!messageField)
+ return;
+ messageField.value = `${messageField.value}\n${supporterName}`;
+ this.logger.log("Added supporter name to personalized message", supporterName);
}
- // network error or json parsing error
- this.writeError(error);
});
- this._form.submitPromise = ret;
- return ret;
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/live-currency.js
-// This script enables live currency symbol and code to the page.
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/embedded-ecard-options.js
+const EmbeddedEcardOptionsDefaults = {
+ pageUrl: "",
+ headerText: "Send an Ecard notification of your gift",
+ checkboxText: "Yes, I would like to send an ecard to announce my gift.",
+ anchor: ".en__field--donationAmt",
+ placement: "afterend",
+ requireInMemCheckbox: false,
+};
-class LiveCurrency {
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/embedded-ecard.js
+/**
+ * This class handles adding a checkbox to a form that, when checked, will display an embedded ecard form.
+ * The embedded ecard form is hosted on a separate page and is displayed in an iframe.
+ * The form data is saved in session storage and is submitted when the thank you page is loaded.
+ * Options can set on the page via window.EngridEmbeddedEcard.
+ */
+
+
+class EmbeddedEcard {
constructor() {
- this.logger = new logger_EngridLogger("LiveCurrency", "#1901b1", "#feb47a", "π²");
- this.elementsFound = false;
- this.isUpdating = false;
- this._amount = DonationAmount.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this._fees = ProcessingFees.getInstance();
- this.searchElements();
- if (!this.shouldRun())
- return;
- engrid_ENGrid.setBodyData("live-currency", "active");
- this.updateCurrency();
- this.addEventListeners();
- // Make labels visible on page load
- document
- .querySelectorAll(".en__field--donationAmt .en__field__element--radio .en__field__item")
- .forEach((node) => {
- node.setAttribute("data-engrid-currency-symbol-updated", "true");
+ this.logger = new logger_EngridLogger("Embedded Ecard", "#D95D39", "#0E1428", "π§");
+ this.options = EmbeddedEcardOptionsDefaults;
+ this._form = en_form_EnForm.getInstance();
+ this.isSubmitting = false;
+ this.ecardFormActive = false;
+ this.iframe = null;
+ // For the page hosting the embedded ecard
+ if (this.onHostPage()) {
+ // Clean up session variables if the page is reloaded, and it isn't a submission failure
+ const submissionFailed = !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
+ window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
+ if (!submissionFailed) {
+ sessionStorage.removeItem("engrid-embedded-ecard");
+ sessionStorage.removeItem("engrid-send-embedded-ecard");
+ }
+ this.options = Object.assign(Object.assign({}, EmbeddedEcardOptionsDefaults), window.EngridEmbeddedEcard);
+ const pageUrl = new URL(this.options.pageUrl);
+ pageUrl.searchParams.append("data-engrid-embedded-ecard", "true");
+ pageUrl.searchParams.append("chain", "");
+ this.options.pageUrl = pageUrl.href;
+ this.logger.log("Running Embedded Ecard component", this.options);
+ this.embedEcard();
+ this.addEventListeners();
+ }
+ // For the thank you page - after the host page form has been submitted
+ // Only runs if eCard was selected on the main page
+ if (this.onPostActionPage()) {
+ engrid_ENGrid.setBodyData("embedded-ecard-sent", "true");
+ this.submitEcard();
+ }
+ // For the page that is embedded
+ if (this.onEmbeddedEcardPage()) {
+ this.setupEmbeddedPage();
+ }
+ }
+ onHostPage() {
+ return (window.hasOwnProperty("EngridEmbeddedEcard") &&
+ typeof window.EngridEmbeddedEcard === "object" &&
+ window.EngridEmbeddedEcard.hasOwnProperty("pageUrl") &&
+ window.EngridEmbeddedEcard.pageUrl !== "");
+ }
+ onEmbeddedEcardPage() {
+ return engrid_ENGrid.getPageType() === "ECARD" && engrid_ENGrid.hasBodyData("embedded") && engrid_ENGrid.getPageNumber() === 1;
+ }
+ onPostActionPage() {
+ return (sessionStorage.getItem("engrid-embedded-ecard") !== null &&
+ sessionStorage.getItem("engrid-send-embedded-ecard") !== null &&
+ !this.onHostPage() &&
+ !this.onEmbeddedEcardPage());
+ }
+ embedEcard() {
+ var _a;
+ const container = document.createElement("div");
+ container.classList.add("engrid--embedded-ecard");
+ const heading = document.createElement("h3");
+ heading.textContent = this.options.headerText;
+ heading.classList.add("engrid--embedded-ecard-heading");
+ container.appendChild(heading);
+ const checkbox = document.createElement("div");
+ checkbox.classList.add("pseudo-en-field", "en__field", "en__field--checkbox", "en__field--000000", "en__field--embedded-ecard");
+ checkbox.innerHTML = `
+
+
+
+ ${this.options.checkboxText}
+
+
`;
+ container.appendChild(checkbox);
+ this.iframe = this.createIframe(this.options.pageUrl);
+ container.appendChild(this.iframe);
+ (_a = document
+ .querySelector(this.options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(this.options.placement, container);
+ }
+ createIframe(url) {
+ const iframe = document.createElement("iframe");
+ iframe.src = url;
+ iframe.setAttribute("src", url);
+ iframe.setAttribute("width", "100%");
+ iframe.setAttribute("scrolling", "no");
+ iframe.setAttribute("frameborder", "0");
+ iframe.setAttribute("title", "Ecard iframe");
+ iframe.classList.add("engrid-iframe", "engrid-iframe--embedded-ecard");
+ iframe.style.display = "none";
+ return iframe;
+ }
+ addEventListeners() {
+ var _a;
+ const sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
+ if (this.options.requireInMemCheckbox) {
+ const inMemoriamCheckbox = document.getElementById("en__field_transaction_inmem");
+ inMemoriamCheckbox === null || inMemoriamCheckbox === void 0 ? void 0 : inMemoriamCheckbox.addEventListener("change", (e) => {
+ const checkbox = e.target;
+ const _sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
+ this.toggleEcardForm(checkbox.checked && _sendEcardCheckbox.checked);
+ });
+ this.toggleEcardForm(((_a = inMemoriamCheckbox === null || inMemoriamCheckbox === void 0 ? void 0 : inMemoriamCheckbox.checked) !== null && _a !== void 0 ? _a : true) && sendEcardCheckbox.checked);
+ }
+ else {
+ this.toggleEcardForm(sendEcardCheckbox.checked);
+ }
+ sendEcardCheckbox === null || sendEcardCheckbox === void 0 ? void 0 : sendEcardCheckbox.addEventListener("change", (e) => {
+ const checkbox = e.target;
+ this.toggleEcardForm(checkbox.checked);
});
+ this._form.onValidate.subscribe(this.validateRecipients.bind(this));
}
- searchElements() {
- const enElements = document.querySelectorAll(`
- .en__component--copyblock,
- .en__component--codeblock,
- .en__field label,
- .en__submit
- `);
- if (enElements.length > 0) {
- this.elementsFound = true;
- const currency = engrid_ENGrid.getCurrencySymbol();
- const currencyCode = engrid_ENGrid.getCurrencyCode();
- const currencyElement = `${currency} `;
- const currencyCodeElement = `${currencyCode} `;
- enElements.forEach((item) => {
- // If item starts with
-//
-// This will override the default CustomCurrency options for that page.
-//
-
-class CustomCurrency {
- constructor() {
- this.logger = new logger_EngridLogger("CustomCurrency", "#1901b1", "#00cc95", "π€");
- this.currencyElement = document.querySelector("[name='transaction.paycurrency']");
- this._country = Country.getInstance();
- if (!this.shouldRun())
- return;
- this.addEventListeners();
- this.loadCurrencies();
+ submitEcard() {
+ var _a;
+ const embeddedEcardData = JSON.parse(sessionStorage.getItem("engrid-embedded-ecard") || "{}");
+ this.logger.log("Submitting ecard", embeddedEcardData);
+ const iframe = this.createIframe(embeddedEcardData.pageUrl);
+ (_a = document.querySelector(".body-main")) === null || _a === void 0 ? void 0 : _a.appendChild(iframe);
+ window.addEventListener("message", (e) => {
+ if (e.origin !== location.origin || !e.data.action)
+ return;
+ if (e.data.action === "ecard_form_ready") {
+ this.sendPostMessage(iframe, "submit_form");
+ }
+ });
}
- shouldRun() {
- // Only run if the currency field is present, and the CustomCurrency option is not false
- if (!this.currencyElement || !engrid_ENGrid.getOption("CustomCurrency")) {
- return false;
+ sendPostMessage(target, action, data = {}) {
+ var _a;
+ if (!target)
+ return;
+ const message = Object.assign({ action }, data);
+ if (target === "parent") {
+ window.parent.postMessage(message, location.origin);
}
- return true;
- }
- addEventListeners() {
- if (this._country.countryField) {
- this._country.onCountryChange.subscribe((country) => {
- this.loadCurrencies(country);
- });
+ else {
+ (_a = target.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, location.origin);
}
}
- // Changes the options in the currency field to match the selected country options
- loadCurrencies(country = "default") {
- const options = engrid_ENGrid.getOption("CustomCurrency");
- if (!options)
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/us-only-form.js
+/*
+ * This class disables the country field and fixes the country to "United States"
+ */
+
+class UsOnlyForm {
+ constructor() {
+ if (!this.shouldRun())
return;
- const label = options.label || `Give with [$$$]`;
- let currencies = options.default;
- if (options.countries && options.countries[country]) {
- currencies = options.countries[country];
+ if (!document.querySelector(".en__field--country .en__field__notice")) {
+ engrid_ENGrid.addHtml('Note: This action is limited to U.S. addresses.
', ".us-only-form .en__field--country .en__field__element", "after");
}
- if (!currencies) {
- this.logger.log(`No currencies found for ${country}`);
- return;
+ const countrySelect = engrid_ENGrid.getField("supporter.country");
+ countrySelect.setAttribute("disabled", "disabled");
+ let countryValue = "United States";
+ if ([...countrySelect.options].some((o) => o.value === "US")) {
+ countryValue = "US";
}
- this.logger.log(`Loading currencies for ${country}`);
- this.currencyElement.innerHTML = "";
- for (const currency in currencies) {
- const option = document.createElement("option");
- option.value = currency;
- option.text = label
- .replace("[$$$]", currency)
- .replace("[$]", currencies[currency]);
- option.setAttribute("data-currency-code", currency);
- option.setAttribute("data-currency-symbol", currencies[currency]);
- this.currencyElement.appendChild(option);
+ else if ([...countrySelect.options].some((o) => o.value === "USA")) {
+ countryValue = "USA";
}
- // Set the currency to the first option and trigger a change event
- this.currencyElement.selectedIndex = 0;
- const event = new Event("change", { bubbles: true });
- this.currencyElement.dispatchEvent(event);
+ engrid_ENGrid.setFieldValue("supporter.country", countryValue);
+ engrid_ENGrid.createHiddenInput("supporter.country", countryValue);
+ countrySelect.addEventListener("change", () => {
+ countrySelect.value = countryValue;
+ });
+ }
+ shouldRun() {
+ return !!document.querySelector(".en__component--formblock.us-only-form .en__field--country");
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/autosubmit.js
-// Automatically submits the page if a URL argument is present
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/thank-you-page-conditional-content.js
-class Autosubmit {
+class ThankYouPageConditionalContent {
constructor() {
- this.logger = new logger_EngridLogger("Autosubmit", "#f0f0f0", "#ff0000", "π");
- this._form = en_form_EnForm.getInstance();
- if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
- !window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed() &&
- engrid_ENGrid.getUrlParameter("autosubmit") === "Y") {
- this.logger.log("Autosubmitting Form");
- // Fix EN ?chain parameter not working with email addresses with + in them
- engrid_ENGrid.setFieldValue("supporter.emailAddress", engrid_ENGrid.getFieldValue("supporter.emailAddress").replace(/\s/g, "+"));
- this._form.submitForm();
+ this.logger = new logger_EngridLogger("ThankYouPageConditionalContent");
+ if (!this.shouldRun())
+ return;
+ this.applyShowHideRadioCheckboxesState();
+ }
+ getShowHideRadioCheckboxesState() {
+ var _a;
+ try {
+ const plainState = (_a = window.sessionStorage.getItem(`engrid_ShowHideRadioCheckboxesState`)) !== null && _a !== void 0 ? _a : "";
+ return JSON.parse(plainState);
+ }
+ catch (err) {
+ return [];
+ }
+ }
+ applyShowHideRadioCheckboxesState() {
+ const state = this.getShowHideRadioCheckboxesState();
+ if (state) {
+ state.forEach((item) => {
+ this.logger.log("Processing TY page conditional content item:", item);
+ if (engrid_ENGrid.getPageID() === item.page) {
+ document
+ .querySelectorAll(`[class*="${item.class}"]`)
+ .forEach((el) => {
+ el.classList.add("hide");
+ });
+ document
+ .querySelectorAll(`.${item.class}${item.value}`)
+ .forEach((el) => {
+ el.classList.remove("hide");
+ });
+ }
+ });
}
+ this.deleteShowHideRadioCheckboxesState();
+ }
+ deleteShowHideRadioCheckboxesState() {
+ window.sessionStorage.removeItem(`engrid_ShowHideRadioCheckboxesState`);
+ }
+ shouldRun() {
+ return engrid_ENGrid.getGiftProcess();
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/event-tickets.js
-class EventTickets {
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/checkbox-label.js
+// Component to allow the user to set custom labels for the checkboxes,
+// you can customize the checkbox label on a per-page basis, which is not possible with Engaging Networks
+// The .checkbox-label element should be placed right before the checkbox form block
+
+class CheckboxLabel {
constructor() {
- // --------------------------------------------
- // Format ticket amounts as currency.
- const ticketCostElements = document.getElementsByClassName("en__ticket__field--cost");
- const ticketCurrencyElements = document.getElementsByClassName("en__ticket__currency");
- for (const ticketCurrencyElement of ticketCurrencyElements) {
- ticketCurrencyElement.classList.add("en__ticket__currency__hidden");
- }
- for (const ticketCostElement of ticketCostElements) {
- const ticketAmountElement = ticketCostElement.getElementsByClassName("en__ticket__price")[0];
- const ticketCurrencyElement = ticketCostElement.getElementsByClassName("en__ticket__currency")[0];
- const formatterOptions = {
- style: "currency",
- currency: ticketCurrencyElement.innerText,
- };
- let ticketAmountAsCurrency = Intl.NumberFormat(undefined, formatterOptions).format(Number(ticketAmountElement.innerText));
- if (ticketAmountAsCurrency.slice(-3) === ".00") {
- ticketAmountAsCurrency = ticketAmountAsCurrency.slice(0, -3);
- }
- ticketAmountElement.innerText = ticketAmountAsCurrency;
- }
+ this.logger = new logger_EngridLogger("CheckboxLabel", "#00CC95", "#2C3E50", "β
");
+ this.checkBoxesLabels = document.querySelectorAll(".checkbox-label");
+ if (!this.shoudRun())
+ return;
+ this.logger.log(`Found ${this.checkBoxesLabels.length} custom labels`);
+ this.run();
+ }
+ shoudRun() {
+ return this.checkBoxesLabels.length > 0;
+ }
+ run() {
+ this.checkBoxesLabels.forEach((checkboxLabel) => {
+ const labelHTML = checkboxLabel.innerHTML.trim();
+ const checkboxContainer = checkboxLabel.nextElementSibling;
+ const checkboxLabelElement = checkboxContainer.querySelector("label:last-child");
+ if (!checkboxLabelElement || !labelHTML)
+ return;
+ checkboxLabelElement.innerHTML = `${labelHTML}
`;
+ // Remove the original label element
+ checkboxLabel.remove();
+ this.logger.log(`Set checkbox label to "${labelHTML}"`);
+ });
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/swap-amounts.js
-// This script allows you to override the default donation amounts in Engaging Networks
-// with a custom list of amounts.
-// If the URL contains a query parameter "engrid-amounts" with a comma separated values, the script will load the
-// amounts from the parameter and set them as the default amounts for the donation
-// form.
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/optin-ladder.js
/**
- * Example:
- * window.EngridAmounts = {
- * "onetime": {
- * amounts: {
- * "10": 10,
- * "30": 30,
- * "50": 50,
- * "100": 100,
- * "Other": "other",
- * },
- * default: 30,
- * stickyDefault: false, // Optional. When true, every swap forces the default amount to be (re)selected
- * },
- * "monthly": {
- * amounts: {
- * "5": 5,
- * "15": 15,
- * "25": 25,
- * "30": 30,
- * "Other": "other",
- * },
- * default: 15,
- * stickyDefault: true, // Example forcing default on each frequency swap
- * },
- * };
+ * Docs: https://engrid.4sitestudios.com/component/optin-ladder
+ * This component is responsible for showing a ladder of checkboxes, one at a time, to the user.
+ * If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit.
+ * If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match.
+ * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps.
+ * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page.
*/
-class SwapAmounts {
+class OptInLadder {
constructor() {
- this.logger = new logger_EngridLogger("SwapAmounts", "purple", "white", "π°");
- this._amount = DonationAmount.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this.defaultChange = false; // Tracks if user changed away from default after swap
- this.swapped = false; // Tracks if we've already executed at least one swap
- this.loadAmountsFromUrl();
- if (!this.shouldRun())
- return;
- // Respond when frequency changes
- this._frequency.onFrequencyChange.subscribe(() => this.swapAmounts());
- // Track if donor moves away from the swapped default amount
- this._amount.onAmountChange.subscribe(() => {
- const configs = window.EngridAmounts;
- if (!configs)
+ this.logger = new EngridLogger("OptInLadder", "lightgreen", "darkgreen", "β");
+ this._form = EnForm.getInstance();
+ if (!this.inIframe()) {
+ this.runAsParent();
+ }
+ else if (ENGrid.getPageNumber() === 1) {
+ this.runAsChildRegular();
+ }
+ else {
+ this.runAsChildThankYou();
+ }
+ }
+ runAsParent() {
+ this.logger.log("Running as Parent");
+ if (ENGrid.getPageNumber() > 1 &&
+ ENGrid.getPageNumber() === ENGrid.getPageCount()) {
+ // We are on the Thank You Page as a Parent
+ // Check autoinject iFrame
+ const optInLadderOptions = ENGrid.getOption("OptInLadder");
+ if (!optInLadderOptions || !optInLadderOptions.iframeUrl) {
+ this.logger.log("Options not found");
return;
- const freq = this._frequency.frequency;
- if (!(freq in configs))
+ }
+ // Create an iFrame
+ const iframe = document.createElement("iframe");
+ iframe.src = optInLadderOptions.iframeUrl;
+ iframe.style.width = "100%";
+ iframe.style.height = "0";
+ iframe.scrolling = "no";
+ iframe.frameBorder = "0";
+ iframe.allowFullscreen = true;
+ iframe.allow = "payment";
+ iframe.classList.add("opt-in-ladder-iframe");
+ iframe.classList.add("engrid-iframe");
+ iframe.setAttribute("title", "Optin Ladder iframe");
+ // If the page already has an iFrame with the same class, we don't need to add another one
+ const existingIframe = document.querySelector(".opt-in-ladder-iframe");
+ if (existingIframe) {
+ this.logger.log("iFrame already exists");
return;
- if (!this.swapped)
- return; // ignore early changes before initial swap
- const currentConfig = configs[freq];
- this.defaultChange = this._amount.amount !== currentConfig.default;
- });
- }
- loadAmountsFromUrl() {
- const urlParams = new URLSearchParams(window.location.search);
- const amounts = urlParams.get("engrid-amounts");
- if (amounts) {
- this.defaultChange = true; // if amounts come from URL, treat as user-set
- const amountArray = amounts
- .split(",")
- .map((amt) => amt.trim())
- .filter(Boolean);
- if (!amountArray.length)
+ }
+ // Check if the current page is part of the excludePageIDs
+ if (optInLadderOptions.excludePageIDs &&
+ optInLadderOptions.excludePageIDs.includes(ENGrid.getPageID())) {
+ this.logger.log("Current page is excluded");
return;
- const urlDefaultParam = engrid_ENGrid.getUrlParameter("transaction.donationAmt");
- const parsedFirst = parseFloat(amountArray[0]);
- const defaultAmount = (urlDefaultParam && parseFloat(urlDefaultParam)) ||
- parsedFirst;
- const amountsObj = {};
- amountArray.forEach((raw) => {
- const numeric = parseFloat(raw);
- amountsObj[raw] = isNaN(numeric) ? raw : numeric;
+ }
+ // Append the iFrame to the proper placement
+ const placementQuerySelector = optInLadderOptions.placementQuerySelector || ".body-top";
+ const placement = document.querySelector(placementQuerySelector);
+ if (!placement) {
+ this.logger.error("Placement not found");
+ return;
+ }
+ placement.appendChild(iframe);
+ }
+ else {
+ // Grab all the checkboxes with the name starting with "supporter.questions"
+ const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
+ if (checkboxes.length === 0) {
+ this.logger.log("No checkboxes found");
+ return;
+ }
+ this._form.onSubmit.subscribe(() => {
+ // Save the checkbox values to sessionStorage
+ this.saveOptInsToSessionStorage("parent");
});
- // Ensure Other choice always present at the end
- amountsObj["Other"] = "other";
- const config = {
- amounts: amountsObj,
- default: defaultAmount,
- // stickyDefault omitted so it defaults to false behavior
- };
- window.EngridAmounts = {
- onetime: config,
- monthly: config,
- };
+ if (ENGrid.getPageNumber() === 1) {
+ // Delete items from sessionStorage
+ this.clearSessionStorage();
+ }
}
}
- swapAmounts() {
- const configs = window.EngridAmounts;
- if (!configs)
+ runAsChildRegular() {
+ if (!this.isEmbeddedThankYouPage()) {
+ this.logger.log("Not Embedded on a Thank You Page");
return;
- const freq = this._frequency.frequency;
- const config = configs[freq];
- if (!config)
+ }
+ const optInHeaders = document.querySelectorAll(".en__component--copyblock.optin-ladder");
+ const optInFormBlocks = document.querySelectorAll(".en__component--formblock.optin-ladder");
+ if (optInHeaders.length === 0 && optInFormBlocks.length === 0) {
+ this.logger.log("No optin-ladder elements found");
return;
- const stickyDefault = !!config.stickyDefault;
- // If stickyDefault, always ignore current value so selected flag in list enforces default
- const ignoreCurrentValue = stickyDefault ? true : this.ignoreCurrentValue();
- window.EngagingNetworks.require._defined.enjs.swapList("donationAmt", this.toEnAmountList(config), { ignoreCurrentValue });
- this._amount.load();
- this.logger.log("Amounts Swapped To", config, { ignoreCurrentValue });
- this.swapped = true;
+ }
+ // Check if the e-mail field exist and is not empty
+ const emailField = ENGrid.getField("supporter.emailAddress");
+ if (!emailField || !emailField.value) {
+ this.logger.log("Email field is empty");
+ // Since this is a OptInLadder page with no e-mail address, hide the page
+ this.hidePage(true);
+ return;
+ }
+ const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
+ let currentStep = 0;
+ let totalSteps = optInHeaders.length;
+ let currentHeader = null;
+ let currentFormBlock = null;
+ for (let i = 0; i < optInHeaders.length; i++) {
+ const header = optInHeaders[i];
+ // Get the optin number from the .optin-ladder-XXXX class
+ const optInNumber = header.className.match(/optin-ladder-(\d+)/);
+ if (!optInNumber) {
+ this.logger.error(`No optin number found in ${header.innerText.trim()}`);
+ return;
+ }
+ const optInIndex = optInNumber[1];
+ // Get the checkbox FormBlock
+ const formBlock = document.querySelector(`.en__component--formblock.optin-ladder:has(.en__field--${optInIndex})`);
+ if (!formBlock) {
+ this.logger.log(`No form block found for ${header.innerText.trim()}`);
+ // Remove the header if there is no form block
+ header.remove();
+ // Increment the current step
+ currentStep++;
+ continue;
+ }
+ // Check if the optInIndex is in sessionStorage
+ if (sessionStorageCheckboxValues[optInIndex] === "Y") {
+ // If the checkbox is checked, remove the header and form block
+ header.remove();
+ formBlock.remove();
+ // Increment the current step
+ currentStep++;
+ continue;
+ }
+ // If there's a header and a form block, end the loop
+ currentHeader = header;
+ currentFormBlock = formBlock;
+ currentStep++;
+ break;
+ }
+ if (!currentHeader || !currentFormBlock) {
+ this.logger.log("No optin-ladder elements found");
+ // Set the current step to the total steps to avoid redirecting to the first page
+ currentStep = totalSteps;
+ this.saveStepToSessionStorage(currentStep, totalSteps);
+ // hide the page
+ this.hidePage();
+ return;
+ }
+ // Show the current header and form block, while removing the rest
+ optInHeaders.forEach((header) => {
+ if (header !== currentHeader) {
+ header.remove();
+ }
+ else {
+ header.style.display = "block";
+ }
+ });
+ optInFormBlocks.forEach((formBlock) => {
+ if (formBlock !== currentFormBlock) {
+ formBlock.remove();
+ }
+ else {
+ formBlock.style.display = "block";
+ }
+ });
+ // Save the current step to sessionStorage
+ this.saveStepToSessionStorage(currentStep, totalSteps);
+ // On form submit, save the checkbox values to sessionStorage
+ this._form.onSubmit.subscribe(() => {
+ this.saveOptInsToSessionStorage("child");
+ // Save the current step to sessionStorage
+ currentStep++;
+ this.saveStepToSessionStorage(currentStep, totalSteps);
+ });
+ }
+ runAsChildThankYou() {
+ if (!this.isEmbeddedThankYouPage()) {
+ this.logger.log("Not Embedded on a Thank You Page");
+ return;
+ }
+ const hasOptInLadderStop = sessionStorage.getItem("engrid.optin-ladder-stop");
+ const hasOptInLadderPersistStop = sessionStorage.getItem("engrid.optin-ladder-persist-stop");
+ if (hasOptInLadderPersistStop) {
+ this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page");
+ sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
+ return;
+ }
+ if (hasOptInLadderStop) {
+ this.logger.log("OptInLadder has been stopped");
+ return;
+ }
+ const sessionStorageOptInLadder = JSON.parse(sessionStorage.getItem("engrid.optin-ladder") || "{}");
+ const currentStep = sessionStorageOptInLadder.step || 0;
+ const totalSteps = sessionStorageOptInLadder.totalSteps || 0;
+ if (totalSteps === 0) {
+ this.logger.log("No total steps found in sessionStorage");
+ this.hidePage();
+ return;
+ }
+ else if (currentStep <= totalSteps) {
+ this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`);
+ this.hidePage(true);
+ // Redirect to the first page
+ window.location.href = this.getFirstPageUrl();
+ return;
+ }
+ else {
+ this.logger.log(`Current step ${currentStep} is greater than total steps ${totalSteps}`);
+ // Remove the session storage
+ this.clearSessionStorage();
+ }
+ }
+ inIframe() {
+ try {
+ return window.self !== window.top;
+ }
+ catch (e) {
+ return true;
+ }
+ }
+ saveStepToSessionStorage(step, totalSteps) {
+ sessionStorage.setItem("engrid.optin-ladder", JSON.stringify({ step, totalSteps }));
+ this.logger.log(`Saved step ${step} of ${totalSteps} to sessionStorage`);
+ }
+ saveOptInsToSessionStorage(type = "parent") {
+ // Grab all the checkboxes with the name starting with "supporter.questions"
+ const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
+ if (checkboxes.length === 0) {
+ this.logger.log("No checkboxes found");
+ return;
+ }
+ const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
+ let hasDeny = false;
+ // Loop through all the checkboxes and store the value in sessionStorage
+ checkboxes.forEach((checkbox) => {
+ if (checkbox.checked) {
+ const index = checkbox.name.split(".")[2];
+ sessionStorageCheckboxValues[index] = "Y";
+ }
+ else {
+ hasDeny = true;
+ }
+ });
+ sessionStorage.setItem("engrid.supporter.questions", JSON.stringify(sessionStorageCheckboxValues));
+ this.logger.log(`Saved checkbox values to sessionStorage: ${JSON.stringify(sessionStorageCheckboxValues)}`);
+ if (type === "child" && hasDeny) {
+ // Add a deny value to the sessionStorage to stop the ladder
+ sessionStorage.setItem("engrid.optin-ladder-stop", "Y");
+ }
}
- /**
- * Convert the internal config object into the structure Engaging Networks expects
- */
- toEnAmountList(config) {
- return Object.entries(config.amounts).map(([label, value]) => ({
- selected: value === config.default,
- label,
- value: value.toString(),
- }));
+ isEmbeddedThankYouPage() {
+ return ENGrid.getBodyData("embedded") === "thank-you-page-donation";
}
- shouldRun() {
- const hasNSG = window.EngagingNetworks.suggestedGift !== undefined &&
- Object.keys(window.EngagingNetworks.suggestedGift).length > 0;
- if (!!window.EngridAmounts && hasNSG) {
- this.logger.log("Not swapping amounts because NSG is active on page");
- }
- return !!window.EngridAmounts && !hasNSG;
+ getPageUrl(page, chain = false) {
+ const url = new URL(window.location.href);
+ const path = url.pathname.split("/");
+ path[path.length - 1] = String(page);
+ return url.origin + path.join("/") + (chain ? "?chain" : "");
}
- ignoreCurrentValue() {
- const urlParam = engrid_ENGrid.getUrlParameter("transaction.donationAmt");
- if (urlParam !== null) {
- const urlAmount = parseFloat(urlParam);
- return this._amount.amount !== urlAmount;
+ getFirstPageUrl() {
+ return this.getPageUrl(1, true);
+ }
+ hidePage(forceHide = false) {
+ if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) {
+ this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page");
+ sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y");
+ window.location.href = this.getPageUrl(2);
}
- // If submission failed or donor manually changed away from default, respect current value
- const submissionFailed = window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed();
- return !(submissionFailed || this.defaultChange);
+ else {
+ const engridPage = document.querySelector("#engrid");
+ if (engridPage) {
+ engridPage.classList.add("hide");
+ }
+ }
+ }
+ clearSessionStorage() {
+ sessionStorage.removeItem("engrid.supporter.questions");
+ sessionStorage.removeItem("engrid.optin-ladder");
+ sessionStorage.removeItem("engrid.optin-ladder-stop");
+ sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/debug-panel.js
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/post-donation-embed.js
+// This component only works on Thank You pages and the current page IS NOT embedded as an iframe.
+// It searches for a post-donation tag (engrid-post-donation)
+// and if it exists, it will replace it with an iframe of the chained `src` attribute (or the current donation page, replacing the
+// "/donate/2" with "/donate/1").
+// The engrid-post-donation tag has 3 attributes:
+// 1. src: the URL of the iframe to load (optional)
+// 2. params: the URL parameters to pass to the iframe
+// 3. amounts: comma separated list of amounts to pass to the iframe
-class DebugPanel {
- constructor(pageLayouts) {
- var _a, _b;
- this.logger = new logger_EngridLogger("Debug Panel", "#f0f0f0", "#ff0000", "π₯");
- this.brandingHtml = new BrandingHtml();
- this.element = null;
- this.currentTimestamp = this.getCurrentTimestamp();
- this.quickFills = {
- "pi-general": [
- {
- name: "supporter.title",
- value: "Ms",
- },
- {
- name: "supporter.firstName",
- value: "4Site",
- },
- {
- name: "supporter.lastName",
- value: "Studio",
- },
- {
- name: "supporter.emailAddress",
- value: "en-test@4sitestudios.com",
- },
- {
- name: "supporter.phoneNumber",
- value: "555-555-5555",
- },
- ],
- "pi-unique": [
- {
- name: "supporter.title",
- value: "Ms",
- },
- {
- name: "supporter.firstName",
- value: `4Site ${this.currentTimestamp}`,
- },
- {
- name: "supporter.lastName",
- value: "Studio",
- },
- {
- name: "supporter.emailAddress",
- value: `en-test+${this.currentTimestamp}@4sitestudios.com`,
- },
- {
- name: "supporter.phoneNumber",
- value: "555-555-5555",
- },
- ],
- "us-address": [
- {
- name: "supporter.address1",
- value: "3431 14th St NW",
- },
- {
- name: "supporter.address2",
- value: "Suite 1",
- },
- {
- name: "supporter.city",
- value: "Washington",
- },
- {
- name: "supporter.region",
- value: "DC",
- },
- {
- name: "supporter.postcode",
- value: "20010",
- },
- {
- name: "supporter.country",
- value: "US",
- },
- ],
- "us-address-senate-rep": [
- {
- name: "supporter.address1",
- value: "20 W 34th Street",
- },
- {
- name: "supporter.address2",
- value: "",
- },
- {
- name: "supporter.city",
- value: "New York",
- },
- {
- name: "supporter.region",
- value: "NY",
- },
- {
- name: "supporter.postcode",
- value: "10001",
- },
- {
- name: "supporter.country",
- value: "US",
- },
- ],
- "us-address-nonexistent": [
- {
- name: "supporter.address1",
- value: "12345 Main Street",
- },
- {
- name: "supporter.address2",
- value: "",
- },
- {
- name: "supporter.city",
- value: "New York",
- },
- {
- name: "supporter.region",
- value: "TX",
- },
- {
- name: "supporter.postcode",
- value: "90210",
- },
- {
- name: "supporter.country",
- value: "US",
- },
- ],
- "cc-paysafe-visa": [
- {
- name: "transaction.ccnumber",
- value: "4530910000012345",
- },
- {
- name: "transaction.ccexpire",
- value: "12/27",
- },
- {
- name: "transaction.ccvv",
- value: "111",
- },
- ],
- "cc-paysafe-visa-invalid": [
- {
- name: "transaction.ccnumber",
- value: "411111",
- },
- {
- name: "transaction.ccexpire",
- value: "12/27",
- },
- {
- name: "transaction.ccvv",
- value: "111",
- },
- ],
- "cc-paysafe-mastercard": [
- {
- name: "transaction.ccnumber",
- value: "5036150000001115",
- },
- {
- name: "transaction.ccexpire",
- value: "12/27",
- },
- {
- name: "transaction.ccvv",
- value: "111",
- },
- ],
- "cc-stripe-visa": [
- {
- name: "transaction.ccnumber",
- value: "4242424242424242",
- },
- {
- name: "transaction.ccexpire",
- value: "12/27",
- },
- {
- name: "transaction.ccvv",
- value: "111",
- },
- ],
- "quick-fill-pi-unique-us-address-senate-rep-cc-stripe-visa": [
- {
- name: "supporter.title",
- value: "Ms",
- },
- {
- name: "supporter.firstName",
- value: `4Site ${this.currentTimestamp}`,
- },
- {
- name: "supporter.lastName",
- value: "Studio",
- },
- {
- name: "supporter.emailAddress",
- value: `en-test+${this.currentTimestamp}@4sitestudios.com`,
- },
- {
- name: "supporter.phoneNumber",
- value: "555-555-5555",
- },
- {
- name: "supporter.address1",
- value: "20 W 34th Street",
- },
- {
- name: "supporter.address2",
- value: "",
- },
- {
- name: "supporter.city",
- value: "New York",
- },
- {
- name: "supporter.region",
- value: "NY",
- },
- {
- name: "supporter.postcode",
- value: "10001",
- },
- {
- name: "supporter.country",
- value: "US",
- },
- {
- name: "transaction.ccnumber",
- value: "4242424242424242",
- },
- {
- name: "transaction.ccexpire",
- value: "12/27",
- },
- {
- name: "transaction.ccvv",
- value: "111",
- },
- ],
- };
- this.logger.log("Adding debug panel and starting a debug session");
- this.pageLayouts = pageLayouts;
- this.loadDebugPanel();
- this.element = document.querySelector(".debug-panel");
- (_a = this.element) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
- var _a;
- (_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.add("debug-panel--open");
- });
- const debugPanelClose = document.querySelector(".debug-panel__close");
- debugPanelClose === null || debugPanelClose === void 0 ? void 0 : debugPanelClose.addEventListener("click", (e) => {
- var _a;
- e.stopPropagation();
- (_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.remove("debug-panel--open");
- });
- if (engrid_ENGrid.getUrlParameter("assets") === "local") {
- (_b = this.element) === null || _b === void 0 ? void 0 : _b.classList.add("debug-panel--local");
+class PostDonationEmbed {
+ constructor() {
+ this.logger = new logger_EngridLogger("PostDonationEmbed", "red", "white", "πΌοΈ");
+ if (!this.shouldRun())
+ return;
+ this.logger.log("Post Donation Tag found");
+ const postDonationTag = document.querySelector("engrid-post-donation");
+ // Get `src` attribute from the tag if it exists
+ // If not, use the current page URL as the base URL
+ let iFrameSRC;
+ if (!postDonationTag.getAttribute("src")) {
+ iFrameSRC = new URL(window.location.href);
+ // Modify the path: replace "/donate/2" with "/donate/1"
+ iFrameSRC.pathname = iFrameSRC.pathname.replace("/donate/2", "/donate/1");
}
- window.sessionStorage.setItem(DebugPanel.debugSessionStorageKey, "active");
- }
- loadDebugPanel() {
- document.body.insertAdjacentHTML("beforeend", `
-
-
Debug
-
-
-
-
- Quick-fill
-
- Choose an option
- Quick-fill - Unique w/ Senate Address - Stripe Visa
- Personal Info - General
- Personal Info - Unique
- US Address - w/ Senate Rep
- US Address - w/o Senate Rep
- US Address - Nonexistent
- CC - Paysafe - Visa
- CC - Paysafe - Visa (Invalid)
- CC - Paysafe - Mastercard
- CC - Stripe - Visa
-
-
-
- Layout
-
-
-
-
-
-
- Embedded layout
-
-
-
-
-
- Theme
-
-
-
- Sub-theme
-
-
-
- Submit form
-
-
-
-
-
-
`);
- this.setupLayoutSwitcher();
- this.setupThemeSwitcher();
- this.setupSubThemeSwitcher();
- this.setupFormQuickfill();
- this.createDebugSessionEndHandler();
- this.setupEmbeddedLayoutSwitcher();
- this.setupDebugLayoutSwitcher();
- this.setupBrandingHtmlHandler();
- this.setupEditBtnHandler();
- this.setupForceSubmitLinkHandler();
- this.setupSubmitBtnHandler();
+ else {
+ iFrameSRC = new URL(postDonationTag.getAttribute("src") || "");
+ }
+ // Extract parameters from the tag
+ let params = postDonationTag.getAttribute("params") || "";
+ let amounts = postDonationTag.getAttribute("amounts");
+ // Format parameters correctly
+ let searchParams = new URLSearchParams(params.replace(/&/g, "&"));
+ let paramString = searchParams
+ .toString()
+ .replace(/%5B/g, "[")
+ .replace(/%5D/g, "]");
+ // Construct new URL with "chain" parameter
+ let newUrl = `${iFrameSRC.origin}${iFrameSRC.pathname}?chain&${paramString}`;
+ if (amounts) {
+ newUrl += `&engrid-amounts=${amounts}`;
+ }
+ // Create the iframe element
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("loading", "lazy");
+ iframe.setAttribute("width", "100%");
+ iframe.setAttribute("scrolling", "no");
+ iframe.setAttribute("class", "engrid-iframe thank-you-page-donation");
+ iframe.setAttribute("src", newUrl);
+ iframe.setAttribute("frameborder", "0");
+ iframe.setAttribute("allowfullscreen", "");
+ iframe.setAttribute("allowpaymentrequest", "true");
+ iframe.setAttribute("allow", "payment");
+ iframe.setAttribute("title", "Post Donation iframe");
+ // Replace with the iframe
+ postDonationTag.replaceWith(iframe);
}
- switchENGridLayout(layout) {
- engrid_ENGrid.setBodyData("layout", layout);
+ shouldRun() {
+ return (engrid_ENGrid.isThankYouPage() &&
+ this.hasPostDonationTag() &&
+ engrid_ENGrid.getBodyData("embedded") === null);
}
- setupLayoutSwitcher() {
- var _a, _b;
- const engridLayoutSwitch = document.getElementById("engrid-layout-switch");
- if (engridLayoutSwitch) {
- (_a = this.pageLayouts) === null || _a === void 0 ? void 0 : _a.forEach((layout) => {
- engridLayoutSwitch.insertAdjacentHTML("beforeend", `${layout} `);
- });
- engridLayoutSwitch.value = (_b = engrid_ENGrid.getBodyData("layout")) !== null && _b !== void 0 ? _b : "";
- engridLayoutSwitch.addEventListener("change", (e) => {
- const target = e.target;
- this.switchENGridLayout(target.value);
- });
- }
+ hasPostDonationTag() {
+ return !!document.querySelector("engrid-post-donation");
}
- setupThemeSwitcher() {
- var _a;
- const engridThemeInput = document.getElementById("engrid-theme");
- if (engridThemeInput) {
- engridThemeInput.value = (_a = engrid_ENGrid.getBodyData("theme")) !== null && _a !== void 0 ? _a : "";
- ["keyup", "blur"].forEach((ev) => {
- engridThemeInput.addEventListener(ev, (e) => {
- const target = e.target;
- this.switchENGridTheme(target.value);
- });
- });
- }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/frequency-upsell-modal.js
+/*
+ * FrequencyUpsellModal - this is class that creates the modal for the frequency upsell.
+ * This component is intentionally "dumb" and only creates the modal renders its content.
+ * Logic for showing the modal and handling the upsell is in the FrequencyUpsell class.
+ */
+
+class FrequencyUpsellModal extends Modal {
+ constructor(upsellOptions) {
+ super({
+ onClickOutside: "bounce",
+ customClass: `engrid--frequency-upsell-modal ${upsellOptions.customClass}`,
+ showCloseX: false,
+ });
+ this._amountWithFees = 0;
+ this._upsellAmountWithFees = 0;
+ this.upsellOptions = upsellOptions;
+ this.updateModalContent();
}
- switchENGridTheme(theme) {
- engrid_ENGrid.setBodyData("theme", theme);
+ set amountWithFees(value) {
+ this._amountWithFees = value;
}
- setupSubThemeSwitcher() {
+ set upsellAmountWithFees(value) {
+ this._upsellAmountWithFees = value;
+ }
+ updateModalContent() {
var _a;
- const engridSubthemeInput = document.getElementById("engrid-subtheme");
- if (engridSubthemeInput) {
- engridSubthemeInput.value = (_a = engrid_ENGrid.getBodyData("subtheme")) !== null && _a !== void 0 ? _a : "";
- ["keyup", "blur"].forEach((ev) => {
- engridSubthemeInput.addEventListener(ev, (e) => {
- const target = e.target;
- this.switchENGridSubtheme(target.value);
- });
- });
+ this.modalContent = this.getModalContent();
+ const modalBody = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector(".engrid-modal__body");
+ if (modalBody) {
+ modalBody.innerHTML = "";
+ modalBody.insertAdjacentHTML("beforeend", this.modalContent);
}
}
- switchENGridSubtheme(subtheme) {
- engrid_ENGrid.setBodyData("subtheme", subtheme);
+ getModalContent() {
+ if (!this.upsellOptions)
+ return "";
+ return `
+
+
+
+
${this.replaceAmountTokens(this.upsellOptions.title)}
+
${this.replaceAmountTokens(this.upsellOptions.paragraph)}
+
+
+
+ ${this.replaceAmountTokens(this.upsellOptions.yesButton)}
+
+
+ ${this.replaceAmountTokens(this.upsellOptions.noButton)}
+
+
+
+ `;
}
- setupFormQuickfill() {
- const engridQuickfill = document.getElementById("engrid-form-quickfill");
- engridQuickfill === null || engridQuickfill === void 0 ? void 0 : engridQuickfill.addEventListener("change", (e) => {
- const target = e.target;
- this.quickFills[target.value].forEach((qf) => {
- this.setFieldValue(qf);
- });
- });
+ replaceAmountTokens(string) {
+ const amount = engrid_ENGrid.formatNumber(this._amountWithFees, this._amountWithFees % 1 == 0 ? 0 : 2, ".", "");
+ const upsellAmount = engrid_ENGrid.formatNumber(this._upsellAmountWithFees, this._upsellAmountWithFees % 1 == 0 ? 0 : 2, ".", "");
+ return string
+ .replace(/{current_amount}/g, amount)
+ .replace(/{upsell_amount}/g, upsellAmount);
}
- setFieldValue(qf) {
- if (qf.name === "transaction.ccexpire") {
- const ccExpireEls = document.getElementsByName("transaction.ccexpire");
- if (ccExpireEls.length > 0) {
- const expirationDate = qf.value.split("/");
- ccExpireEls[0].value = expirationDate[0];
- ccExpireEls[1].value = expirationDate[1];
- ccExpireEls[0].dispatchEvent(new Event("change", { bubbles: true }));
- ccExpireEls[1].dispatchEvent(new Event("change", { bubbles: true }));
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/frequency-upsell.js
+/*
+ * FrequencyUpsell component which creates a modal to upsell the frequency of the donation
+ * This is typically used to upsell a single donation into an annual donation, but the component
+ * options can be configured to upsell any frequency to any other frequency. The upsell amount can also be configured
+ * See FrequencyUpsellOptions for more details.
+ */
+
+
+class FrequencyUpsell {
+ constructor() {
+ this.logger = new logger_EngridLogger("FrequencyUpsell", "lightgray", "darkblue", "π¦");
+ this.upsellModal = null;
+ this.options = null;
+ this._frequency = DonationFrequency.getInstance();
+ this._amount = DonationAmount.getInstance();
+ this._fee = ProcessingFees.getInstance();
+ this._form = en_form_EnForm.getInstance();
+ this.modalSeen = false;
+ if (!this.shouldRun()) {
+ this.logger.log("FrequencyUpsell not running");
+ return;
+ }
+ this.options = this.selectOptions(window.EngridFrequencyUpsell);
+ this.logger.log("FrequencyUpsell initialized", this.options);
+ this.upsellModal = new FrequencyUpsellModal(this.options);
+ this.createFrequencyField();
+ this.addEventListeners();
+ }
+ /**
+ * Select the proper options (single config or A/B variant) and return a concrete FrequencyUpsellOptions object.
+ * If an A/B test config is provided (abTest: true, options: [...]) a random variant is chosen and stored
+ * in a 1-day cookie so subsequent visits get the same variant.
+ */
+ selectOptions(config) {
+ // Simple (non AB) case
+ if (!config.abTest) {
+ return Object.assign(Object.assign({}, FrequencyUpsellOptionsDefaults), config);
+ }
+ const abConfig = config;
+ const cookieName = abConfig.cookieName || "engrid_frequency_upsell_variant";
+ const existing = get(cookieName);
+ let index;
+ if (existing !== undefined) {
+ const parsed = parseInt(existing, 10);
+ if (!isNaN(parsed) && parsed >= 0 && parsed < abConfig.options.length) {
+ index = parsed;
}
else {
- ccExpireEls[0].value = qf.value;
- ccExpireEls[0].dispatchEvent(new Event("change", { bubbles: true }));
+ index = this.randomIndex(abConfig.options.length);
}
- return;
}
- engrid_ENGrid.setFieldValue(qf.name, qf.value, true, true);
- }
- getCurrentTimestamp() {
- const now = new Date();
- const year = now.getFullYear();
- const month = String(now.getMonth() + 1).padStart(2, "0");
- const day = String(now.getDate()).padStart(2, "0");
- const hours = String(now.getHours()).padStart(2, "0");
- const minutes = String(now.getMinutes()).padStart(2, "0");
- return `${year}${month}${day}-${hours}${minutes}`;
- }
- createDebugSessionEndHandler() {
- const debugSessionEndBtn = document.querySelector(".debug-panel__end-debug-link");
- debugSessionEndBtn === null || debugSessionEndBtn === void 0 ? void 0 : debugSessionEndBtn.addEventListener("click", () => {
- var _a;
- this.logger.log("Removing panel and ending debug session");
- (_a = this.element) === null || _a === void 0 ? void 0 : _a.remove();
- window.sessionStorage.removeItem(DebugPanel.debugSessionStorageKey);
- });
- }
- setupEmbeddedLayoutSwitcher() {
- const embeddedLayoutSwitch = document.getElementById("engrid-embedded-layout");
- if (embeddedLayoutSwitch) {
- embeddedLayoutSwitch.checked = !!engrid_ENGrid.getBodyData("embedded");
- embeddedLayoutSwitch.addEventListener("change", (e) => {
- const target = e.target;
- engrid_ENGrid.setBodyData("embedded", target.checked);
+ else {
+ index = this.randomIndex(abConfig.options.length);
+ }
+ // Persist for configured duration
+ const duration = abConfig.cookieDurationDays || 1;
+ set(cookieName, index.toString(), { expires: duration });
+ const chosen = abConfig.options[index];
+ // Push variant info to dataLayer if available
+ if (window.dataLayer) {
+ window.dataLayer.push({
+ event: "frequency_upsell_ab_variant",
+ frequencyUpsellVariantIndex: index,
+ frequencyUpsellVariantTitle: chosen.title,
});
}
+ return Object.assign(Object.assign({}, FrequencyUpsellOptionsDefaults), chosen);
}
- setupDebugLayoutSwitcher() {
- const debugLayoutSwitch = document.getElementById("engrid-debug-layout");
- if (debugLayoutSwitch) {
- debugLayoutSwitch.checked = engrid_ENGrid.getBodyData("debug") === "layout";
- debugLayoutSwitch.addEventListener("change", (e) => {
- const target = e.target;
- if (target.checked) {
- engrid_ENGrid.setBodyData("debug", "layout");
- }
- else {
- engrid_ENGrid.setBodyData("debug", "");
- }
- });
+ randomIndex(length) {
+ return Math.floor(Math.random() * length);
+ }
+ /**
+ * Check if the FrequencyUpsell should run:
+ * - Check if the FrequencyUpsell is enabled in the window object
+ * - Check that we don't have an EngridUpsell active on this page
+ * - Check that we don't have an EngagingNetworks upsell active on this page
+ * @returns {boolean} - true if the FrequencyUpsell should run, false otherwise
+ */
+ shouldRun() {
+ return (window.EngridFrequencyUpsell &&
+ !window.EngridUpsell &&
+ (!window.EngagingNetworks.upsell ||
+ window.EngagingNetworks.upsell.length === 0));
+ }
+ /**
+ * Get the upsell amount with/without fees
+ * We want to display to the user the amount with fees, but we need to set the donation amount to the value without fees
+ * @param {boolean} withFee - true if we want to include the fees in the upsell amount
+ * @returns {number} - The upsell amount with fees
+ */
+ getUpsellAmount(withFee) {
+ if (withFee) {
+ const upsellAmount = this.options.upsellAmount(this._amount.amount);
+ return upsellAmount + this._fee.calculateFees(upsellAmount);
}
+ return this.options.upsellAmount(this._amount.amount);
}
- setupBrandingHtmlHandler() {
- const brandingInput = document.getElementById("engrid-branding");
- brandingInput.checked =
- engrid_ENGrid.getUrlParameter("development") === "branding";
- brandingInput.addEventListener("change", (e) => {
- if (brandingInput.checked) {
- this.brandingHtml.show();
+ addEventListeners() {
+ var _a, _b;
+ // When the Modal buttons are clicked
+ (_b = (_a = this.upsellModal) === null || _a === void 0 ? void 0 : _a.modal) === null || _b === void 0 ? void 0 : _b.addEventListener("click", (e) => {
+ const target = e.target;
+ // Upsell is accepted
+ if (target.id === "frequency-upsell-yes") {
+ this.logger.log("Frequency upsell accepted");
+ this._frequency.setFrequency(this.options.upsellFrequency);
+ this._amount.setAmount(this.getUpsellAmount(false));
+ this.options.onAccept();
+ this._form.submitForm();
+ this.upsellModal.close();
+ return;
}
- else {
- this.brandingHtml.hide();
+ // Upsell is declined
+ if (target.id === "frequency-upsell-no") {
+ this.logger.log("Frequency upsell declined");
+ this.options.onDecline();
+ this._form.submitForm();
+ this.upsellModal.close();
+ return;
}
});
- }
- setupEditBtnHandler() {
- const editBtn = document.querySelector(".debug-panel__edit-link");
- editBtn === null || editBtn === void 0 ? void 0 : editBtn.addEventListener("click", () => {
- window.open(`https://${engrid_ENGrid.getDataCenter()}.engagingnetworks.app/index.html#pages/${engrid_ENGrid.getPageID()}/edit`, "_blank");
- });
- }
- setupForceSubmitLinkHandler() {
- const submitBtn = document.querySelector(".debug-panel__force-submit-link");
- submitBtn === null || submitBtn === void 0 ? void 0 : submitBtn.addEventListener("click", () => {
- const enForm = document.querySelector("form.en__component");
- enForm === null || enForm === void 0 ? void 0 : enForm.submit();
+ // When the form is submitted
+ this._form.onSubmit.subscribe(() => {
+ var _a;
+ // If we have a frequency we want to upsell on & the modal isn't already open
+ // Since frequency in the event class doesn't have a specific type, I need to cast our options array to a general string array
+ if (this.options.upsellFromFrequency.includes(this._frequency.frequency) &&
+ !this.modalSeen) {
+ // Open the modal and prevent form submission
+ this.upsellModal.amountWithFees =
+ this._amount.amount + this._fee.calculateFees(this._amount.amount);
+ this.upsellModal.upsellAmountWithFees = this.getUpsellAmount(true);
+ this.upsellModal.updateModalContent();
+ this.logger.log("Frequency upsell modal opened");
+ (_a = this.upsellModal) === null || _a === void 0 ? void 0 : _a.open();
+ this.options.onOpen();
+ this.modalSeen = true;
+ this._form.submit = false;
+ return false;
+ }
+ // If not opening, continue with the form submission
+ this._form.submit = true;
+ return true;
});
}
- setupSubmitBtnHandler() {
- const submitBtn = document.querySelector(".debug-panel__btn--submit");
- submitBtn === null || submitBtn === void 0 ? void 0 : submitBtn.addEventListener("click", () => {
- const enForm = document.querySelector(".en__submit button");
- enForm === null || enForm === void 0 ? void 0 : enForm.click();
- });
+ /**
+ * Create the frequency field for the upsell, if it does not exist on the page already
+ * This is required by DonationFrequency to set the frequency
+ */
+ createFrequencyField() {
+ const frequencyField = document.querySelector(`input[name="transaction.recurrfreq"][value="${this.options.upsellFrequency.toUpperCase()}"]`);
+ if (frequencyField)
+ return;
+ const frequencyFieldContainer = document.querySelector(".en__field--recurrfreq .en__field__element");
+ frequencyFieldContainer === null || frequencyFieldContainer === void 0 ? void 0 : frequencyFieldContainer.insertAdjacentHTML("beforeend", `
+
+
+
+ `);
}
}
-DebugPanel.debugSessionStorageKey = "engrid_debug_panel";
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/debug-hidden-fields.js
-// Switches hidden fields to be type text when debug mode is enabled.
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/sticky-nsg.js
-class DebugHiddenFields {
- constructor() {
- this.logger = new logger_EngridLogger("Debug hidden fields", "#f0f0f0", "#ff0000", "π«£");
- this.ignoreFields = ["transaction.paycurrency"];
- // Query all hidden input elements within the specified selectors
- const fields = document.querySelectorAll(".en__component--row [type='hidden'][class*='en_'], .engrid-added-input[type='hidden']");
- // Check if there are any hidden fields
- if (fields.length > 0) {
- // Log the names of the hidden fields being changed to type 'text'
- this.logger.log(`Switching the following type 'hidden' fields to type 'text': ${[
- ...fields,
- ]
- .map((f) => f.name)
- .join(", ")}`);
- // Iterate through each hidden input element
- fields.forEach((el) => {
- // Check if the field name is in the ignore list
- if (this.ignoreFields.includes(el.name)) {
- this.logger.log(`Ignoring field: ${el.name} because it is in the ignore list`);
- return;
- }
- // Change the input type to 'text' and add the required classes
- el.type = "text";
- el.classList.add("en__field__input", "en__field__input--text");
- // Create a new label element and set its text and classes
- const label = document.createElement("label");
- label.textContent = "Hidden field: " + el.name;
- label.classList.add("en__field__label");
- // Create a new 'div' element for the input field and add the required classes
- const fieldElement = document.createElement("div");
- fieldElement.classList.add("en__field__element", "en__field__element--text");
- // Create a new 'div' container for the label and input field, and add the required classes and attribute
- const fieldContainer = document.createElement("div");
- fieldContainer.classList.add("en__field", "en__field--text", "hide");
- fieldContainer.dataset.unhidden = "";
- fieldContainer.appendChild(label);
- fieldContainer.appendChild(fieldElement);
- // Insert the new field container before the original input element and move the input element into the field element div
- if (el.parentNode) {
- el.parentNode.insertBefore(fieldContainer, el);
- fieldElement.appendChild(el);
- }
- });
- }
- }
-}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/branding-html.js
-var branding_html_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-/**
- * Inserts all of the branding HTML from https://github.com/4site-interactive-studios/engrid/tree/main/reference-materials/html/brand-guide-markup
- * into the body-main section of the page.
- */
-class BrandingHtml {
+
+class StickyNSG {
constructor() {
- this.assetBaseUrl = "https://cdn.jsdelivr.net/gh/4site-interactive-studios/engrid@main/reference-materials/html/brand-guide-markup/";
- this.brandingHtmlFiles = [
- "html5-tags.html",
- "en-common-fields.html",
- "survey.html",
- // "en-common-fields-with-errors.html",
- // "en-common-fields-with-fancy-errors.html",
- "donation-page.html",
- "premium-donation.html",
- "ecards.html",
- "email-to-target.html",
- "tweet-to-target.html",
- // "click-to-call.html",
- "petition.html",
- "event.html",
- // "ecommerce.html",
- // "membership.html",
- "styles.html",
- ];
- this.bodyMain = document.querySelector(".body-main");
- this.htmlFetched = false;
+ this.logger = new logger_EngridLogger("StickyNSG", "teal", "white", "π");
+ this.cookieName = "engrid-sticky-nsg";
+ if (!this.shouldRun())
+ return;
+ this.logger.log("Sticky NSG is enabled");
+ this.deleteCookieIfGiftProcessComplete();
+ this.createStickyNSGCookie();
+ this.applyStickyNSGCookie();
}
- fetchHtml() {
- return branding_html_awaiter(this, void 0, void 0, function* () {
- const htmlRequests = this.brandingHtmlFiles.map((file) => branding_html_awaiter(this, void 0, void 0, function* () {
- const res = yield fetch(this.assetBaseUrl + file);
- return res.text();
- }));
- const brandingHtmls = yield Promise.all(htmlRequests);
- return brandingHtmls;
- });
+ shouldRun() {
+ return engrid_ENGrid.getOption("StickyNSG") === true;
}
- appendHtml() {
- this.fetchHtml().then((html) => html.forEach((h) => {
- var _a;
- const brandingSection = document.createElement("div");
- brandingSection.classList.add("brand-guide-section");
- brandingSection.innerHTML = h;
- (_a = this.bodyMain) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement("beforeend", brandingSection);
- }));
- this.htmlFetched = true;
+ /*
+ * Determine if NSG provided by EN is active on the page
+ */
+ nsgActiveOnPage() {
+ return (window.EngagingNetworks &&
+ window.EngagingNetworks.suggestedGift &&
+ typeof window.EngagingNetworks.suggestedGift === "object" &&
+ Object.keys(window.EngagingNetworks.suggestedGift).length > 0);
}
- show() {
- if (!this.htmlFetched) {
- this.appendHtml();
- return;
+ /*
+ * Delete the cookie if the gift process is complete
+ */
+ deleteCookieIfGiftProcessComplete() {
+ if (engrid_ENGrid.getGiftProcess()) {
+ this.logger.log("Gift process complete, removing sticky NSG cookie if it exists");
+ remove(this.cookieName);
}
- const guides = document.querySelectorAll(".brand-guide-section");
- guides === null || guides === void 0 ? void 0 : guides.forEach((g) => (g.style.display = "block"));
}
- hide() {
- const guides = document.querySelectorAll(".brand-guide-section");
- guides === null || guides === void 0 ? void 0 : guides.forEach((g) => (g.style.display = "none"));
+ /*
+ * Create the sticky NSG cookie if NSG is active on the page
+ */
+ createStickyNSGCookie() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.nsgActiveOnPage()) {
+ this.logger.log("No NSG active on page, not creating sticky NSG cookie");
+ return;
+ }
+ const url = new URL(window.location.href);
+ if (url.searchParams.get("skipstickynsg") === "true") {
+ this.logger.log("'skipstickynsg' param present, not creating sticky NSG cookie");
+ return;
+ }
+ // We do some reformating to match the EngridAmounts format
+ // We also add "Other" to the amounts list
+ const nsg = window.EngagingNetworks.suggestedGift;
+ this.logger.log("Creating sticky NSG cookie", nsg);
+ const oneTimeNsg = (_a = nsg.single) === null || _a === void 0 ? void 0 : _a.reduce((acc, curr) => {
+ acc[curr.value] = curr.value;
+ return acc;
+ }, {});
+ const oneTimeDefault = (_c = (_b = nsg.single) === null || _b === void 0 ? void 0 : _b.find((gift) => gift.nextSuggestedGift)) === null || _c === void 0 ? void 0 : _c.value;
+ const recurringNsg = (_d = nsg.recurring) === null || _d === void 0 ? void 0 : _d.reduce((acc, curr) => {
+ acc[curr.value] = curr.value;
+ return acc;
+ }, {});
+ const recurringDefault = (_f = (_e = nsg.recurring) === null || _e === void 0 ? void 0 : _e.find((gift) => gift.nextSuggestedGift)) === null || _f === void 0 ? void 0 : _f.value;
+ const nsgCookieData = {};
+ if (oneTimeNsg && oneTimeDefault) {
+ nsgCookieData.onetime = {
+ amounts: oneTimeNsg,
+ default: oneTimeDefault,
+ stickyDefault: false,
+ };
+ }
+ if (recurringNsg && recurringDefault) {
+ nsgCookieData.monthly = {
+ amounts: recurringNsg,
+ default: recurringDefault,
+ stickyDefault: false,
+ };
+ }
+ if (Object.keys(nsgCookieData).length === 0) {
+ this.logger.log("No valid NSG data found to create sticky NSG cookie");
+ return;
+ }
+ const cookieValue = JSON.stringify(nsgCookieData);
+ set(this.cookieName, cookieValue, { path: "/", expires: 30 });
+ this.logger.log("Sticky NSG cookie created", cookieValue);
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/country-disable.js
-// This class allows you to disable some countries from the country dropdown list.
-
-class CountryDisable {
- constructor() {
- this.logger = new logger_EngridLogger("CountryDisable", "#f0f0f0", "#333333", "π");
- const countries = document.querySelectorAll('select[name="supporter.country"], select[name="transaction.shipcountry"], select[name="supporter.billingCountry"], select[name="transaction.infcountry"]');
- const CountryDisable = engrid_ENGrid.getOption("CountryDisable");
- // Remove the countries from the dropdown list
- if (countries.length > 0 && CountryDisable.length > 0) {
- const countriesLower = CountryDisable.map((country) => country.toLowerCase());
- countries.forEach((country) => {
- country.querySelectorAll("option").forEach((option) => {
- if (countriesLower.includes(option.value.toLowerCase()) ||
- countriesLower.includes(option.text.toLowerCase())) {
- this.logger.log(`Removing ${option.text} from ${country.getAttribute("name")}`);
- option.remove();
- }
- });
- });
+ /*
+ * Apply the sticky NSG cookie values to window.EngridAmounts if NSG is not active on the page
+ */
+ applyStickyNSGCookie() {
+ if (this.nsgActiveOnPage()) {
+ this.logger.log("NSG active on page, not applying sticky NSG cookie, leaving the EN NSG values.");
+ return;
+ }
+ const cookieValue = get(this.cookieName);
+ if (!cookieValue) {
+ this.logger.log("No sticky NSG cookie found, nothing to apply");
+ return;
+ }
+ try {
+ const nsg = JSON.parse(cookieValue);
+ this.logger.log("Applying sticky NSG cookie values", nsg);
+ window.EngridAmounts = nsg;
+ }
+ catch (e) {
+ this.logger.error("Error parsing sticky NSG cookie, not applying", e);
}
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/premium-gift.js
-// Component to handle premium gift features
-// 1 - Add a class to body to indicate which premium gift is selected (data-engrid-premium-gift-name="item-name-slugged")
-// 2 - Add a class to body to indicate if the "maximize my impact" is selected (data-engrid-premium-gift-maximize="true|false")
-// 3 - Check the premium gift when click on the title or description
-// 4 - Create new {$PREMIUMTITLE} merge tag that's replaced with the premium gift name
-// 5 - Add aria-label to the radio inputs and alt tags to the images
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/sticky-prepopulation.js
+var sticky_prepopulation_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
-class PremiumGift {
+
+
+class StickyPrepopulation {
constructor() {
- this.logger = new logger_EngridLogger("PremiumGift", "#232323", "#f7b500", "π");
- this.enElements = new Array();
- this._frequency = DonationFrequency.getInstance();
- this._amount = DonationAmount.getInstance();
- if (!this.shoudRun())
+ this.logger = new logger_EngridLogger("StickyPrepopulation", "teal", "white", "π");
+ this.options = { fields: [] };
+ this.cookieName = "engrid-sticky-prepop";
+ if (!this.shouldRun()) {
return;
- this.searchElements();
- this.addEventListeners();
- this.checkPremiumGift();
- window.setTimeout(() => {
- this.altsAndArias();
- this.maxDonationAria();
- }, 1000);
- }
- shoudRun() {
- return ("pageJson" in window &&
- "pageType" in window.pageJson &&
- window.pageJson.pageType === "premiumgift");
- }
- addEventListeners() {
- ["click", "change"].forEach((event) => {
- document.addEventListener(event, (e) => {
- const element = e.target;
- const premiumGift = element.closest(".en__pg__body");
- if (premiumGift) {
- const premiumGiftInput = premiumGift.querySelector('[name="en__pg"]');
- if ("type" in element === false) {
- const premiumGiftValue = premiumGiftInput.value;
- window.setTimeout(() => {
- const newPremiumGift = document.querySelector('[name="en__pg"][value="' + premiumGiftValue + '"]');
- if (newPremiumGift) {
- newPremiumGift.checked = true;
- newPremiumGift.dispatchEvent(new Event("change"));
- }
- }, 100);
- }
- window.setTimeout(() => {
- this.checkPremiumGift();
- }, 110);
- }
- });
- });
- // Check when visibility of the Premium Gift Block changes.
- // EN will add "display: none" to this element when the supporter does not qualify for a premium
- const premiumGiftsBlock = document.querySelector(".en__component--premiumgiftblock");
- if (premiumGiftsBlock) {
- const observer = new MutationObserver((mutationsList) => {
- for (const mutation of mutationsList) {
- if (mutation.type === "attributes" &&
- mutation.attributeName === "style") {
- if (premiumGiftsBlock.style.display === "none") {
- this.logger.log("Premium Gift Section hidden - removing premium gift body data attributes and premium title.");
- engrid_ENGrid.setBodyData("premium-gift-maximize", false);
- engrid_ENGrid.setBodyData("premium-gift-name", false);
- this.setPremiumTitle("");
- }
- }
- }
- });
- observer.observe(premiumGiftsBlock, { attributes: true });
}
- this._frequency.onFrequencyChange.subscribe(() => {
- window.setTimeout(() => {
- this.altsAndArias();
- }, 1000);
- });
- this._amount.onAmountChange.subscribe(() => {
- window.setTimeout(() => {
- this.altsAndArias();
- }, 1000);
- });
- }
- checkPremiumGift() {
- const premiumGift = document.querySelector('[name="en__pg"]:checked');
- if (premiumGift) {
- const premiumGiftValue = premiumGift.value;
- this.logger.log("Premium Gift Value: " + premiumGiftValue);
- const premiumGiftContainer = premiumGift.closest(".en__pg");
- if (premiumGiftValue !== "0") {
- const premiumGiftName = premiumGiftContainer.querySelector(".en__pg__name");
- engrid_ENGrid.setBodyData("premium-gift-maximize", "false");
- engrid_ENGrid.setBodyData("premium-gift-name", engrid_ENGrid.slugify(premiumGiftName.innerText));
- this.setPremiumTitle(premiumGiftName.innerText);
- }
- else {
- engrid_ENGrid.setBodyData("premium-gift-maximize", "true");
- engrid_ENGrid.setBodyData("premium-gift-name", false);
- this.setPremiumTitle("");
- }
- if (!premiumGiftContainer.classList.contains("en__pg--selected")) {
- const checkedPremiumGift = document.querySelector(".en__pg--selected");
- if (checkedPremiumGift) {
- checkedPremiumGift.classList.remove("en__pg--selected");
- }
- premiumGiftContainer.classList.add("en__pg--selected");
- }
+ this.logger.log("StickyPrepopulation initialized");
+ if (engrid_ENGrid.getGiftProcess()) {
+ this.deleteCookie();
+ return;
+ }
+ if (engrid_ENGrid.getPageNumber() !== 1 || !engrid_ENGrid.getField("supporter.emailAddress")) {
+ this.logger.log("Not on page 1 or email field not present, not creating cookie or applying pre-population.");
+ return;
}
+ this.createCookie();
+ this.applyPrepopulation();
}
- searchElements() {
- const enElements = document.querySelectorAll(`
- .en__component--copyblock,
- .en__component--codeblock,
- .en__field
- `);
- if (enElements.length > 0) {
- enElements.forEach((item) => {
- if (item instanceof HTMLElement &&
- item.innerHTML.includes("{$PREMIUMTITLE}")) {
- item.innerHTML = item.innerHTML.replace("{$PREMIUMTITLE}", ` `);
- this.enElements.push(item);
- }
- });
+ /*
+ * Determine if we should run the script
+ * Do not run if RememberMe is active
+ * Do not run if on a chain link
+ * Only run if StickyPrepopulation option is set with fields
+ */
+ shouldRun() {
+ if (engrid_ENGrid.getOption("RememberMe")) {
+ return false;
+ }
+ const url = new URL(window.location.href);
+ const options = engrid_ENGrid.getOption("StickyPrepopulation");
+ if (options && (options === null || options === void 0 ? void 0 : options.fields.length) > 0 && !url.searchParams.has("chain")) {
+ this.options = options;
+ return true;
+ }
+ else {
+ return false;
}
}
- setPremiumTitle(title) {
- this.enElements.forEach((item) => {
- const premiumTitle = item.querySelector(".engrid_premium_title");
- if (premiumTitle) {
- premiumTitle.innerHTML = title;
+ /*
+ * Delete the cookie if the gift process is complete
+ */
+ deleteCookie() {
+ this.logger.log("Gift process complete, removing sticky prepopulation cookie if it exists");
+ remove(this.cookieName);
+ }
+ /*
+ * Create the cookie if we're coming from a campaign link and supporterId is present
+ */
+ createCookie() {
+ var _a;
+ return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ // If we're not coming from a campaign link, don't create the cookie
+ if (!((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId)) {
+ this.logger.log("No supporterId present, not creating sticky prepopulation cookie");
+ return;
+ }
+ try {
+ const encryptedSupporterDetails = yield this.encryptSupporterDetails(this.getSupporterDetailsFromFields());
+ set(this.cookieName, window.btoa(JSON.stringify({
+ encryptedData: encryptedSupporterDetails.encryptedData,
+ iv: encryptedSupporterDetails.iv,
+ pageId: engrid_ENGrid.getPageID()
+ })), { path: "/", expires: 7 });
+ }
+ catch (e) {
+ this.logger.log("Error creating sticky prepopulation cookie");
+ return;
}
+ this.logger.log("Sticky prepopulation cookie created");
});
}
- // Sets alt tags for premium gift images and aria tags for premium gift radio inputs
- altsAndArias() {
- const premiumTitle = document.querySelectorAll(".en__pg__detail h2.en__pg__name");
- const multistepBackButton = document.querySelectorAll(".multistep-button-container button.btn-back");
- premiumTitle.forEach((item) => {
- if (item) {
- const titleText = item.innerHTML;
- const parent = item.parentElement;
- const prevSibling = parent === null || parent === void 0 ? void 0 : parent.previousElementSibling;
- const radioInputSibling = prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.previousElementSibling;
- if (prevSibling) {
- const imageDiv = prevSibling.querySelector(".en__pg__images");
- if (imageDiv) {
- const img = imageDiv.querySelector("img");
- if (img) {
- img.setAttribute("alt", titleText);
- img.style.width = "125px";
- img.style.height = "100px";
- }
- }
- }
- if (radioInputSibling) {
- const radioInput = radioInputSibling.querySelector('input[type="radio"]');
- if (radioInput) {
- radioInput.setAttribute("aria-label", titleText);
- }
+ /*
+ * If the cookie is present and supporterId is not (it's not a campaign link prefilled by EN),
+ * then apply the prepopulation
+ */
+ applyPrepopulation() {
+ var _a;
+ return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const cookieData = get(this.cookieName);
+ if (!cookieData) {
+ this.logger.log("No sticky prepopulation cookie found, not prepopulating fields");
+ return;
+ }
+ if ((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId) {
+ this.logger.log("SupporterId present, not applying sticky prepopulation");
+ return;
+ }
+ let supporterDetails = {};
+ try {
+ const encryptedSupporterDetails = JSON.parse(window.atob(cookieData));
+ if (!encryptedSupporterDetails || (encryptedSupporterDetails === null || encryptedSupporterDetails === void 0 ? void 0 : encryptedSupporterDetails.pageId) !== engrid_ENGrid.getPageID()) {
+ this.logger.log("No encrypted supporter details found in cookie, or page ID does not match");
+ return;
}
+ supporterDetails = JSON.parse(yield this.decryptSupporterDetails(this.base64ToArrayBuffer(encryptedSupporterDetails.encryptedData), new Uint8Array(this.base64ToArrayBuffer(encryptedSupporterDetails.iv))));
}
- multistepBackButton.forEach((item) => {
- item.setAttribute("aria-label", "Back");
+ catch (e) {
+ this.logger.log("Error decrypting supporter details from cookie");
+ return;
+ }
+ this.options.fields.forEach((fieldName) => {
+ if (!supporterDetails[fieldName])
+ return;
+ engrid_ENGrid.setFieldValue(fieldName, decodeURIComponent(supporterDetails[fieldName]));
+ this.logger.log(`Setting "${fieldName}" to "${decodeURIComponent(supporterDetails[fieldName])}"`);
});
});
}
- // This is for the Maximize My Donation aria-label - the tree structure for it is slightly different.
- maxDonationAria() {
- const maxDonationTitle = Array.from(document.querySelectorAll(".en__pg__detail")).filter((el) => !el.querySelector("h2"));
- maxDonationTitle.forEach((item) => {
- var _a;
- if (item) {
- const titleText = ((_a = item.querySelector(".en__pg__description")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "";
- const prevSibling = item.previousElementSibling;
- const radioInputSibling = prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.previousElementSibling;
- if (radioInputSibling) {
- const radioInput = radioInputSibling.querySelector('input[type="radio"]');
- if (radioInput) {
- radioInput.setAttribute("aria-label", titleText);
- }
+ /*
+ * Get the supporter details from the form fields
+ */
+ getSupporterDetailsFromFields() {
+ const supporterDetails = {};
+ this.options.fields.forEach((fieldName) => {
+ let field = document.querySelector(`[name="${fieldName}"]`);
+ // If it is a radio or checkbox, get the checked value
+ if (field) {
+ if (field.type === "radio" || field.type === "checkbox") {
+ field = document.querySelector(`[name="${fieldName}"]:checked`);
}
+ supporterDetails[fieldName] = encodeURIComponent(field.value);
}
});
+ return supporterDetails;
+ }
+ /*
+ * Encrypt the supporter details
+ */
+ encryptSupporterDetails(supporterDetails) {
+ return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const encryptionKey = yield this.createEncryptionKey(this.getSeed());
+ const iv = window.crypto.getRandomValues(new Uint8Array(12));
+ const supporterDetailsString = JSON.stringify(supporterDetails);
+ const encryptedData = yield window.crypto.subtle.encrypt({
+ name: "AES-GCM",
+ iv: iv,
+ }, encryptionKey, new TextEncoder().encode(supporterDetailsString));
+ return {
+ encryptedData: this.arrayBufferToBase64(encryptedData),
+ iv: this.arrayBufferToBase64(iv),
+ };
+ });
+ }
+ /*
+ * Decrypt the supporter details
+ */
+ decryptSupporterDetails(encryptedSupporterDetails, iv) {
+ return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const encryptionKey = yield this.createEncryptionKey(this.getSeed());
+ const decryptedData = yield window.crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, encryptionKey, encryptedSupporterDetails);
+ return new TextDecoder().decode(decryptedData);
+ });
+ }
+ /*
+ * Create the encryption key
+ */
+ createEncryptionKey(seed) {
+ return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const encoder = new TextEncoder();
+ const keyMaterial = yield window.crypto.subtle.importKey("raw", encoder.encode(seed), { name: "PBKDF2" }, false, ["deriveKey"]);
+ return yield window.crypto.subtle.deriveKey({
+ name: "PBKDF2",
+ salt: encoder.encode(seed),
+ iterations: 100000,
+ hash: "SHA-256",
+ }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
+ });
+ }
+ /*
+ * Convert an ArrayBuffer to a base64 string
+ */
+ arrayBufferToBase64(buffer) {
+ let binary = "";
+ const bytes = new Uint8Array(buffer);
+ const len = bytes.byteLength;
+ for (let i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i]);
+ }
+ return window.btoa(binary);
+ }
+ /*
+ * Create an Array Buffer from a base64 string
+ */
+ base64ToArrayBuffer(base64) {
+ const binary_string = window.atob(base64);
+ const len = binary_string.length;
+ const bytes = new Uint8Array(len);
+ for (let i = 0; i < len; i++) {
+ bytes[i] = binary_string.charCodeAt(i);
+ }
+ return bytes.buffer;
+ }
+ /*
+ * Derive a seed from the page URL
+ */
+ getSeed() {
+ const url = new URL(window.location.href);
+ return url.origin + url.pathname + (url.searchParams.get("ea.tracking.id") ? `?ea.tracking.id=${url.searchParams.get("ea.tracking.id")}` : '');
}
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/custom-premium.js
-// ENgrid component: CustomPremium
-// Filters premium gifts based on window.EngridPageOptions.CustomPremium configuration
-// Rules:
-// - Config shape: window.EngridPageOptions.CustomPremium[frequency][productId] = minimumAmount
-// - On frequency or amount change, wait 500ms (allow EN to re-render), then:
-// - Show only gifts whose minimumAmount <= current amount; hide others
-// - If none visible, hide entire .en__component--premiumgiftblock
-// - If current selection becomes invalid, select default; if default not visible, select "No Premium" and clear transaction.selprodvariantid
-// - Run once 500ms after page load
-// - Add EnForm onSubmit hook to clear transaction.selprodvariantid when no visible premium items
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/preferred-payment-method.js
-class CustomPremium {
+class PreferredPaymentMethod {
constructor() {
- this.logger = new logger_EngridLogger("CustomPremium", "teal", "white", "π§©");
- this._amount = DonationAmount.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this._enForm = en_form_EnForm.getInstance();
- this.stylesInjected = false;
- this.pendingFrequencyChange = false;
- if (!this.shouldRun())
+ var _a;
+ this.logger = new logger_EngridLogger("PreferredPaymentMethod", "#ffffff", "#1f2933", "βοΈ");
+ this.availabilityTimeoutMs = 4000;
+ this.cleanupHandlers = [];
+ this.selectionFinalized = false;
+ this.listenersAttached = false;
+ this.config = this.resolveConfig();
+ this.preferredFieldName = ((_a = this.config.preferredPaymentMethodField) === null || _a === void 0 ? void 0 : _a.trim()) || "";
+ if (!this.shouldRun()) {
return;
- this.injectStyles();
- // Initial run: execute once after 500ms
- window.setTimeout(() => this.run(), 500);
- // On changes, schedule processing and fade out immediately
- this._amount.onAmountChange.subscribe(() => this.scheduleRun());
- this._frequency.onFrequencyChange.subscribe(() => {
- this.pendingFrequencyChange = true;
- this.scheduleRun();
- });
- // Clear hidden variant field on submit if there are no visible premium items
- this._enForm.onSubmit.subscribe(() => {
- if (!this.hasVisiblePremiumItems()) {
- this.clearVariantField();
- }
- });
+ }
+ this.attachGiveBySelectListeners();
+ const candidates = this.buildCandidateList();
+ if (candidates.length === 0) {
+ this.logger.log("No payment methods to evaluate. Skipping.");
+ return;
+ }
+ this.logger.log(`Evaluating preferred payment methods in order: ${candidates.join(", ")}`);
+ this.tryCandidateAtIndex(0, candidates);
}
shouldRun() {
- const isPremiumPage = "pageJson" in window &&
- "pageType" in window.pageJson &&
- window.pageJson.pageType === "premiumgift";
- const hasConfig = !!engrid_ENGrid.getOption("CustomPremium");
- return isPremiumPage && hasConfig;
- }
- get config() {
- const cfg = engrid_ENGrid.getOption("CustomPremium");
- return cfg || null;
- }
- get premiumContainer() {
- return document.querySelector(".en__component--premiumgiftblock");
+ if (engrid_ENGrid.getPageType() !== "DONATION") {
+ this.logger.log("Not a donation page. Skipping preferred payment selection.");
+ return false;
+ }
+ // If there's a "payment" URL parameter, we can proceed
+ if (engrid_ENGrid.getUrlParameter("payment")) {
+ return true;
+ }
+ if (!this.getGiveBySelectInputs().length) {
+ this.logger.log("No give-by-select inputs found. Skipping.");
+ return false;
+ }
+ const config = engrid_ENGrid.getOption("PreferredPaymentMethod") || false;
+ if (config === false) {
+ this.logger.log("PreferredPaymentMethod option disabled.");
+ return false;
+ }
+ return true;
}
- get giftItems() {
- return Array.from(document.querySelectorAll(".en__pg"));
+ resolveConfig() {
+ const option = engrid_ENGrid.getOption("PreferredPaymentMethod") || false;
+ if (option && typeof option === "object") {
+ const preferredPaymentMethodField = option.preferredPaymentMethodField || "";
+ const defaultPaymentMethod = Array.isArray(option.defaultPaymentMethod)
+ ? option.defaultPaymentMethod.filter((item) => !!item)
+ : [];
+ return {
+ preferredPaymentMethodField,
+ defaultPaymentMethod: defaultPaymentMethod.length > 0 ? defaultPaymentMethod : ["card"],
+ };
+ }
+ return {
+ preferredPaymentMethodField: "",
+ defaultPaymentMethod: ["card"],
+ };
}
- getFrequencyConfig(frequency) {
- const customPremiumConfig = this.config;
- if (!customPremiumConfig)
- return null;
- const frequencyConfig = customPremiumConfig[frequency];
- if (frequencyConfig && typeof frequencyConfig === "object")
- return frequencyConfig;
- return null;
+ buildCandidateList() {
+ const candidates = [];
+ const seen = new Set();
+ const pushCandidate = (value) => {
+ if (!value)
+ return;
+ const normalized = this.normalizePaymentValue(value);
+ if (!normalized || seen.has(normalized))
+ return;
+ seen.add(normalized);
+ candidates.push(normalized);
+ };
+ pushCandidate(this.getFieldPreference());
+ pushCandidate(this.getUrlPreference());
+ this.config.defaultPaymentMethod.forEach(pushCandidate);
+ return candidates;
}
- getProductsMap(frequency) {
- const frequencyConfig = this.getFrequencyConfig(frequency);
- const productsMap = {};
- if (!frequencyConfig)
- return productsMap;
- // If explicit products object exists, use it
- if (frequencyConfig.products &&
- typeof frequencyConfig.products === "object") {
- Object.entries(frequencyConfig.products).forEach(([productId, min]) => {
- const id = String(productId);
- const minAmount = Number(min);
- if (!isNaN(minAmount))
- productsMap[id] = minAmount;
- });
- return productsMap;
+ hasPreferredField() {
+ if (!this.preferredFieldName)
+ return false;
+ const field = engrid_ENGrid.getField(this.preferredFieldName);
+ return !!field;
+ }
+ attachGiveBySelectListeners() {
+ if (this.listenersAttached)
+ return;
+ if (!this.preferredFieldName)
+ return;
+ if (!this.hasPreferredField()) {
+ this.logger.log(`Preferred payment field "${this.preferredFieldName}" not found. Field sync disabled.`);
+ return;
}
- // Otherwise, treat own numeric-value keys as products, ignore 'default'
- Object.entries(frequencyConfig).forEach(([key, value]) => {
- if (key === "default")
- return;
- const minAmount = Number(value);
- if (!isNaN(minAmount))
- productsMap[String(key)] = minAmount;
+ const inputs = this.getGiveBySelectInputs();
+ inputs.forEach((input) => {
+ input.addEventListener("change", () => {
+ if (input.checked) {
+ this.syncPreferredField(input.value);
+ }
+ });
});
- return productsMap;
+ this.listenersAttached = true;
}
- getConfiguredDefaultPid(frequency) {
- const frequencyConfig = this.getFrequencyConfig(frequency);
- if (!frequencyConfig)
+ syncPreferredField(value) {
+ if (!this.preferredFieldName)
+ return;
+ if (!this.hasPreferredField())
+ return;
+ engrid_ENGrid.setFieldValue(this.preferredFieldName, value, false, true);
+ }
+ getFieldPreference() {
+ if (!this.preferredFieldName) {
return null;
- const defaultValue = frequencyConfig.default;
- if (defaultValue === undefined || defaultValue === null)
- return "0"; // not set => No Premium by spec
- const id = String(defaultValue);
- return id;
+ }
+ const fieldValue = engrid_ENGrid.getFieldValue(this.preferredFieldName);
+ if (!fieldValue) {
+ this.logger.log(`Preferred payment field "${this.preferredFieldName}" is empty. Moving on.`);
+ return null;
+ }
+ this.logger.log(`Preferred payment from field "${this.preferredFieldName}" resolved to "${fieldValue}".`);
+ return fieldValue;
}
- injectStyles() {
- if (this.stylesInjected)
+ getUrlPreference() {
+ const urlValue = engrid_ENGrid.getUrlParameter("payment");
+ if (typeof urlValue === "string" && urlValue.trim() !== "") {
+ this.logger.log(`Preferred payment from URL parameter: "${urlValue}".`);
+ return urlValue;
+ }
+ return null;
+ }
+ tryCandidateAtIndex(index, candidates) {
+ if (this.selectionFinalized) {
return;
- const id = "engrid-custom-premium-style";
- if (document.getElementById(id)) {
- this.stylesInjected = true;
+ }
+ if (index >= candidates.length) {
+ this.logger.log("No preferred payment method was applied.");
return;
}
- const style = document.createElement("style");
- style.id = id;
- style.innerHTML = `
- .en__component--premiumgiftblock { transition: opacity 200ms ease-in-out; }
- .en__component--premiumgiftblock.engrid-premium-processing { opacity: 0; pointer-events: none; }
- .en__component--premiumgiftblock.engrid-premium-hidden { display: none !important; }
- .en__component--premiumgiftblock.engrid-premium-ready { opacity: 1; }
- `;
- document.head.appendChild(style);
- this.stylesInjected = true;
+ const method = candidates[index];
+ if (!this.paymentMethodExists(method)) {
+ this.logger.log(`Payment method "${method}" not found. Skipping.`);
+ this.tryCandidateAtIndex(index + 1, candidates);
+ return;
+ }
+ if (this.isPaymentMethodAvailable(method)) {
+ this.logger.success(`Selecting available payment method "${method}".`);
+ this.applySelection(method);
+ return;
+ }
+ this.logger.log(`Payment method "${method}" exists but is not available yet. Waiting up to ${this.availabilityTimeoutMs}ms.`);
+ this.waitForAvailability(method, () => {
+ if (this.selectionFinalized)
+ return;
+ if (this.isPaymentMethodAvailable(method)) {
+ this.logger.success(`Selecting payment method "${method}" once it became available.`);
+ this.applySelection(method);
+ }
+ }, () => {
+ if (this.selectionFinalized)
+ return;
+ this.logger.log(`Payment method "${method}" still unavailable after waiting. Trying next option.`);
+ this.tryCandidateAtIndex(index + 1, candidates);
+ });
}
- startProcessingVisual() {
- const container = this.premiumContainer;
- if (container) {
- container.classList.add("engrid-premium-processing");
- container.classList.remove("engrid-premium-ready");
+ waitForAvailability(method, onAvailable, onTimeout) {
+ const observers = [];
+ const cleanup = () => {
+ observers.forEach((observer) => observer.disconnect());
+ observers.length = 0;
+ this.cleanupHandlers = this.cleanupHandlers.filter((fn) => fn !== cleanup);
+ window.clearTimeout(timeoutId);
+ };
+ this.cleanupHandlers.push(cleanup);
+ const checkAvailability = () => {
+ if (this.selectionFinalized) {
+ cleanup();
+ return;
+ }
+ if (this.isPaymentMethodAvailable(method)) {
+ cleanup();
+ onAvailable();
+ }
+ };
+ const fieldContainer = this.getGiveBySelectContainer() || document.body;
+ const domObserver = new MutationObserver(() => checkAvailability());
+ domObserver.observe(fieldContainer, {
+ attributes: true,
+ attributeFilter: ["class", "style"],
+ childList: true,
+ subtree: true,
+ });
+ observers.push(domObserver);
+ const attributeFilters = this.getAvailabilityAttributeFilters(method);
+ if (attributeFilters.length > 0) {
+ const attrObserver = new MutationObserver(() => checkAvailability());
+ attrObserver.observe(document.body, {
+ attributes: true,
+ attributeFilter: attributeFilters,
+ });
+ observers.push(attrObserver);
}
+ const timeoutId = window.setTimeout(() => {
+ cleanup();
+ onTimeout();
+ }, this.availabilityTimeoutMs);
}
- endProcessingVisual(hasVisible) {
- const container = this.premiumContainer;
- if (!container)
+ applySelection(method) {
+ if (this.selectionFinalized) {
return;
- container.classList.remove("engrid-premium-processing");
- if (hasVisible) {
- container.classList.remove("engrid-premium-hidden");
- container.classList.add("engrid-premium-ready");
}
- else {
- container.classList.add("engrid-premium-hidden");
- container.classList.remove("engrid-premium-ready");
+ const input = this.findPaymentInput(method);
+ if (!input) {
+ this.logger.log(`Unable to locate give-by-select input for "${method}" during selection.`);
+ return;
+ }
+ if (!this.isPaymentMethodAvailable(method)) {
+ this.logger.log(`Payment method "${method}" is not available to select.`);
+ return;
}
+ input.checked = true;
+ input.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
+ engrid_ENGrid.setPaymentType(method);
+ this.syncPreferredField(input.value);
+ this.selectionFinalized = true;
+ this.cleanupAllObservers();
}
- scheduleRun() {
- // Immediately fade out while we wait for EN to re-render
- this.startProcessingVisual();
- if (this.debounceTimer)
- window.clearTimeout(this.debounceTimer);
- this.debounceTimer = window.setTimeout(() => this.run(), 500);
+ paymentMethodExists(method) {
+ return !!this.findPaymentInput(method);
}
- getCurrentFreq() {
- return (this._frequency.frequency || "onetime").toLowerCase();
+ isPaymentMethodAvailable(method) {
+ const input = this.findPaymentInput(method);
+ if (!input || input.disabled) {
+ return false;
+ }
+ const container = this.getInputContainer(input);
+ return container ? engrid_ENGrid.isVisible(container) : engrid_ENGrid.isVisible(input);
}
- getCurrentAmount() {
- return this._amount.amount || 0;
+ findPaymentInput(method) {
+ const normalized = this.normalizePaymentValue(method);
+ if (!normalized) {
+ return null;
+ }
+ const inputs = this.getGiveBySelectInputs();
+ return (Array.from(inputs).find((input) => input.value && this.normalizePaymentValue(input.value) === normalized) || null);
}
- getAllowedProductIds(freq, amount) {
- const cfg = this.config;
- const allowed = new Set();
- if (!cfg)
- return allowed;
- const products = this.getProductsMap(freq);
- Object.keys(products).forEach((pid) => {
- const min = Number(products[pid]);
- if (!isNaN(min) && amount >= min)
- allowed.add(String(pid));
- });
- return allowed;
+ getGiveBySelectInputs() {
+ return document.getElementsByName("transaction.giveBySelect");
}
- getProductId(item) {
- const input = item.querySelector('input[name="en__pg"]');
- return input ? input.value : null;
+ getGiveBySelectContainer() {
+ return document.querySelector(".en__field--give-by-select, .give-by-select");
}
- showItem(item, show) {
- item.style.display = show ? "" : "none";
+ getInputContainer(input) {
+ return (input.closest(".en__field__item") ||
+ input.closest(".en__field__element") ||
+ input.parentElement);
}
- selectByProductId(productId) {
- const radio = document.querySelector('input[name="en__pg"][value="' + productId + '"]');
- if (radio) {
- radio.checked = true;
- radio.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
- // Update EN's selected class if necessary
- const prev = document.querySelector(".en__pg--selected");
- const pg = radio.closest(".en__pg");
- if (prev && prev !== pg)
- prev.classList.remove("en__pg--selected");
- if (pg)
- pg.classList.add("en__pg--selected");
+ findLabelForInput(input) {
+ if (input.id) {
+ const externalLabel = document.querySelector(`label[for="${input.id}"]`);
+ if (externalLabel) {
+ return externalLabel;
+ }
}
+ return input.closest("label");
}
- clearVariantField() {
- engrid_ENGrid.setFieldValue("transaction.selprodvariantid", "");
+ normalizePaymentValue(value) {
+ return value.trim().toLowerCase();
}
- hasVisiblePremiumItems() {
- // Exclude the "No Premium" (value 0) from count
- return this.giftItems.some((item) => {
- const pid = this.getProductId(item);
- const visible = engrid_ENGrid.isVisible(item);
- return visible && pid !== "0";
- });
+ getAvailabilityAttributeFilters(method) {
+ const map = {
+ stripedigitalwallet: [
+ "data-engrid-payment-type-option-apple-pay",
+ "data-engrid-payment-type-option-google-pay",
+ ],
+ paypaltouch: [
+ "data-engrid-payment-type-option-paypal-one-touch",
+ "data-engrid-payment-type-option-venmo",
+ ],
+ daf: ["data-engrid-payment-type-option-daf"],
+ };
+ return map[method] || [];
}
- run() {
- const container = this.premiumContainer;
- if (!container)
- return this.logger.log("No premium container found.");
- const frequency = this.getCurrentFreq();
- const amount = this.getCurrentAmount();
- const allowedProductIds = this.getAllowedProductIds(frequency, amount);
- // Iterate items and toggle visibility
- let anyVisible = false;
- const items = this.giftItems;
- const noPremiumItems = [];
- items.forEach((item) => {
- const productId = this.getProductId(item);
- if (!productId)
- return;
- if (productId === "0") {
- // track no-premium items but don't decide visibility here β it's always available
- noPremiumItems.push(item);
- this.showItem(item, true);
- return;
- }
- const visible = allowedProductIds.has(productId);
- this.showItem(item, visible);
- if (visible)
- anyVisible = true;
+ cleanupAllObservers() {
+ this.cleanupHandlers.forEach((cleanup) => cleanup());
+ this.cleanupHandlers = [];
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/version.js
+const AppVersion = "0.25.2";
+
+;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/index.js
+ // Runs first so it can change the DOM markup before any markup dependent code fires
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Events
+
+// Version
+
+
+// EXTERNAL MODULE: ./node_modules/smoothscroll-polyfill/dist/smoothscroll.js
+var smoothscroll = __webpack_require__(1196);
+var smoothscroll_default = /*#__PURE__*/__webpack_require__.n(smoothscroll);
+;// CONCATENATED MODULE: ./src/scripts/donation-lightbox-form.js
+const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+const donation_lightbox_form_tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
+if (isSafari) {
+ window.__forceSmoothScrollPolyfill__ = true;
+}
+
+smoothscroll_default().polyfill();
+class DonationLightboxForm {
+ constructor(DonationAmount, DonationFrequency, App) {
+ if (!this.isIframe() || document.querySelector("body").dataset.engridSubtheme !== "multistep" && document.querySelector("body").dataset.engridSubtheme !== "one-step-lightbox") return;
+ this.amount = DonationAmount;
+ this.frequency = DonationFrequency;
+ this.app = App;
+ this.ipCountry = "";
+ this.isDonation = ["donation", "premiumgift"].includes(window.pageJson.pageType);
+ this.upsellSection = null;
+ this.upsellSectionId = null;
+ console.log("DonationLightboxForm: constructor");
+
+ // Adjust Field Tooltip
+ const fieldTooltip = document.querySelectorAll(".en__field__notice");
+ if (fieldTooltip && donation_lightbox_form_tippy) {
+ fieldTooltip.forEach(tooltip => {
+ const fieldTooltipContent = tooltip.innerHTML;
+ // Replace the tooltip content with an i icon
+ tooltip.innerHTML = `
+
+
+
+ `;
+ // Move the tooltip block to the email field
+ const parentField = tooltip.closest(".en__field").querySelector(".en__field__element");
+ if (parentField) {
+ parentField.appendChild(tooltip);
+ }
+ // Add the tooltip content to the tippy instance
+ donation_lightbox_form_tippy(tooltip, {
+ content: fieldTooltipContent,
+ allowHTML: true,
+ arrow: true,
+ arrowType: "default",
+ placement: "top",
+ trigger: "click mouseenter focus",
+ interactive: true
});
- // If nothing visible (besides no-premium), hide whole container
- const hasVisibleGifts = anyVisible;
- this.endProcessingVisual(hasVisibleGifts);
- // Selection handling
- const current = document.querySelector('input[name="en__pg"]:checked');
- const currentProductId = (current === null || current === void 0 ? void 0 : current.value) || null;
- const defaultProductId = this.getConfiguredDefaultPid(frequency); // may be "0"
- // If current selection is invalid after filtering, apply default logic
- const currentIsValid = currentProductId === "0" ||
- (currentProductId ? allowedProductIds.has(currentProductId) : false);
- if (!currentIsValid) {
- if (defaultProductId &&
- defaultProductId !== "0" &&
- allowedProductIds.has(defaultProductId)) {
- this.selectByProductId(defaultProductId);
- }
- else {
- this.selectByProductId("0");
- this.clearVariantField();
- }
+ });
+ }
+
+ // Each EN Row is a Section
+ this.sections = document.querySelectorAll("form.en__component > .en__component");
+ this.currentSectionId = 0;
+ // Check if we're on the Thank You page
+ if (pageJson.pageNumber === pageJson.pageCount) {
+ this.sendMessage("status", "loaded");
+ if (this.isDonation) this.sendMessage("status", "celebrate");
+ this.sendMessage("class", "thank-you");
+ document.querySelector("body").dataset.thankYou = "true";
+ // Get Query Strings
+ const urlParams = new URLSearchParams(window.location.search);
+ if (urlParams.get("name")) {
+ let engrid = document.querySelector("#engrid");
+ if (engrid) {
+ let engridContent = engrid.innerHTML;
+ engridContent = engridContent.replace("{user_data~First Name}", urlParams.get("name"));
+ engridContent = engridContent.replace("{receipt_data~recurringFrequency}", urlParams.get("frequency"));
+ engridContent = engridContent.replace("{receipt_data~amount}", "$" + urlParams.get("amount"));
+ engrid.innerHTML = engridContent;
+ this.sendMessage("firstname", urlParams.get("name"));
}
- else {
- // Current selection is valid; only force No Premium if frequency changed and default is 0/missing
- if (this.pendingFrequencyChange &&
- (!defaultProductId || defaultProductId === "0")) {
- if (currentProductId !== "0") {
- this.selectByProductId("0");
- this.clearVariantField();
+ } else {
+ // Try to get the first name
+ const thisClass = this;
+ const pageDataUrl = location.protocol + "//" + location.host + location.pathname + "/pagedata";
+ fetch(pageDataUrl).then(function (response) {
+ return response.json();
+ }).then(function (json) {
+ if (json.hasOwnProperty("firstName") && json.firstName !== null) {
+ thisClass.sendMessage("firstname", json.firstName);
+ } else {
+ thisClass.sendMessage("firstname", "Friend");
+ }
+ }).catch(error => {
+ console.error("PageData Error:", error);
+ });
+ }
+ const bequestContainer = document.querySelector(".bequest-container");
+ const bequestBtn = document.querySelector(".bequest-btn");
+ if (bequestContainer && bequestBtn) {
+ bequestBtn.addEventListener("click", e => {
+ e.preventDefault();
+ const overlay = document.querySelector(".engrid-modal__overlay");
+ if (overlay) {
+ overlay.classList.toggle("hide");
+ if (!overlay.classList.contains("hide")) {
+ // Listen for the close event from iframe
+ window.addEventListener("message", function (event) {
+ if (event.data === "iframeSubmitted") {
+ overlay.classList.add("hide");
+ bequestContainer.classList.add("hide");
+ bequestBtn.classList.add("hide");
}
+ }, false);
}
- }
- // If container hidden (no visible gifts), select No Premium and clear hidden
- if (!hasVisibleGifts) {
- this.selectByProductId("0");
- this.clearVariantField();
- }
- this.logger.log(`Processed gifts for freq=${frequency}, amount=${amount}. Visible gifts: ${hasVisibleGifts ? "yes" : "no"}`);
- // Reset frequency-change flag after processing
- this.pendingFrequencyChange = false;
+ }
+ });
+ }
+ return false;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/digital-wallets.js
-
-
+ if (!this.sections.length) {
+ // No section or no Donation Page was found
+ this.sendMessage("error", "No sections found");
+ return false;
+ }
+ if (document.querySelector("body").dataset.engridSubtheme === "one-step-lightbox") {
+ document.querySelector(".en__submit button")?.addEventListener("click", e => {
+ e.preventDefault();
+ this.submitLogic();
+ });
+ return false;
+ }
+ console.log(this.sections);
+ if (this.isIframe()) {
+ // If iFrame
+ this.buildSectionNavigation();
+ // If Form Submission Failed
+ if (this.checkNested(EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && EngagingNetworks.require._defined.enjs.checkSubmissionFailed()) {
+ console.log("DonationLightboxForm: Submission Failed");
+ this.showHideDynamicSection(false);
+ window.setTimeout(() => {
+ if (this.validateForm()) {
+ // Front-End Validation Passed, get first Error Message
+ const error = document.querySelector("li.en__error");
+ if (error) {
+ // Check if error contains "problem processing" to send a smaller message
+ if (error.innerHTML.toLowerCase().indexOf("problem processing") > -1) {
+ this.sendMessage("error", "Sorry! There's a problem processing your donation.");
+ this.scrollToElement(document.querySelector(".en__field--ccnumber"));
+ } else {
+ this.sendMessage("error", error.textContent);
+ }
+ // Check if error contains "payment" or "account" and scroll to the right section
+ if (error.innerHTML.toLowerCase().indexOf("payment") > -1 || error.innerHTML.toLowerCase().indexOf("account") > -1) {
+ this.scrollToElement(document.querySelector(".en__field--ccnumber"));
+ } else if (error.innerHTML.toLowerCase().indexOf("routing") > -1 || error.innerHTML.toLowerCase().indexOf("account") > -1 || error.innerHTML.toLowerCase().indexOf("bank") > -1) {
+ this.scrollToElement(document.querySelector(".en__field--bankRoutingNumber"));
+ }
+ }
+ }
+ }, 100);
+ }
+ document.querySelectorAll("form.en__component input.en__field__input").forEach(e => {
+ e.addEventListener("focus", event => {
+ // Run after 50ms - We need this or else some browsers will disregard the scroll due to the focus event
+ const nextSectionId = Number(this.getSectionId(e));
+ const currentSectionId = Number(this.currentSectionId);
+ console.log("Focus on", nextSectionId, currentSectionId);
+ setTimeout(() => {
+ const focusIsOnNextSection = nextSectionId === currentSectionId + 1 || nextSectionId > currentSectionId + 1 && !this.isVisible(this.sections[currentSectionId + 1]);
-class DigitalWallets {
- constructor() {
- this.logger = new logger_EngridLogger("DigitalWallets", "#fff", "#333", "π");
- this._form = en_form_EnForm.getInstance();
- //digital wallets not enabled.
- if (!document.getElementById("en__digitalWallet")) {
- engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
- engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "false");
- engrid_ENGrid.setBodyData("payment-type-option-google-pay", "false");
- engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
- engrid_ENGrid.setBodyData("payment-type-option-venmo", "false");
- engrid_ENGrid.setBodyData("payment-type-option-daf", "false");
- this.logger.log("No digital wallet container found, skipping digital wallet setup.");
- return;
- }
- // Add giveBySelect classes to the separate wallet containers
- // and hide them on load.
- const stripeButtons = document.getElementById("en__digitalWallet__stripeButtons__container");
- if (stripeButtons) {
- stripeButtons.classList.add("giveBySelect-stripedigitalwallet");
- stripeButtons.classList.add("showif-stripedigitalwallet-selected");
- // stripeButtons.style.display = "none";
- }
- const paypalTouchButtons = document.getElementById("en__digitalWallet__paypalTouch__container");
- if (paypalTouchButtons) {
- paypalTouchButtons.classList.add("giveBySelect-paypaltouch");
- paypalTouchButtons.classList.add("showif-paypaltouch-selected");
- // paypalTouchButtons.style.display = "none";
- }
- const donorAdvisedFundButtonContainer = document.getElementById("en__digitalWallet__chariot__container");
- if (donorAdvisedFundButtonContainer) {
- donorAdvisedFundButtonContainer.classList.add("giveBySelect-daf");
- donorAdvisedFundButtonContainer.classList.add("showif-daf-selected");
- }
- /**
- * Check for presence of elements that indicated Stripe digital wallets
- * (Google Pay, Apple Pay) have loaded, and add functionality for them.
- * If they haven't yet loaded, set up a Mutation Observer to check for
- * when they do.
- */
- if (document.querySelector("#en__digitalWallet__stripeButtons__container > *")) {
- this.addStripeDigitalWallets();
- }
- else {
- engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "false");
- engrid_ENGrid.setBodyData("payment-type-option-google-pay", "false");
- engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
- const stripeContainer = document.getElementById("en__digitalWallet__stripeButtons__container");
- if (stripeContainer) {
- this.checkForWalletsBeingAdded(stripeContainer, "stripe");
+ // if (focusIsOnNextSection && this.validateForm(currentSectionId)) {
+ if (focusIsOnNextSection) {
+ // // Only scroll if the current section doesn't have radio elements
+ // const radioElement =
+ // this.sections[currentSectionId].querySelector(
+ // ".en__field--radio"
+ // );
+ // if (!radioElement) this.scrollToElement(e);
+ return;
}
- // If the default payment type is Stripe Digital Wallet and the page doesnt support it, set the payment type to Card
- const paymentType = engrid_ENGrid.getPaymentType();
- if (paymentType.toLowerCase() === "stripedigitalwallet") {
- engrid_ENGrid.setPaymentType("card");
+ }, 50);
+ // If the field is the credit card number, remove the error class from the parent
+ if ("id" in e && e.id === "en__field_transaction_ccnumber") {
+ const parent = e.closest(".en__field");
+ if (parent) {
+ parent.classList.remove("has-error");
}
- }
- /**
- * Check for presence of elements that indicated Paypal digital wallets
- * (Paypal One Touch, Venmo, Etc) have loaded, and add functionality for them.
- * If they haven't yet loaded, set up a Mutation Observer to check for
- * when they do.
- */
- if (document.querySelector("#en__digitalWallet__paypalTouch__container > *")) {
- this.addPaypalTouchDigitalWallets();
- }
- else {
- engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
- engrid_ENGrid.setBodyData("payment-type-option-venmo", "false");
- const paypalContainer = document.getElementById("en__digitalWallet__paypalTouch__container");
- if (paypalContainer) {
- this.checkForWalletsBeingAdded(paypalContainer, "paypalTouch");
+ }
+ });
+ });
+ // For TAB navigation, ensure the script will scroll to the focused element's section. So we will watch for the keydown event on the document.
+
+ document.addEventListener("keydown", event => {
+ if (event.keyCode === 9) {
+ const focusedElement = document.activeElement;
+ // If the focused element is not inside the form, return
+ if (!focusedElement.closest("form.en__component")) return;
+ console.log("Tabbed to", focusedElement);
+ const nextSectionId = Number(this.getSectionId(focusedElement));
+ const currentSectionId = Number(this.currentSectionId);
+ if (currentSectionId !== nextSectionId) {
+ event.preventDefault();
+ if (this.validateForm(currentSectionId)) {
+ this.scrollToSection(nextSectionId, currentSectionId);
}
+ }
}
- /**
- * Check for presence of elements that indicate DAF is present, and add functionality for it.
- * If it hasn't loaded yet, set up a Mutation Observer to check for when it does.
- */
- if (document.querySelector("#en__digitalWallet__chariot__container > *")) {
- this.addDAF();
- }
- else {
- engrid_ENGrid.setBodyData("payment-type-option-daf", "false");
- const donorAdvisedFundButtonContainer = document.getElementById("en__digitalWallet__chariot__container");
- if (donorAdvisedFundButtonContainer) {
- this.checkForWalletsBeingAdded(donorAdvisedFundButtonContainer, "daf");
+ });
+ // Map the enter key to the next button
+ document.querySelectorAll("form.en__component input.en__field__input").forEach(e => {
+ e.addEventListener("keydown", event => {
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ const sectionId = Number(this.getSectionId(e));
+ if (this.validateForm(sectionId)) {
+ this.scrollToSection(sectionId + 1, sectionId);
}
- }
- }
- addStripeDigitalWallets() {
- this.logger.log("Stripe Digital Wallets detected");
- this.addOptionToPaymentTypeField("stripedigitalwallet", "GooglePay / ApplePay");
- // ENGrid.setBodyData(
- // "payment-type-option-apple-pay",
- // DigitalWallets.isApplePayAvailable.toString()
- // );
- // ENGrid.setBodyData(
- // "payment-type-option-google-pay",
- // !DigitalWallets.isApplePayAvailable.toString()
- // );
- // TODO: Change to trustworthy detection of Google Pay & Apple Pay availability
- engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "true");
- engrid_ENGrid.setBodyData("payment-type-option-google-pay", "true");
- engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "true");
- this.addStripeDigitalWalletListener()
- ? this.logger.log("Stripe Digital Wallet listener added successfully")
- : this.logger.log("Failed to add Stripe Digital Wallet listener");
+ }
+ });
+ });
}
- addPaypalTouchDigitalWallets() {
- this.logger.log("Paypal Touch Digital Wallets detected");
- this.addOptionToPaymentTypeField("paypaltouch", "Paypal / Venmo");
- engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "true");
- engrid_ENGrid.setBodyData("payment-type-option-venmo", "true");
- this.addPaypalOneTouchListener()
- ? this.logger.log("Paypal Touch listener added successfully")
- : this.logger.log("Failed to add Paypal Touch listener");
+ let paymentOpts = document.querySelector(".payment-options");
+ if (paymentOpts) {
+ this.clickPaymentOptions(paymentOpts);
}
- addDAF() {
- this.logger.log("DAF Digital Wallet detected");
- this.addOptionToPaymentTypeField("daf", "Donor Advised Fund");
- engrid_ENGrid.setBodyData("payment-type-option-daf", "true");
- this.addDAFListener()
- ? this.logger.log("DAF listener added successfully")
- : this.logger.log("Failed to add DAF listener");
+ this.addTabIndexToLabels();
+ this.putArrowUpSVG();
+ this.bounceArrow(this.frequency.getInstance().frequency);
+ this.addEvents();
+ this.changeSubmitButton();
+ this.hideAnnualFrequency();
+ this.sendMessage("status", "loaded");
+ // Check if theres a color value in the url
+ const urlParams = new URLSearchParams(window.location.search);
+ if (urlParams.get("color")) {
+ document.body.style.setProperty("--color_primary", urlParams.get("color"));
}
- addOptionToPaymentTypeField(value, label) {
- const paymentTypeField = document.querySelector('[name="transaction.paymenttype"]');
- if (paymentTypeField &&
- !paymentTypeField.querySelector(`[value=${value}]`)) {
- const walletOption = document.createElement("option");
- walletOption.value = value;
- walletOption.innerText = label;
- paymentTypeField.appendChild(walletOption);
- }
- // If this payment type is set as the default on GiveBySelect, set the payment type to this value
- // We need to do this here because the digital wallets are sometimes slow to load
- const giveBySelect = document.querySelector('input[name="transaction.giveBySelect"][value="' + value + '"]');
- if (giveBySelect && giveBySelect.dataset.default === "true") {
- giveBySelect.checked = true;
- const event = new Event("change", {
- bubbles: true,
- cancelable: true,
- });
- giveBySelect.dispatchEvent(event);
+ window.addEventListener("message", this.receiveMessage.bind(this), false);
+ this.sendMessage("isMobile");
+ this.showHideDynamicSection(false);
+ App.watchForError(() => {
+ this.sendMessage("status", "loaded");
+ if (this.validateForm(false, false)) {
+ // Front-End Validation Passed, get first Error Message
+ const error = document.querySelector("li.en__error");
+ if (error) {
+ // Check if error contains "processing" to send a smaller message
+ if (error.innerHTML.toLowerCase().indexOf("processing") > -1) {
+ this.sendMessage("error", "Sorry! There's a problem processing your donation.");
+ this.scrollToElement(document.querySelector(".en__field--ccnumber"));
+ } else if (error.innerHTML.toLowerCase().indexOf("captcha") > -1) {
+ console.error("Captcha Error");
+ this.scrollToElement(document.querySelector(".en__captcha"));
+ } else {
+ this.sendMessage("error", error.textContent);
+ }
+ // Check if error contains "payment" or "account" and scroll to the right section
+ if (error.innerHTML.toLowerCase().indexOf("payment") > -1 || error.innerHTML.toLowerCase().indexOf("account") > -1 || error.innerHTML.toLowerCase().indexOf("card") > -1) {
+ this.scrollToElement(document.querySelector(".en__field--ccnumber"));
+ }
}
+ }
+ });
+ // Custom class and label for the Stripe Digital Wallets Payment Method
+ const digitalWallets = document.querySelector(".give-by-select .stripedigitalwallet");
+ if (digitalWallets) {
+ const digitalWalletsLabel = digitalWallets.querySelector("span");
+ if (digitalWalletsLabel) {
+ const isApplePay = window.hasOwnProperty("ApplePaySession");
+ digitalWalletsLabel.innerHTML = isApplePay ? "APPLE PAY" : "GOOGLE PAY";
+ digitalWallets.classList.add(isApplePay ? "apple-pay" : "google-pay");
+ }
}
- checkForWalletsBeingAdded(node, walletType) {
- const callback = (mutationList, observer) => {
- for (const mutation of mutationList) {
- //Once a child node has been added, set up the appropriate digital wallet
- if (mutation.type === "childList" && mutation.addedNodes.length) {
- if (walletType === "stripe") {
- this.addStripeDigitalWallets();
- }
- else if (walletType === "paypalTouch") {
- this.addPaypalTouchDigitalWallets();
- }
- else if (walletType === "daf") {
- this.addDAF();
+ }
+ // Send iframe message to parent
+ sendMessage(key, value) {
+ const message = {
+ key: key,
+ value: value
+ };
+ window.parent.postMessage(message, "*");
+ }
+ // Receive iframe message from parent
+ receiveMessage(event) {
+ if (event.data.key === "isMobile" && event.data.value === true) {
+ document.body.classList.add("is-mobile");
+ }
+ if (event.data.key === "isMobile" && event.data.value === false) {
+ document.body.classList.remove("is-mobile");
+ }
+ }
+
+ // Check if is iFrame
+ isIframe() {
+ return window.self !== window.top;
+ }
+ submitLogic() {
+ if (this.isDonation) {
+ console.log("DonationLightboxForm: submitLogic - Donation");
+ // Send Basic User Data to Parent
+ this.sendMessage("donationinfo", JSON.stringify({
+ name: document.querySelector("#en__field_supporter_firstName").value,
+ amount: this.getDonationTotal(),
+ frequency: this.frequency.getInstance().frequency
+ }));
+ // Only shows cortain if payment is not paypal
+ const paymentType = document.querySelector("#en__field_transaction_paymenttype").value;
+ if (paymentType.toLowerCase() != "paypal") {
+ if (document.querySelector("body").dataset.engridSubtheme === "one-step-lightbox") {
+ const waitForUpsellModal = () => {
+ const upsellModal = document.querySelector("#en__upsellModal");
+ if (upsellModal) {
+ return Promise.resolve(upsellModal);
+ }
+ return new Promise(resolve => {
+ const observer = new MutationObserver(mutations => {
+ for (const mutation of mutations) {
+ for (const node of mutation.addedNodes) {
+ if (!(node instanceof HTMLElement)) continue;
+ const modal = node.id === "en__upsellModal" ? node : node.querySelector?.("#en__upsellModal");
+ if (modal) {
+ observer.disconnect();
+ resolve(modal);
+ return;
}
- //Disconnect observer and break loop to prevent multiple additions
- observer.disconnect();
- break;
+ }
}
- }
- };
- const observer = new MutationObserver(callback);
- observer.observe(node, { childList: true, subtree: true });
+ });
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true
+ });
+ });
+ };
+ waitForUpsellModal().then(modal => {
+ document.querySelector("#en__upsellModal__yes button")?.addEventListener("click", () => {
+ this.sendMessage("status", "loading");
+ });
+ document.querySelector("#en__upsellModal__no button")?.addEventListener("click", () => {
+ this.sendMessage("status", "loading");
+ });
+ });
+ } else {
+ this.sendMessage("status", "loading");
+ }
+ } else {
+ // If Paypal, submit the form on a new tab
+ const thisClass = this;
+ document.addEventListener("visibilitychange", function () {
+ if (document.visibilityState === "visible") {
+ thisClass.sendMessage("status", "submitted");
+ } else {
+ thisClass.sendMessage("status", "loading");
+ }
+ });
+ document.querySelector("form.en__component").target = "_blank";
+ }
+ if (this.checkNested(window.EngagingNetworks, "require", "_defined", "enDefaults", "validation", "_getSubmitPromise")) {
+ console.log("DonationLightboxForm: Using EN Validation Promise");
+ window.EngagingNetworks.require._defined.enDefaults.validation._getSubmitPromise().then(function () {
+ document.querySelector("form.en__component").submit();
+ });
+ } else {
+ console.log("DonationLightboxForm: Using standard submit");
+ document.querySelector("form.en__component").requestSubmit();
+ }
+ } else {
+ console.log("DonationLightboxForm: submitLogic - Non Donation");
+ this.sendMessage("status", "loading");
+ document.querySelector("form.en__component").requestSubmit();
}
- addPaypalOneTouchListener() {
- var _a, _b, _c, _d, _e;
- const paypalTouch = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enPaypalTouch) === null || _d === void 0 ? void 0 : _d.paypalTouch;
- if (!((_e = paypalTouch === null || paypalTouch === void 0 ? void 0 : paypalTouch.library) === null || _e === void 0 ? void 0 : _e.Buttons)) {
- this.logger.log("Paypal Touch library not found, cannot add listener");
- return false;
+ }
+ // Build Section Navigation
+ buildSectionNavigation() {
+ console.log("DonationLightboxForm: buildSectionNavigation");
+ this.sections.forEach((section, key) => {
+ section.dataset.sectionId = key;
+ const isUpsellSection = section.querySelector(".upsell-buttons");
+ if (isUpsellSection) {
+ this.upsellSection = section;
+ this.upsellSectionId = key;
+ section.dataset.upsellSection = true;
+ this.replaceUpsellMergeTags();
+ }
+ const sectionNavigation = document.createElement("div");
+ sectionNavigation.classList.add("section-navigation");
+ const sectionCount = document.createElement("div");
+ sectionCount.classList.add("section-count");
+ const sectionTotal = this.sections.length;
+ if (sectionTotal > 1) {
+ if (key == 0) {
+ sectionNavigation.innerHTML = `
+
+ Donate Today
+
+
+
+
+ `;
+ } else if (key == this.sections.length - 1) {
+ // Add Last Section Data Attribute
+ section.dataset.lastSection = true;
+ sectionNavigation.innerHTML = `
+
+
+
+
+
+
+ Give Now
+
+ `;
+ } else if (key == this.upsellSectionId) {
+ // Add only the back button to the upsell section
+ sectionNavigation.innerHTML = `
+
+
+
+
+
+ `;
+ } else {
+ sectionNavigation.innerHTML = `
+
+
+
+
+
+
+ Continue
+
+
+
+
+ `;
+ }
+ if (key + 1 < sectionTotal) {
+ sectionCount.innerHTML = `
+ ${key + 1} of
+ ${sectionTotal}
+ `;
}
- const buttons = paypalTouch.library.Buttons.bind(paypalTouch.library);
- paypalTouch.library.Buttons = (o) => buttons(Object.assign(Object.assign({}, o), { onClick: (d, a) => (this._form.dispatchIntentSubmit(),
- o.onClick && o.onClick(d, a)) }));
- paypalTouch.unloadButton && paypalTouch.unloadButton();
- paypalTouch.loadButton && paypalTouch.loadButton();
- return true;
- }
- addStripeDigitalWalletListener() {
- var _a, _b, _c, _d, _e, _f;
- return !!((_f = (_e = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enStripeButtons) === null || _d === void 0 ? void 0 : _d.stripeButtons) === null || _e === void 0 ? void 0 : _e.paymentRequest) === null || _f === void 0 ? void 0 : _f.on("paymentmethod", this._form.dispatchIntentSubmit.bind(this._form)));
+ } else {
+ // Single Section Pages
+ const submitButtonLabel = document.querySelector(".en__submit button")?.innerText || "Submit";
+ sectionNavigation.innerHTML = `
+
+ ${submitButtonLabel}
+
+ `;
+ }
+ sectionNavigation.querySelector(".section-navigation__previous")?.addEventListener("click", e => {
+ e.preventDefault();
+ this.scrollToSection(key - 1, key);
+ });
+ sectionNavigation.querySelector(".section-navigation__next")?.addEventListener("click", e => {
+ e.preventDefault();
+ if (this.validateForm(key)) {
+ this.scrollToSection(key + 1, key);
+ }
+ });
+ sectionNavigation.querySelector(".section-navigation__submit")?.addEventListener("click", e => {
+ e.preventDefault();
+ // Validate the entire form again
+ if (this.validateForm(false, this.isDonation)) {
+ this.submitLogic();
+ }
+ });
+ section.querySelector(".en__component").append(sectionNavigation);
+ section.querySelector(".en__component").append(sectionCount);
+ });
+ const digitalWallets = document.querySelector(".digital-wallets-wrapper");
+ if (digitalWallets) {
+ // Create a back link for digital wallets
+ const backLink = document.createElement("a");
+ backLink.classList.add("back-link");
+ backLink.innerHTML = `back`;
+ backLink.href = "#";
+ backLink.addEventListener("click", e => {
+ e.preventDefault();
+ this.scrollToSection(this.getSectionId(digitalWallets) - 1, 0);
+ });
+ digitalWallets.prepend(backLink);
}
- addDAFListener() {
- const chariotButton = document.getElementById("chariot-button");
- chariotButton === null || chariotButton === void 0 ? void 0 : chariotButton.addEventListener("click", this._form.dispatchIntentSubmit.bind(this._form));
- return !!chariotButton;
+ }
+ // Update section-count based on visible sections
+ updateSectionCount() {
+ console.log("DonationLightboxForm: updateSectionCount");
+ const visibleSections = Array.from(this.sections).filter(section => this.isVisible(section));
+ visibleSections.forEach((section, key) => {
+ const sectionCount = section.querySelector(".section-count");
+ const sectionCurrent = section.querySelector(".section-count__current");
+ const sectionTotal = section.querySelector(".section-count__total");
+ if (sectionCount && sectionCurrent && sectionTotal) {
+ sectionCurrent.innerHTML = key + 1;
+ sectionTotal.innerHTML = visibleSections.length;
+ }
+ });
+ }
+ // Scroll to a section
+ scrollToSection(sectionId, fromSectionId) {
+ console.log("DonationLightboxForm: scrollToSection", sectionId);
+ const section = document.querySelector(`[data-section-id="${sectionId}"]`);
+ // Check if we're scrolling to an invisible section
+ if (section && !this.isVisible(section)) {
+ console.log("DonationLightboxForm: scrollToSection: Section is not visible");
+ // If we're scrolling to a section that's not visible, check fromSectionId to see if we're scrolling left or right
+ if (fromSectionId > sectionId) {
+ // If we're scrolling left, scroll to the previous section
+ this.scrollToSection(sectionId - 1, sectionId);
+ } else {
+ // If we're scrolling right, scroll to the next section
+ this.scrollToSection(sectionId + 1, sectionId);
+ }
+ return;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/mobile-cta.js
-// This component adds a floating CTA button to the page, which can be used to scroll to the top of the form
-class MobileCTA {
- constructor() {
- var _a;
- // Initialize options with the MobileCTA value or false
- this.options = (_a = engrid_ENGrid.getOption("MobileCTA")) !== null && _a !== void 0 ? _a : false;
- this.buttonLabel = "";
- // Return early if the options object is falsy or the current page type is not in the options.pages array
- if (!this.options || engrid_ENGrid.getPageNumber() !== 1) {
- return;
- }
- const labelForPageType = this.options.find((option) => option.pageType === engrid_ENGrid.getPageType());
- if (!labelForPageType)
- return;
- // Set the button label to the window.mobileCTAButtonLabel value or the label for the current page type
- this.buttonLabel = window.mobileCTAButtonLabel || labelForPageType.label;
- this.renderButton();
- this.addEventListeners();
- }
- renderButton() {
- const engridDiv = document.querySelector("#engrid");
- const formBlock = document.querySelector(".body-main .en__component--widgetblock:first-child, .en__component--formblock");
- // Return early if engridDiv or formBlock are not found
- if (!engridDiv || !formBlock)
- return;
- const buttonContainer = document.createElement("div");
- const button = document.createElement("button");
- // Add necessary classes and set the initial display style for the button container
- buttonContainer.classList.add("engrid-mobile-cta-container", "hide-cta");
- button.classList.add("primary");
- // Set the button's innerHTML and add a click event listener
- button.innerHTML =
- this.buttonLabel +
- ' ';
- button.addEventListener("click", () => {
- formBlock.scrollIntoView({ behavior: "smooth" });
- });
- // Append the button to the button container and the container to engridDiv
- buttonContainer.appendChild(button);
- engridDiv.appendChild(buttonContainer);
+ // If scrolling to the first section, remove upsold attribute and reset upsell section
+ if (sectionId == 0 && this.upsellSection) {
+ this.upsellSection.removeAttribute("data-upsold");
+ this.refreshUpsellSection();
}
- addEventListeners() {
- const bodyMain = document.querySelector(".body-main");
- // Return early if formBlock is not found
- if (!bodyMain)
- return;
- // Define a function to toggle the button visibility based on the bodyMain position
- const toggleButton = () => {
- if (bodyMain.getBoundingClientRect().top <= window.innerHeight - 100) {
- this.hideButton();
- }
- else {
- this.showButton();
- }
- };
- toggleButton();
- // Add event listeners for load, resize, and scroll events to toggle the button visibility
- window.addEventListener("load", toggleButton);
- window.addEventListener("resize", toggleButton);
- window.addEventListener("scroll", toggleButton);
+ if (this.sections[sectionId]) {
+ console.log(section);
+ this.currentSectionId = sectionId;
+ console.log("Changed current section ID to", sectionId);
+ this.sections[sectionId].scrollIntoView({
+ behavior: "smooth"
+ // block: "start",
+ // inline: "center",
+ });
}
- // Hide the button by setting the container's display style to "none"
- hideButton() {
- const buttonContainer = document.querySelector(".engrid-mobile-cta-container");
- if (buttonContainer)
- buttonContainer.classList.add("hide-cta");
+ }
+ // Scroll to an element's section
+ scrollToElement(element) {
+ if (element) {
+ const sectionId = this.getSectionId(element);
+ if (sectionId) {
+ const oldSectionId = this.currentSectionId;
+ this.currentSectionId = sectionId;
+ console.log("Changed current section ID to", sectionId);
+ this.scrollToSection(sectionId, oldSectionId);
+ }
}
- // Show the button by setting the container's display style to "block"
- showButton() {
- const buttonContainer = document.querySelector(".engrid-mobile-cta-container");
- if (buttonContainer)
- buttonContainer.classList.remove("hide-cta");
+ }
+ // Get Element's section id
+ getSectionId(element) {
+ if (element) {
+ return element.closest("[data-section-id]").dataset.sectionId;
}
-}
+ return false;
+ }
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/live-frequency.js
-// This script creates merge tags: [[frequency]], [[Frequency]], or [[FREQUENCY]]
-// that gets replaced with the donation frequency
-// and can be used on any Code Block, Text Block, or Form Block
+ // Validate the form
+ // checkCard was added to avoid checking the card if there was a server-side error (the card would be empty)
+ validateForm(sectionId = false, checkCard = true) {
+ const form = document.querySelector("form.en__component");
-class LiveFrequency {
- constructor() {
- this.logger = new logger_EngridLogger("LiveFrequency", "#00ff00", "#000000", "π§Ύ");
- this.elementsFound = false;
- this._amount = DonationAmount.getInstance();
- this._frequency = DonationFrequency.getInstance();
- this.searchElements();
- if (!this.shouldRun())
- return;
- this.updateFrequency();
- this.addEventListeners();
- }
- searchElements() {
- const enElements = document.querySelectorAll(`
- .en__component--copyblock,
- .en__component--codeblock,
- .en__field label,
- .en__submit
- `);
- if (enElements.length > 0) {
- const pattern = /\[\[(frequency)\]\]/gi;
- let totalFound = 0;
- enElements.forEach((item) => {
- const match = item.innerHTML.match(pattern);
- if (item instanceof HTMLElement && match) {
- this.elementsFound = true;
- match.forEach((matchedSubstring) => {
- totalFound++;
- this.replaceMergeTags(matchedSubstring, item);
- });
- }
- });
- if (totalFound > 0) {
- this.logger.log(`Found ${totalFound} merge tag${totalFound > 1 ? "s" : ""} in the page.`);
- }
- }
- }
- shouldRun() {
- if (!this.elementsFound) {
- this.logger.log("No merge tags found. Skipping.");
- return false;
+ // Validate Frequency
+ const frequency = form.querySelector("[name='transaction.recurrfreq']:checked");
+ const frequencyBlock = form.querySelector(".en__field--recurrfreq");
+ const frequencySection = this.getSectionId(frequencyBlock);
+ if (this.isDonation) {
+ if (sectionId === false || sectionId == frequencySection) {
+ if (!frequency || !frequency.value) {
+ this.scrollToElement(form.querySelector("[name='transaction.recurrfreq']:checked"));
+ this.sendMessage("error", "Please select a frequency");
+ if (frequencyBlock) {
+ frequencyBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (frequencyBlock) {
+ frequencyBlock.classList.remove("has-error");
+ }
}
- return true;
- }
- addEventListeners() {
- this._amount.onAmountChange.subscribe(() => {
- setTimeout(() => {
- this.updateFrequency();
- }, 10);
- });
- this._frequency.onFrequencyChange.subscribe(() => {
- setTimeout(() => {
- this.searchElements();
- this.updateFrequency();
- }, 10);
- });
- }
- updateFrequency() {
- const frequency = this._frequency.frequency === "onetime"
- ? "one-time"
- : this._frequency.frequency;
- const elemenst = document.querySelectorAll(".engrid-frequency");
- elemenst.forEach((item) => {
- if (item.classList.contains("engrid-frequency--lowercase")) {
- item.innerHTML = frequency.toLowerCase();
- }
- else if (item.classList.contains("engrid-frequency--capitalized")) {
- item.innerHTML = frequency.charAt(0).toUpperCase() + frequency.slice(1);
- }
- else if (item.classList.contains("engrid-frequency--uppercase")) {
- item.innerHTML = frequency.toUpperCase();
+ }
+ // Validate Amount
+ const amount = this.getDonationTotal();
+ const amountBlock = form.querySelector(".en__field--donationAmt");
+ const amountSection = this.getSectionId(amountBlock);
+ if (sectionId === false || sectionId == amountSection) {
+ if (!amount || amount <= 0) {
+ this.scrollToElement(amountBlock);
+ this.sendMessage("error", "Please enter a valid amount");
+ if (amountBlock) {
+ amountBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (amount < 10) {
+ this.sendMessage("error", "Amount must be at least $10 - Contact us for assistance");
+ if (amountBlock) {
+ amountBlock.classList.add("has-error");
}
- else {
- item.innerHTML = frequency;
+ return false;
+ }
+ const maxAmount = window.EngridOptions?.MaxAmount ?? 30000;
+ if (amount > maxAmount) {
+ this.sendMessage("error", `Amount must be less than $${maxAmount.toLocaleString()} - Contact us for assistance`);
+ if (amountBlock) {
+ amountBlock.classList.add("has-error");
}
- });
- }
- replaceMergeTags(tag, element) {
- const frequency = this._frequency.frequency === "onetime"
- ? "one-time"
- : this._frequency.frequency;
- const frequencyElement = document.createElement("span");
- frequencyElement.classList.add("engrid-frequency");
- frequencyElement.innerHTML = frequency;
- switch (tag) {
- case "[[frequency]]":
- frequencyElement.classList.add("engrid-frequency--lowercase");
- frequencyElement.innerHTML = frequencyElement.innerHTML.toLowerCase();
- element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
- break;
- case "[[Frequency]]":
- frequencyElement.classList.add("engrid-frequency--capitalized");
- frequencyElement.innerHTML =
- frequencyElement.innerHTML.charAt(0).toUpperCase() +
- frequencyElement.innerHTML.slice(1);
- element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
- break;
- case "[[FREQUENCY]]":
- frequencyElement.classList.add("engrid-frequency--uppercase");
- frequencyElement.innerHTML = frequencyElement.innerHTML.toUpperCase();
- element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
- break;
- }
- }
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/universal-opt-in.js
-/**
- * This class will add event listeners to every yes/no radio button or checkbox
- * inside a universal opt-in element (any form block with the CSS class universal-opt-in). When the user clicks on a radio/checkbox
- * button, we will search for every other radio/checkbox button inside the same
- * universal opt-in element and mirror the user's selection.
- * If instead of universal-opt-in you use universal-opt-in_null, the class will
- * not mirror the user's selection when a radio "No" option is selected. Instead,
- * it will unset all other radio buttons.
- */
-
-class UniversalOptIn {
- constructor() {
- this.logger = new logger_EngridLogger("UniversalOptIn", "#f0f0f0", "#d2691e", "πͺ");
- this._elements = document.querySelectorAll(".universal-opt-in, .universal-opt-in_null");
- if (!this.shouldRun())
- return;
- this.addEventListeners();
- }
- shouldRun() {
- if (this._elements.length === 0) {
- this.logger.log("No universal opt-in elements found. Skipping.");
return false;
+ }
+ if (amountBlock) {
+ amountBlock.classList.remove("has-error");
+ }
}
- this.logger.log(`Found ${this._elements.length} universal opt-in elements.`);
- return true;
- }
- addEventListeners() {
- this._elements.forEach((element) => {
- const yesNoElements = element.querySelectorAll(".en__field__input--radio, .en__field__input--checkbox");
- if (yesNoElements.length > 0) {
- yesNoElements.forEach((yesNoElement) => {
- yesNoElement.addEventListener("click", () => {
- if (yesNoElement instanceof HTMLInputElement &&
- yesNoElement.getAttribute("type") === "checkbox") {
- const yesNoValue = yesNoElement.checked;
- if (yesNoValue) {
- this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is checked");
- yesNoElements.forEach((yesNoElement2) => {
- if (yesNoElement === yesNoElement2)
- return;
- if (yesNoElement2 instanceof HTMLInputElement &&
- yesNoElement2.getAttribute("type") === "checkbox")
- yesNoElement2.checked = true;
- });
- }
- else {
- this.logger.log("Yes/No " +
- yesNoElement.getAttribute("type") +
- " is unchecked");
- yesNoElements.forEach((yesNoElement2) => {
- if (yesNoElement === yesNoElement2)
- return;
- if (yesNoElement2 instanceof HTMLInputElement &&
- yesNoElement2.getAttribute("type") === "checkbox")
- yesNoElement2.checked = false;
- });
- }
- return;
- }
- const yesNoValue = yesNoElement.getAttribute("value");
- if (yesNoValue === "Y") {
- this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is checked");
- yesNoElements.forEach((yesNoElement2) => {
- const fieldName = yesNoElement2.getAttribute("name");
- const clickedFieldName = yesNoElement.getAttribute("name");
- if (!fieldName || fieldName === clickedFieldName)
- return;
- engrid_ENGrid.setFieldValue(fieldName, "Y");
- });
- }
- else {
- this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is unchecked");
- yesNoElements.forEach((yesNoElement2) => {
- const fieldName = yesNoElement2.getAttribute("name");
- const clickedFieldName = yesNoElement.getAttribute("name");
- if (!fieldName || fieldName === clickedFieldName)
- return;
- if (element.classList.contains("universal-opt-in")) {
- engrid_ENGrid.setFieldValue(fieldName, "N");
- }
- else {
- yesNoElement2.checked = false;
- }
- });
- }
- });
- });
+ }
+ // Validate Payment Method
+ const paymentType = form.querySelector("#en__field_transaction_paymenttype");
+ const ccnumber = form.querySelector("#en__field_transaction_ccnumber");
+ const ccnumberBlock = form.querySelector(".en__field--ccnumber");
+ const ccnumberSection = this.getSectionId(ccnumberBlock);
+ const isDigitalWalletPayment = ["paypal", "paypaltouch", "stripedigitalwallet", "daf"].includes(paymentType.value.toLowerCase());
+ const isBankPayment = paymentType.value.toLowerCase() === "ach";
+ console.log("DonationLightboxForm: validateForm", ccnumberBlock, ccnumberSection);
+ if (!isDigitalWalletPayment && !isBankPayment && (sectionId === false || sectionId == ccnumberSection) && checkCard) {
+ if (!paymentType || !paymentType.value) {
+ this.scrollToElement(paymentType);
+ this.sendMessage("error", "Please add your credit card information");
+ if (ccnumberBlock) {
+ ccnumberBlock.classList.add("has-error");
+ }
+ return false;
+ }
+ const ccValid = ccnumber instanceof HTMLInputElement ? !!ccnumber.value : ccnumber.classList.contains("vgs-collect-container__valid");
+ if (!ccValid) {
+ this.scrollToElement(ccnumber);
+ this.sendMessage("error", "Please enter a valid credit card number");
+ if (ccnumberBlock) {
+ ccnumberBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (ccnumberBlock) {
+ ccnumberBlock.classList.remove("has-error");
+ }
+ }
+ const ccexpire = form.querySelector("#en__field_transaction_ccexpire");
+ const ccexpireBlock = form.querySelector(".en__field--ccexpire");
+ let ccexpireValid = ccexpire ? ccexpire.classList.contains("vgs-collect-container__valid") : false;
+ if (!ccexpireValid) {
+ this.scrollToElement(ccexpire);
+ this.sendMessage("error", "Please enter a valid expiration date");
+ if (ccexpireBlock) {
+ ccexpireBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (ccexpireBlock) {
+ ccexpireBlock.classList.remove("has-error");
+ }
+ }
+ const cvv = form.querySelector("#en__field_transaction_ccvv");
+ const cvvBlock = form.querySelector(".en__field--ccvv");
+ const cvvValid = cvv instanceof HTMLInputElement ? !!cvv.value : cvv.classList.contains("vgs-collect-container__valid");
+ if (!cvvValid) {
+ this.scrollToElement(cvv);
+ this.sendMessage("error", "Please enter a valid CVV");
+ if (cvvBlock) {
+ cvvBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (cvvBlock) {
+ cvvBlock.classList.remove("has-error");
+ }
+ }
+ }
+ // Validate Bank Details
+ if (paymentType && paymentType.value.toLowerCase() === "ach") {
+ const routingNumber = form.querySelector("#en__field_supporter_bankRoutingNumber");
+ if (!routingNumber) return;
+ const bankSection = this.getSectionId(routingNumber);
+ if (sectionId === false || sectionId == bankSection) {
+ // All form fields from this section are mandatory if the payment type is ACH
+ const mandatoryFields = this.sections[bankSection].querySelectorAll("input:not([type='hidden'])");
+ let hasError = false;
+ mandatoryFields.forEach(field => {
+ if (hasError) {
+ return;
+ }
+ const fieldElement = field;
+ const fieldLabel = field.closest(".en__field").querySelector(".en__field__label");
+ if (!fieldElement.value) {
+ this.scrollToElement(fieldElement);
+ this.sendMessage("error", "Please enter " + fieldLabel.textContent);
+ fieldElement.closest(".en__field").classList.add("has-error");
+ hasError = true;
+ return false;
+ } else if (fieldElement.type === "checkbox" && !fieldElement.checked) {
+ this.scrollToElement(fieldElement);
+ this.sendMessage("error", "Please check the agreement checkbox");
+ fieldElement.closest(".en__field").classList.add("has-error");
+ hasError = true;
+ return false;
+ } else {
+ fieldElement.closest(".en__field").classList.remove("has-error");
}
- });
+ });
+ if (hasError) {
+ return false;
+ }
+ }
+ }
}
-}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/stripe-financial-connections.js
-/**
- * This component improves EN's implementation of Stripe Financial Connections.
- * Enhancements:
- * - When the modal is closed, it re-enables the submit button.
- */
+ // Validate Recaptcha
+ const recaptchaResponse = form.querySelector("#g-recaptcha-response");
+ const recapchaSection = this.getSectionId(recaptchaResponse);
+ if (recaptchaResponse && recaptchaResponse.value === "" && (sectionId === false || sectionId == recapchaSection)) {
+ this.scrollToElement(recaptchaResponse);
+ this.sendMessage("error", "Please complete the reCAPTCHA");
+ return false;
+ }
-class StripeFinancialConnections {
- constructor() {
- this.stripeModalOpen = false;
- this.logger = new logger_EngridLogger("Stripe Financial Connections", "black", "pink", "ποΈ");
- const observer = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- mutation.addedNodes.forEach((node) => {
- if (!this.stripeModalOpen && this.isStripeModalNodeWIthIframe(node)) {
- this.logger.log("Stripe Financial Connections modal opened.");
- this.onStripeModalOpen();
- }
- });
- mutation.removedNodes.forEach((node) => {
- if (this.stripeModalOpen && this.isStripeModalNode(node)) {
- this.logger.log("Stripe Financial Connections modal closed.");
- this.onStripeModalClose();
- }
- });
- });
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- });
+ // Validate Everything else
+ const mandatoryFields = form.querySelectorAll(".en__mandatory");
+ let hasError = false;
+ mandatoryFields.forEach(field => {
+ if (hasError) {
+ return;
+ }
+ const fieldElement = field.querySelector(".en__field__input");
+ const fieldLabel = field.querySelector(".en__field__label");
+ const fieldSection = this.getSectionId(fieldElement);
+ if (sectionId === false || sectionId == fieldSection) {
+ if (!fieldElement.value) {
+ this.scrollToElement(fieldElement);
+ this.sendMessage("error", "Please enter " + fieldLabel.textContent);
+ field.classList.add("has-error");
+ hasError = true;
+ return false;
+ } else {
+ field.classList.remove("has-error");
+ }
+ // If it's the e-mail field, check if it's a valid email
+ if (fieldElement.name === "supporter.emailAddress" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(fieldElement.value) === false) {
+ this.scrollToElement(fieldElement);
+ this.sendMessage("error", "Please enter a valid email address");
+ field.classList.add("has-error");
+ hasError = true;
+ return false;
+ }
+ }
+ });
+ if (hasError) {
+ return false;
}
- isStripeModalNode(node) {
- return (node instanceof HTMLElement &&
- node.hasAttribute("data-react-aria-top-layer"));
+ // Validate City Characters Limit
+ const city = form.querySelector("#en__field_supporter_city");
+ const cityBlock = form.querySelector(".en__field--city");
+ if (!this.checkCharsLimit("#en__field_supporter_city", 100)) {
+ this.scrollToElement(city);
+ this.sendMessage("error", "This field only allows up to 100 characters");
+ if (cityBlock) {
+ cityBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (cityBlock) {
+ cityBlock.classList.remove("has-error");
+ }
}
- isStripeModalNodeWIthIframe(node) {
- return !!(this.isStripeModalNode(node) &&
- node instanceof HTMLElement &&
- node.querySelector('iframe[src*="js.stripe.com"]'));
+ // Validate Street Address line 1 Characters Limit
+ const streetAddress1 = form.querySelector("#en__field_supporter_address1");
+ const streetAddress1Block = form.querySelector(".en__field--address1");
+ if (!this.checkCharsLimit("#en__field_supporter_address1", 35)) {
+ this.scrollToElement(streetAddress1);
+ this.sendMessage("error", "This field only allows up to 35 characters. Longer street addresses can be broken up between Lines 1 and 2.");
+ if (streetAddress1Block) {
+ streetAddress1Block.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (streetAddress1Block) {
+ streetAddress1Block.classList.remove("has-error");
+ }
}
- onStripeModalOpen() {
- this.stripeModalOpen = true;
+ // Validate Street Address line 2 Characters Limit
+ const streetAddress2 = form.querySelector("#en__field_supporter_address2");
+ const streetAddress2Block = form.querySelector(".en__field--address2");
+ if (!this.checkCharsLimit("#en__field_supporter_address2", 35)) {
+ this.scrollToElement(streetAddress2);
+ this.sendMessage("error", "This field only allows up to 35 characters. Longer street addresses can be broken up between Lines 1 and 2.");
+ if (streetAddress2Block) {
+ streetAddress2Block.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (streetAddress2Block) {
+ streetAddress2Block.classList.remove("has-error");
+ }
}
- onStripeModalClose() {
- this.stripeModalOpen = false;
- engrid_ENGrid.enableSubmit();
+ // Validate Zip Code Characters Limit
+ const zipCode = form.querySelector("#en__field_supporter_postcode");
+ const zipCodeBlock = form.querySelector(".en__field--postcode");
+ if (!this.checkCharsLimit("#en__field_supporter_postcode", 20)) {
+ this.scrollToElement(zipCode);
+ this.sendMessage("error", "This field only allows up to 20 characters");
+ if (zipCodeBlock) {
+ zipCodeBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (zipCodeBlock) {
+ zipCodeBlock.classList.remove("has-error");
+ }
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/give-by-select.js
-class GiveBySelect {
- constructor() {
- this.logger = new logger_EngridLogger("GiveBySelect", "#FFF", "#333", "π");
- this.transactionGiveBySelect = document.getElementsByName("transaction.giveBySelect");
- this._frequency = DonationFrequency.getInstance();
- if (!this.transactionGiveBySelect)
- return;
- this._frequency.onFrequencyChange.subscribe(() => this.checkPaymentTypeVisibility());
- this.transactionGiveBySelect.forEach((giveBySelect) => {
- giveBySelect.addEventListener("change", () => {
- this.logger.log("Changed to " + giveBySelect.value);
- engrid_ENGrid.setPaymentType(giveBySelect.value);
- });
- });
- // Set the initial value of giveBySelect to the transaction.paymenttype field
- const paymentType = engrid_ENGrid.getPaymentType();
- if (paymentType) {
- this.logger.log("Setting giveBySelect to " + paymentType);
- const isCard = [
- "card",
- "visa",
- "mastercard",
- "amex",
- "discover",
- "diners",
- "jcb",
- "vi",
- "mc",
- "ax",
- "dc",
- "di",
- "jc",
- ].includes(paymentType.toLowerCase());
- this.transactionGiveBySelect.forEach((giveBySelect) => {
- if (isCard && giveBySelect.value.toLowerCase() === "card") {
- giveBySelect.checked = true;
- }
- else if (giveBySelect.value.toLowerCase() === paymentType.toLowerCase()) {
- giveBySelect.checked = true;
- }
- });
- }
+ // Validate First Name Characters Limit
+ const firstName = form.querySelector("#en__field_supporter_firstName");
+ const firstNameBlock = form.querySelector(".en__field--firstName");
+ if (!this.checkCharsLimit("#en__field_supporter_firstName", 100)) {
+ this.scrollToElement(firstName);
+ this.sendMessage("error", "This field only allows up to 100 characters");
+ if (firstNameBlock) {
+ firstNameBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (firstNameBlock) {
+ firstNameBlock.classList.remove("has-error");
+ }
}
- // Returns true if the selected payment type is visible
- // Returns false if the selected payment type is not visible
- isSelectedPaymentVisible() {
- let visible = true;
- this.transactionGiveBySelect.forEach((giveBySelect) => {
- const container = giveBySelect.parentElement;
- if (giveBySelect.checked && !engrid_ENGrid.isVisible(container)) {
- this.logger.log(`Selected Payment Type is not visible: ${giveBySelect.value}`);
- visible = false;
- }
- });
- return visible;
+ // Validate Last Name Characters Limit
+ const lastName = form.querySelector("#en__field_supporter_lastName");
+ const lastNameBlock = form.querySelector(".en__field--lastName");
+ if (!this.checkCharsLimit("#en__field_supporter_lastName", 100)) {
+ this.scrollToElement(lastName);
+ this.sendMessage("error", "This field only allows up to 100 characters");
+ if (lastNameBlock) {
+ lastNameBlock.classList.add("has-error");
+ }
+ return false;
+ } else {
+ if (lastNameBlock) {
+ lastNameBlock.classList.remove("has-error");
+ }
}
- // Checks if the selected payment type is visible
- // If the selected payment type is not visible, it sets the payment type to the first visible option
- checkPaymentTypeVisibility() {
- window.setTimeout(() => {
- var _a;
- if (!this.isSelectedPaymentVisible()) {
- this.logger.log("Setting payment type to first visible option");
- const firstVisible = Array.from(this.transactionGiveBySelect).find((giveBySelect) => {
- const container = giveBySelect.parentElement;
- return engrid_ENGrid.isVisible(container);
- });
- if (firstVisible) {
- this.logger.log("Setting payment type to ", firstVisible.value);
- const container = firstVisible.parentElement;
- (_a = container.querySelector("label")) === null || _a === void 0 ? void 0 : _a.click();
- engrid_ENGrid.setPaymentType(firstVisible.value);
- }
- }
- else {
- this.logger.log("Selected Payment Type is visible");
- }
- }, 300);
+ console.log("DonationLightboxForm: validateForm PASSED");
+ return true;
+ }
+ checkCharsLimit(field, max) {
+ const fieldElement = document.querySelector(field);
+ if (fieldElement && fieldElement.value.length > max) {
+ return false;
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/url-params-to-body-attrs.js
-//This component adds any url parameters that begin with "data-engrid-" to the body as attributes.
+ return true;
+ }
-class UrlParamsToBodyAttrs {
- constructor() {
- this.logger = new logger_EngridLogger("UrlParamsToBodyAttrs", "white", "magenta", "π");
- this.urlParams = new URLSearchParams(document.location.search);
- this.urlParams.forEach((value, key) => {
- if (key.startsWith("data-engrid-")) {
- engrid_ENGrid.setBodyData(key.split("data-engrid-")[1], value);
- this.logger.log(`Set "${key}" on body to "${value}" from URL params`);
- }
- });
+ // Bounce Arrow Up and Down
+ bounceArrow(freq) {
+ const arrow = document.querySelector(".monthly-upsell-message");
+ if (!arrow) return;
+ if (arrow && freq === "onetime") {
+ arrow.classList.add("bounce");
+ // setTimeout(() => {
+ // arrow.classList.remove("bounce");
+ // }, 1000);
+ } else {
+ arrow.classList.remove("bounce");
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/exit-intent-lightbox.js
-
-
-class ExitIntentLightbox {
- constructor() {
- this.opened = false;
- this.dataLayer = window.dataLayer || [];
- this.logger = new logger_EngridLogger("ExitIntentLightbox", "yellow", "black", "πͺ");
- this.triggerDelay = 1000; // Don't run the exit intent lightbox until at least 1 second has passed after page load
- this.triggerTimeout = null;
- let options = "EngridExitIntent" in window ? window.EngridExitIntent : {};
- this.options = Object.assign(Object.assign({}, ExitIntentOptionsDefaults), options);
- if (!this.options.enabled) {
- this.logger.log("Not enabled");
- return;
- }
- if (get(this.options.cookieName)) {
- this.logger.log("Not showing - cookie found.");
- return;
- }
- const activeTriggers = Object.keys(this.options.triggers)
- .filter((t) => this.options.triggers[t])
- .join(", ");
- this.logger.log("Enabled, waiting for trigger. Active triggers: " + activeTriggers);
- this.watchForTriggers();
+ }
+ changeSubmitButton() {
+ const submit = document.querySelector(".section-navigation__submit");
+ let amount = "$" + this.app.formatNumber(this.getDonationTotal());
+ // If amount ends with .00, remove it
+ if (amount && amount.endsWith(".00")) {
+ amount = amount.slice(0, -3);
}
- watchForTriggers() {
- window.addEventListener("load", () => {
- setTimeout(() => {
- if (this.options.triggers.mousePosition) {
- this.watchMouse();
- }
- if (this.options.triggers.visibilityState) {
- this.watchDocumentVisibility();
- }
- }, this.triggerDelay); // Delay activation of triggers
- });
+ let frequency = this.frequency.getInstance().frequency;
+ let label = submit ? submit.dataset.label : "";
+ frequency = frequency === "onetime" ? "" : frequency === "monthly" ? "/mo " : frequency === "annual" ? "/yr " : "";
+ if (amount) {
+ label = label.replace("$AMOUNT", amount);
+ label = label.replace("$FREQUENCY", frequency);
+ } else {
+ label = label.replace("$AMOUNT", "");
+ label = label.replace("$FREQUENCY", "");
}
- watchMouse() {
- document.addEventListener("mouseout", (e) => {
- // If this is an autocomplete element.
- if (e.target.tagName.toLowerCase() == "input")
- return;
- // Get the current viewport width.
- const vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
- // If the current mouse X position is within 50px of the right edge
- // of the viewport, return.
- if (e.clientX >= vpWidth - 50)
- return;
- // If the current mouse Y position is not within 50px of the top
- // edge of the viewport, return.
- if (e.clientY >= 50)
- return;
- // Reliable, works on mouse exiting window and
- // user switching active program
- const from = e.relatedTarget;
- if (!from) {
- this.logger.log("Triggered by mouse position");
- this.open();
- }
- if (!this.triggerTimeout) {
- this.triggerTimeout = window.setTimeout(() => {
- if (!from) {
- this.logger.log("Triggered by mouse position");
- this.open();
- }
- this.triggerTimeout = null;
- }, this.triggerDelay);
- }
- });
+ if (submit && label) {
+ submit.innerHTML = `${label} `;
}
- watchDocumentVisibility() {
- const visibilityListener = () => {
- if (document.visibilityState === "hidden") {
- if (!this.triggerTimeout) {
- this.triggerTimeout = window.setTimeout(() => {
- this.logger.log("Triggered by visibilityState is hidden");
- this.open();
- document.removeEventListener("visibilitychange", visibilityListener);
- this.triggerTimeout = null;
- }, this.triggerDelay);
- }
- }
- };
- document.addEventListener("visibilitychange", visibilityListener);
+ }
+ clickPaymentOptions(opts) {
+ opts.querySelectorAll("button").forEach(btn => {
+ btn.addEventListener("click", e => {
+ e.preventDefault();
+ const paymentType = document.querySelector("#en__field_transaction_paymenttype");
+ if (paymentType) {
+ paymentType.value = btn.className.substr(15);
+ // Go to the next section
+ this.scrollToSection(parseInt(btn.closest("[data-section-id]").dataset.sectionId) + 1, this.currentSectionId);
+ }
+ });
+ });
+ }
+ // Append arrow SVG to the monthly upsell message
+ putArrowUpSVG() {
+ const arrow = document.querySelector(".monthly-upsell-message");
+ if (arrow) {
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+ svg.classList.add(this.setArrowPosition());
+ svg.classList.add("monthly-upsell-message__arrow");
+ svg.setAttribute("viewBox", "0 0 55 40");
+ svg.setAttribute("fill", "none");
+ svg.innerHTML = ` `;
+ arrow.appendChild(svg);
}
- open() {
- var _a, _b, _c;
- if (this.opened)
- return;
- engrid_ENGrid.setBodyData("exit-intent-lightbox", "open");
- set(this.options.cookieName, "1", {
- expires: this.options.cookieDuration,
- });
- document.body.insertAdjacentHTML("beforeend", `
-
-
-
-
X
-
-
${this.options.title}
-
${this.options.text}
-
- ${this.options.buttonText}
-
-
-
-
-
- `);
- this.opened = true;
- this.dataLayer.push({ event: "exit_intent_lightbox_shown" });
- (_a = document
- .querySelector(".ExitIntent__close")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
- this.dataLayer.push({ event: "exit_intent_lightbox_closed" });
- this.close();
- });
- (_b = document
- .querySelector(".ExitIntent__overlay")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", (event) => {
- if (event.target === event.currentTarget) {
- this.dataLayer.push({ event: "exit_intent_lightbox_closed" });
- this.close();
+ }
+ // Return the arrow position
+ setArrowPosition() {
+ const frequencyWrapper = document.querySelector(".en__field--recurrfreq .en__field__element--radio");
+ if (frequencyWrapper) {
+ const left = frequencyWrapper.querySelector('.en__field__item:first-child input[value="MONTHLY"]');
+ const right = frequencyWrapper.querySelector('.en__field__item:last-child input[value="MONTHLY"]');
+ if (left) {
+ return "left";
+ }
+ if (right) {
+ return "right";
+ }
+ }
+ return null;
+ }
+ checkNested(obj, level, ...rest) {
+ if (obj === undefined) return false;
+ if (rest.length == 0 && obj.hasOwnProperty(level)) return true;
+ return this.checkNested(obj[level], ...rest);
+ }
+ // Add Tabindex to Labels
+ addTabIndexToLabels() {
+ const labels = document.querySelectorAll(".en__field__label.en__field__label--item");
+ labels.forEach(label => {
+ label.tabIndex = 0;
+ });
+ }
+ isVisible(element) {
+ return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
+ }
+ addEvents() {
+ const feeCover = document.querySelector("#en__field_transaction_feeCover");
+ if (feeCover) {
+ feeCover.addEventListener("change", () => {
+ this.changeSubmitButton();
+ });
+ }
+ this.frequency.getInstance().onFrequencyChange.subscribe(s => this.bounceArrow(s));
+ this.frequency.getInstance().onFrequencyChange.subscribe(() => this.changeSubmitButton());
+ this.frequency.getInstance().onFrequencyChange.subscribe(() => {
+ this.showHideDynamicSection(false);
+ });
+ this.amount.getInstance().onAmountChange.subscribe(() => this.changeSubmitButton());
+ // Payment Type Radio Change
+ const paymentType = document.querySelectorAll("input[name='transaction.giveBySelect']");
+ if (paymentType.length) {
+ paymentType.forEach(item => {
+ item.addEventListener("change", () => {
+ this.showHideDynamicSection(item.value.toLowerCase());
+ if (item.value === "card") {
+ const paymentType = document.querySelector("#en__field_transaction_paymenttype");
+ if (paymentType) {
+ paymentType.value = "card";
}
+ }
+ console.log(`Payment type changed to: ${item.value.toLowerCase()}`);
+ window.setTimeout(() => {
+ this.scrollToElement(item.closest(".en__component"));
+ }, 100);
});
- (_c = document
- .querySelector(".ExitIntent__button")) === null || _c === void 0 ? void 0 : _c.addEventListener("click", () => {
- this.dataLayer.push({ event: "exit_intent_lightbox_cta_clicked" });
- this.close();
- const target = this.options.buttonLink;
- if (target.startsWith(".") || target.startsWith("#")) {
- const targetEl = document.querySelector(target);
- if (targetEl) {
- targetEl.scrollIntoView({ behavior: "smooth" });
- }
- }
- else {
- window.open(target, "_blank");
- }
+ });
+ }
+ const recaptchaContainer = document.querySelector(".en__captcha");
+ if (recaptchaContainer) {
+ if (typeof window._grecaptchaExpireCallback === "function") {
+ // Add our own callback to the recaptcha
+ const oldCallback = window._grecaptchaExpireCallback;
+ window._grecaptchaExpireCallback = () => {
+ oldCallback();
+ window.setTimeout(() => {
+ this.scrollToElement(recaptchaContainer.closest(".en__component"));
+ this.sendMessage("error", "reCAPTCHA expired");
+ }, 400);
+ };
+ }
+ }
+ if (this.upsellSection) {
+ this.frequency.getInstance().onFrequencyChange.subscribe(() => this.refreshUpsellSection());
+ this.amount.getInstance().onAmountChange.subscribe(() => this.refreshUpsellSection());
+ const upsellButtons = this.upsellSection.querySelectorAll(".upsell-buttons button");
+ upsellButtons.forEach(btn => {
+ btn.addEventListener("click", e => {
+ e.preventDefault();
+ const upsellFrequency = btn.dataset.freq || "onetime";
+ const upsellAmount = parseFloat(btn.dataset.amount) || this.getDonationTotal();
+ if (upsellAmount === 0) {
+ return;
+ }
+ if (upsellFrequency === "onetime") {
+ this.upsellSection.dataset.upsold = "false";
+ } else {
+ this.upsellSection.dataset.upsold = "true";
+ }
+ this.amount.getInstance().setAmount(upsellAmount);
+ this.frequency.getInstance().setFrequency(upsellFrequency);
+ this.scrollToElement(document.querySelector(".give-by-select"));
+ // this.changeSubmitButton();
});
+ });
}
- close() {
- var _a;
- (_a = document.querySelector(".ExitIntent")) === null || _a === void 0 ? void 0 : _a.remove();
- engrid_ENGrid.setBodyData("exit-intent-lightbox", "closed");
+ }
+ // paymentType is any of the values from the giveBySelect radio buttons
+ // it can also be false, in which case it will try to get the value from the paymentType field
+ showHideDynamicSection(paymentType) {
+ let ptValue = paymentType;
+ if (!paymentType) {
+ const payment = document.querySelector("#en__field_transaction_paymenttype");
+ if (payment && ["visa", "mastercard", "amex", "discover", "diners", "jcb", "card"].includes(payment.value)) {
+ ptValue = "card";
+ // Check Card transaction.giveBySelect
+ const card = document.querySelector("[name='transaction.giveBySelect'][value='card']");
+ if (card) {
+ card.checked = true;
+ const event = new Event("change");
+ card.dispatchEvent(event);
+ }
+ } else {
+ ptValue = payment ? payment.value.toLowerCase() : null;
+ const giveBySelectItem = document.querySelector(`[name='transaction.giveBySelect'][value='${ptValue}']`);
+ if (giveBySelectItem) {
+ giveBySelectItem.checked = true;
+ const event = new Event("change");
+ giveBySelectItem.dispatchEvent(event);
+ }
+ }
}
-}
+ // Get every element that has the CSS class giveBySelect-*
+ const giveBySelectItems = document.querySelectorAll("[class*='giveBySelect-']");
+ console.log(`Found ${giveBySelectItems.length} total giveBySelect- elements`);
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/supporter-hub.js
-// Component that adds 4Site Special Features to the Supporter Hub Page
+ // Create a Set of sections that have giveBySelect- elements (excluding those in digital-wallets-wrapper)
+ const sectionsWithGiveBySelect = new Set();
+ giveBySelectItems.forEach(item => {
+ // Skip if the element is inside digital-wallets-wrapper
+ if (item.closest(".digital-wallets-wrapper")) {
+ console.log(`Skipping giveBySelect- element in digital-wallets-wrapper: ${item.className}`);
+ return;
+ }
+ const section = this.getSectionId(item);
+ if (section !== false) {
+ sectionsWithGiveBySelect.add(section);
+ console.log(`Section ${section} has giveBySelect- element: ${item.className}`);
+ }
+ });
+ console.log(`Found ${sectionsWithGiveBySelect.size} sections with giveBySelect- elements`);
-class SupporterHub {
- constructor() {
- this.logger = new logger_EngridLogger("SupporterHub", "black", "pink", "π");
- this._form = en_form_EnForm.getInstance();
- if (!this.shoudRun())
- return;
- this.logger.log("Enabled");
- this.watch();
- this.preventDuplicateSubmits();
+ // First, handle sections without giveBySelect- elements
+ this.sections.forEach((section, sectionId) => {
+ if (!sectionsWithGiveBySelect.has(sectionId) && sectionId !== this.upsellSectionId) {
+ section.style.display = "block";
+ console.log(`Showing section ${sectionId} (no giveBySelect elements)`);
+ }
+ });
+
+ // Then, handle sections with giveBySelect- elements
+ sectionsWithGiveBySelect.forEach(sectionId => {
+ const section = this.sections[sectionId];
+ // Only get giveBySelect- elements that are not in digital-wallets-wrapper
+ const sectionItems = Array.from(section.querySelectorAll("[class*='giveBySelect-']")).filter(item => !item.closest(".digital-wallets-wrapper"));
+ console.log(`Section ${sectionId} has ${sectionItems.length} giveBySelect- elements (excluding digital-wallets-wrapper)`);
+ let shouldShow = false;
+ sectionItems.forEach(item => {
+ // Get the value of the class
+ let value = item.className.split("giveBySelect-")[1];
+ // Get the value until the next space
+ value = value.split(" ")[0];
+ console.log(`Checking giveBySelect- element in section ${sectionId}: ${value} against payment type: ${ptValue}`);
+ // If the value is the same as the payment type, show the section
+ if (value.toLowerCase() === ptValue) {
+ shouldShow = true;
+ console.log(`Match found for section ${sectionId}`);
+ }
+ });
+ section.style.display = shouldShow ? "block" : "none";
+ console.log(`${shouldShow ? "Showing" : "Hiding"} section ${sectionId} (payment type: ${ptValue})`);
+ });
+ this.updateSectionCount();
+ }
+ getDonationTotal() {
+ return this.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationTotal") ? window.EngagingNetworks.require._defined.enjs.getDonationTotal() : 0;
+ }
+ getDonationFee() {
+ return this.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationFee") ? window.EngagingNetworks.require._defined.enjs.getDonationFee() : 0;
+ }
+ // Return the Suggested Upsell Amount
+ getUpsellAmount(freq = "monthly") {
+ const amount = this.getDonationTotal() - this.getDonationFee();
+ let upsellAmount = 0;
+ if ("EngridMultistepUpsell" in window && freq in window.EngridMultistepUpsell) {
+ const amountRange = window.EngridMultistepUpsell[freq];
+ for (let i = 0; i < amountRange.length; i++) {
+ let val = amountRange[i];
+ if (upsellAmount == 0 && amount <= val.max) {
+ upsellAmount = val.suggestion;
+ if (upsellAmount === 0) return 0;
+ if (typeof upsellAmount !== "number") {
+ const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
+ upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
+ }
+ break;
+ }
+ }
}
- shoudRun() {
- return ("pageJson" in window &&
- "pageType" in window.pageJson &&
- window.pageJson.pageType === "supporterhub");
+ return upsellAmount;
+ }
+ replaceUpsellMergeTags() {
+ if (this.upsellSection === null) return;
+ const upsellSectionContent = this.upsellSection.querySelector(".en__component--column");
+ if (!upsellSectionContent) return;
+ let content = upsellSectionContent.innerHTML;
+ content = content.replace(/{old-amount}/g, " ");
+ content = content.replace(/{new-amount-monthly}/g, " ");
+ content = content.replace(/{new-amount-annual}/g, " ");
+ upsellSectionContent.innerHTML = content;
+ }
+ refreshUpsellSection() {
+ if (this.upsellSection === null || this.upsellSection.dataset.upsold) return;
+ // Update merge tags
+ const amount = this.getDonationTotal() - this.getDonationFee();
+ const upsellAmountMonthly = this.getUpsellAmount("monthly");
+ const upsellAmountAnnual = this.getUpsellAmount("annual");
+ if (upsellAmountMonthly === 0 && upsellAmountAnnual === 0) {
+ // If both upsell amounts are 0, hide the upsell section
+ this.upsellSection.style.display = "none";
+ this.updateSectionCount();
+ return;
}
- watch() {
- const form = engrid_ENGrid.enForm;
- // Create a observer to watch the Form for overlays
- const observer = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- if (mutation.type === "childList") {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeName === "DIV") {
- const overlay = node;
- if (overlay.classList.contains("en__hubOverlay") ||
- overlay.classList.contains("en__hubPledge__panels")) {
- this.logger.log("Overlay found");
- this.creditCardUpdate(node);
- this.amountLabelUpdate(node);
- }
- }
- });
- }
- });
- });
- // Start observing the Link ID
- observer.observe(form, {
- childList: true,
- subtree: true,
- });
- // Run the Credit Card Update function in case the overlay is already present on page load
- const hubOverlay = document.querySelector(".en__hubOverlay");
- if (hubOverlay) {
- this.creditCardUpdate(hubOverlay);
- this.amountLabelUpdate(hubOverlay);
- }
+ const oldAmounts = this.upsellSection.querySelectorAll(".upsell_amount");
+ const newAmountsMonthly = this.upsellSection.querySelectorAll(".upsell_suggestion_monthly");
+ const newAmountsAnnual = this.upsellSection.querySelectorAll(".upsell_suggestion_annual");
+ const monthlyBtn = this.upsellSection.querySelector(".upsell-buttons button[data-freq='monthly']");
+ const annualBtn = this.upsellSection.querySelector(".upsell-buttons button[data-freq='annual']");
+ const onetimeBtn = this.upsellSection.querySelector(".upsell-buttons button[data-freq='onetime']");
+ if (monthlyBtn) {
+ monthlyBtn.dataset.amount = upsellAmountMonthly;
}
- creditCardUpdate(overlay) {
- window.setTimeout(() => {
- // Check if the overlay has Credit Card field and Update Button
- const ccField = overlay.querySelector("#en__hubPledge__field--ccnumber"), updateButton = overlay.querySelector(".en__hubUpdateCC__toggle");
- if (ccField && updateButton) {
- // When field gets focus, click the update button
- ccField.addEventListener("focus", () => {
- this.logger.log("Credit Card field focused");
- updateButton.click();
- });
- }
- }, 300);
+ if (annualBtn) {
+ annualBtn.dataset.amount = upsellAmountAnnual;
}
- amountLabelUpdate(overlay) {
- window.setTimeout(() => {
- // Check if the overlay has Amounts, and set the currency symbol updated attribute
- const amountContainer = overlay.querySelector(".en__field--donationAmt");
- if (amountContainer) {
- amountContainer
- .querySelectorAll(".en__field__element--radio .en__field__item")
- .forEach((node) => {
- node.setAttribute("data-engrid-currency-symbol-updated", "true");
- });
- }
- }, 300);
+ if (onetimeBtn) {
+ onetimeBtn.dataset.amount = amount;
}
- // The supporter hub does not properly handle or prevent duplicate submits, so we add a listener to prevent this.
- preventDuplicateSubmits() {
- document.addEventListener("click", (e) => {
- const btn = e.target.closest(".en__submit button");
- if (!btn)
- return;
- if (btn.dataset.busy) {
- e.stopImmediatePropagation();
- e.preventDefault();
- return;
- }
- btn.dataset.busy = "true";
- setTimeout(() => delete btn.dataset.busy, 10000);
- }, true);
+ if (oldAmounts) {
+ let upsellOnetimeAmount = "$" + this.app.formatNumber(amount);
+ if (upsellOnetimeAmount.endsWith(".00")) {
+ upsellOnetimeAmount = upsellOnetimeAmount.slice(0, -3);
+ }
+ oldAmounts.forEach(oldAmount => {
+ oldAmount.innerHTML = upsellOnetimeAmount;
+ });
+ }
+ if (newAmountsMonthly) {
+ let upsellMonthlyAmount = "$" + this.app.formatNumber(upsellAmountMonthly);
+ if (upsellMonthlyAmount.endsWith(".00")) {
+ upsellMonthlyAmount = upsellMonthlyAmount.slice(0, -3);
+ }
+ newAmountsMonthly.forEach(newAmount => {
+ newAmount.innerHTML = upsellMonthlyAmount;
+ });
+ }
+ if (newAmountsAnnual) {
+ let upsellAnnualAmount = "$" + this.app.formatNumber(upsellAmountAnnual);
+ if (upsellAnnualAmount.endsWith(".00")) {
+ upsellAnnualAmount = upsellAnnualAmount.slice(0, -3);
+ }
+ newAmountsAnnual.forEach(newAmount => {
+ newAmount.innerHTML = upsellAnnualAmount;
+ });
+ }
+ // If frequency is anything other than onetime, hide the upsell section
+ window.setTimeout(() => {
+ const frequency = this.frequency.getInstance().frequency;
+ if (this.upsellSection && !this.upsellSection.dataset.upsold) {
+ if (frequency === "onetime") {
+ this.upsellSection.style.display = "block";
+ } else {
+ this.upsellSection.style.display = "none";
+ }
+ }
+ this.updateSectionCount();
+ }, 600);
+ // Update visibility
+ }
+ hideAnnualFrequency() {
+ const annualFreqField = document.querySelector("[name='transaction.recurrfreq'][value='ANNUAL']");
+ if (annualFreqField) {
+ const annualFrequency = annualFreqField.closest(".en__field__item");
+ if (annualFrequency) {
+ annualFrequency.classList.add("hide");
+ }
}
+ }
+}
+;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/typeof.js
+function _typeof(o) {
+ "@babel/helpers - typeof";
+
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
+ return typeof o;
+ } : function (o) {
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
+ }, _typeof(o);
}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/fast-form-fill.js
+;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/toPrimitive.js
+
+function toPrimitive(t, r) {
+ if ("object" != _typeof(t) || !t) return t;
+ var e = t[Symbol.toPrimitive];
+ if (void 0 !== e) {
+ var i = e.call(t, r || "default");
+ if ("object" != _typeof(i)) return i;
+ throw new TypeError("@@toPrimitive must return a primitive value.");
+ }
+ return ("string" === r ? String : Number)(t);
+}
+
+;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js
+
+
+function toPropertyKey(t) {
+ var i = toPrimitive(t, "string");
+ return "symbol" == _typeof(i) ? i : i + "";
+}
+
+;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/defineProperty.js
+
+function _defineProperty(e, r, t) {
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
+ value: t,
+ enumerable: !0,
+ configurable: !0,
+ writable: !0
+ }) : e[r] = t, e;
+}
+
+;// CONCATENATED MODULE: ./src/scripts/tracking.js
+
+function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
+function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
/**
- * This class adds body data attributes if all mandatory inputs, on specific form blocks, are filled.
- * Related styling (to hide elements) can be found in "fast-form-fill.scss".
- *
- * To activate: add the custom class "fast-personal-details" or "fast-address-details"
- * to the relevant form block.
+ * @typedef {Object} Window
+ * @property {Object} utag
+ * @property {Object} utag_data
+ * @property {String} utag_data.page_name
+ * @property {Object} pageJson
+ * @property {String} pageJson.pageType
*/
-class FastFormFill {
- constructor() {
- this.logger = new logger_EngridLogger("FastFormFill", "white", "magenta", "π");
- this.rememberMeEvents = RememberMeEvents.getInstance();
- if (engrid_ENGrid.getOption("RememberMe")) {
- this.rememberMeEvents.onLoad.subscribe((hasData) => {
- this.logger.log("Remember me - onLoad", hasData);
- this.run();
- });
- this.rememberMeEvents.onClear.subscribe(() => {
- // This is a test for the onClear event
- this.logger.log("Remember me - onClear");
- });
- }
- else {
- this.run();
- }
- }
- run() {
- const fastPersonalDetailsFormBlocks = document.querySelectorAll(".en__component--formblock.fast-personal-details");
- if (fastPersonalDetailsFormBlocks.length > 0) {
- if ([...fastPersonalDetailsFormBlocks].every((formBlock) => FastFormFill.allMandatoryInputsAreFilled(formBlock))) {
- this.logger.log("Personal details - All mandatory inputs are filled");
- engrid_ENGrid.setBodyData("hide-fast-personal-details", "true");
- }
- else {
- this.logger.log("Personal details - Not all mandatory inputs are filled");
- engrid_ENGrid.setBodyData("hide-fast-personal-details", "false");
- }
- }
- const fastAddressDetailsFormBlocks = document.querySelectorAll(".en__component--formblock.fast-address-details");
- if (fastAddressDetailsFormBlocks.length > 0) {
- if ([...fastAddressDetailsFormBlocks].every((formBlock) => FastFormFill.allMandatoryInputsAreFilled(formBlock))) {
- this.logger.log("Address details - All mandatory inputs are filled");
- engrid_ENGrid.setBodyData("hide-fast-address-details", "true");
- }
- else {
- this.logger.log("Address details - Not all mandatory inputs are filled");
- engrid_ENGrid.setBodyData("hide-fast-address-details", "false");
- }
- }
- }
- static allMandatoryInputsAreFilled(formBlock) {
- const fields = formBlock.querySelectorAll(".en__mandatory input, .en__mandatory select, .en__mandatory textarea");
- return [...fields].every((input) => {
- if (input.type === "radio" || input.type === "checkbox") {
- const inputs = document.querySelectorAll('[name="' + input.name + '"]');
- return [...inputs].some((radioOrCheckbox) => radioOrCheckbox.checked);
- }
- else {
- return input.value !== null && input.value.trim() !== "";
- }
+function trackEvent(eventName, eventData) {
+ if (typeof utag !== "undefined") {
+ utag.link(_objectSpread({
+ event_name: eventName
+ }, eventData));
+ } else {
+ window.utagQueue = window.utagQueue || [];
+ window.utagQueue.push(_objectSpread({
+ event_name: eventName
+ }, eventData));
+ const tealiumScript = document.querySelector('script[src*="//tags.tiqcdn.com/utag/tnc/global/prod/utag.js"]');
+ if (tealiumScript) {
+ tealiumScript.onload = () => {
+ window.utagQueue.forEach(event => {
+ utag.link(event);
});
+ window.utagQueue = [];
+ };
+ }
+ }
+}
+function setDonationDataSessionStorage(App, DonationAmount) {
+ const donationData = {};
+ donationData.productId = utag_data.page_name.slice(0, -2);
+ donationData.campaignId = pageJson.campaignId;
+ donationData.campaignPageId = App.getPageID();
+ donationData.state = App.getFieldValue("supporter.region");
+ donationData.zipCode = App.getFieldValue("supporter.postcode");
+ donationData.emailAddress = App.getFieldValue("supporter.emailAddress");
+ donationData.originalDonationAmount = DonationAmount.getInstance().amount;
+ donationData.extraAmount = 0;
+ // New donationData fields for Google Ads Enhanced Conversions
+ donationData.firstName = App.getFieldValue("supporter.firstName");
+ donationData.lastName = App.getFieldValue("supporter.lastName");
+ donationData.address1 = App.getFieldValue("supporter.address1");
+ donationData.city = App.getFieldValue("supporter.city");
+ donationData.country = App.getFieldValue("supporter.country");
+ donationData.phoneNumber = App.getFieldValue("supporter.phoneNumber2");
+ donationData.isEmailOptInChecked = ["supporter.questions.848518", "supporter.questions.848520", "supporter.questions.848521", "supporter.questions.848522", "supporter.questions.848523"].some(field => {
+ /** @type {HTMLInputElement} */
+ const el = App.getField(field);
+ return el && el.checked;
+ });
+
+ /** @type {HTMLInputElement} */
+ //If fee cover is checked, set extra amount to 3% of donation amount and subtract from original donation amount
+ const feeCoverCheckbox = App.getField("transaction.feeCover");
+ if (feeCoverCheckbox && feeCoverCheckbox.checked) {
+ donationData.extraAmount = (DonationAmount.getInstance().amount * 0.03).toFixed(2);
+ donationData.originalDonationAmount = donationData.originalDonationAmount - donationData.extraAmount;
+ }
+ const sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
+ if (sendEcardCheckbox && sendEcardCheckbox.checked) {
+ donationData.ecardSelected = "true";
+ }
+ sessionStorage.setItem("donationData", JSON.stringify(donationData));
+}
+function trackFormSubmit(App, DonationAmount) {
+ //Donation page submits
+ if (App.getPageType() === "DONATION" && App.getPageNumber() === 1) {
+ setDonationDataSessionStorage(App, DonationAmount);
+ }
+
+ //Mobile phone data (for "F32 - Real Time SMS Push" script - opts user into SMS via API)
+ /** @type {HTMLInputElement} */
+ const mobilePhoneNumber = App.getField("supporter.phoneNumber2");
+ if (mobilePhoneNumber) {
+ const mobilePhoneData = {};
+ mobilePhoneData.phoneNumber = mobilePhoneNumber.value;
+ /** @type {HTMLInputElement} */
+ const mobilePhoneOptIn = App.getField("supporter.questions.848527") || App.getField("supporter.questions.1952175") || App.getField("supporter.questions.2268563");
+ if (mobilePhoneOptIn && mobilePhoneOptIn.checked) {
+ mobilePhoneData.optIn = "Y";
}
- static someMandatoryInputsAreFilled(formBlock) {
- const fields = formBlock.querySelectorAll(".en__mandatory input, .en__mandatory select, .en__mandatory textarea");
- return [...fields].some((input) => {
- if (input.type === "radio" || input.type === "checkbox") {
- const inputs = document.querySelectorAll('[name="' + input.name + '"]');
- return [...inputs].some((radioOrCheckbox) => radioOrCheckbox.checked);
- }
- else {
- return input.value !== null && input.value.trim() !== "";
- }
- });
+ sessionStorage.setItem("mobilePhoneData", JSON.stringify(mobilePhoneData));
+ }
+
+ //Track ETT, petition, survey and data capture submits
+ if (["ADVOCACY", "EMAILTOTARGET", "SURVEY"].includes(App.getPageType())) {
+ if (App.getFieldValue("supporter.emailAddress") === "") {
+ return;
}
-}
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/set-attr.js
-/*+
- The class is used to set body attributes via click handlers.
- The format is "setattr--{attribute}--{value}".
- e.g. setattr--data-engrid-hide-fast-address-details--true
- */
+ // Tealium (utag_data) isn't loaded on every page type β notably,
+ // the QCB data-capture iframes processed by the IframeQueue
+ // don't include it. Bail out cleanly instead of throwing
+ // ReferenceError, which would abort the form submission.
+ if (typeof utag_data === "undefined") {
+ return;
+ }
+ let utagData = {};
+ utagData.form_type = pageJson.pageType;
+ utagData.form_name = utag_data.page_name.slice(0, -2);
+ utagData.action_id = utag_data.form_name;
+ utagData.action_type = pageJson.pageType;
+ utagData.zip_code = App.getFieldValue("supporter.postcode");
+ utagData.email_signup_location = pageJson.pageType;
-class SetAttr {
- constructor() {
- this.logger = new logger_EngridLogger("SetAttr", "black", "yellow", "π");
- const enGrid = document.getElementById("engrid");
- if (enGrid) {
- enGrid.addEventListener("click", (e) => {
- const clickedEl = e.target;
- if (typeof clickedEl.className !== "string") {
- return;
- }
- const clickedElClassNames = clickedEl.className.split(" ");
- if (clickedElClassNames.some((className) => className.startsWith("setattr--"))) {
- clickedEl.classList.forEach((className) => {
- //Check element has class with format "setattr--attribute--value"
- const match = className.match(/^setattr--(.+)--(.+)$/i);
- if (match && match[1] && match[2]) {
- this.logger.log(`Clicked element with class "${className}". Setting body attribute "${match[1]}" to "${match[2]}"`);
- engrid_ENGrid.setBodyData(match[1].replace("data-engrid-", ""), match[2]);
- }
- });
- }
- });
- }
+ // New utag variables fields for Google Ads Enhanced Conversions for ETT & PET
+ utagData.const_first = App.getFieldValue("supporter.firstName");
+ utagData.const_last = App.getFieldValue("supporter.lastName");
+ utagData.const_address = App.getFieldValue("supporter.address1");
+ utagData.const_city = App.getFieldValue("supporter.city");
+ utagData.customer_state = App.getFieldValue("supporter.region");
+ utagData.customer_postal_code = App.getFieldValue("supporter.postcode");
+ utagData.customer_country = App.getFieldValue("supporter.country");
+ utagData.const_phone = App.getFieldValue("supporter.phoneNumber2");
+ const eventName = getSubmitEventName(App);
+ if (eventName === "frm_emt_txt_submit" || eventName === "frm_emt_emo_txt_submit") {
+ utagData.text_signup_location = pageJson.pageType;
}
+ trackEvent(eventName, utagData);
+ }
+}
+function getSubmitEventName(App) {
+ const isOptedInToPhone = ["supporter.questions.848528", "supporter.questions.1952175", "supporter.questions.848527", "supporter.questions.891102"].some(field => {
+ /** @type {HTMLInputElement} */
+ const el = App.getField(field);
+ return el && el.checked && App.getFieldValue("supporter.phoneNumber2") !== "" || el && el.checked && field.split(".")[2] === "891102" && App.getFieldValue("supporter.phoneNumber");
+ });
+ const isOptedInToEmail = ["supporter.questions.848518", "supporter.questions.848520", "supporter.questions.848521", "supporter.questions.848522", "supporter.questions.848523"].some(field => {
+ /** @type {HTMLInputElement} */
+ const el = App.getField(field);
+ return el && el.checked;
+ });
+ if (isOptedInToEmail && isOptedInToPhone) {
+ return "frm_emt_emo_txt_submit";
+ }
+ if (isOptedInToPhone) {
+ return "frm_emt_txt_submit";
+ }
+ if (isOptedInToEmail) {
+ return "frm_emt_emo_submit";
+ }
+ return "frm_emt_submit";
}
+function trackFormErrors() {
+ setTimeout(() => {
+ let invalidFields = "";
+ let errors = "";
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/show-if-present.js
-/**
- * This class contains the logic for special classes that can be used to hide elements if
- * certain supporter questions are present or absent.
- * Typically, this can be used to hide elements when an opt in question is not rendered on the page
- * because the supporter came from a campaign link and is already opted in, so EN doesn't render
- * the question on the page.
- *
- * The class names are of the format:
- * engrid__supporterquestions{id}-present -- show this element when the supporter question is present
- * engrid__supporterquestions{id}-absent -- show this element when the supporter question is absent
- *
- * The {id} is the id of the supporter question. This can be found by inspecting the element on the page.
- *
- * It's also possible to combine multiple questions using the following format. These examples show 2 questions,
- * but you can use as many as you like:
- * engrid__supporterquestions{id1}__supporterquestions{id2}-present -- show this element when EITHER question is present
- * engrid__supporterquestions{id1}__supporterquestions{id2}-absent -- show this element when EITHER question is absent
- */
+ // Gather invalid fields and error messages
+ document.querySelectorAll(".en__field--validationFailed").forEach(el => {
+ if (el.querySelector(".en__field__error")) {
+ invalidFields += `${el.querySelector(".en__field__input").getAttribute("name")}|`;
+ errors += `${el.querySelector(".en__field__error").textContent}|`;
+ }
+ });
-class ShowIfPresent {
- constructor() {
- this.logger = new logger_EngridLogger("ShowIfPresent", "yellow", "black", "π");
- this.elements = [];
- if (this.shouldRun()) {
- this.run();
- }
- }
- shouldRun() {
- // Check if we have any elements on the page that match the pattern for this functionality
- // e.g. engrid__supporterquestions{id}__supporterquestions{id}-present, etc.
- this.elements = [
- ...document.querySelectorAll('[class*="engrid__supporterquestions"]'),
- ].filter((el) => {
- const classNames = el.className.split(" ");
- return classNames.some((className) => /^engrid__supporterquestions\d+(__supporterquestions\d+)*-(present|absent)$/.test(className));
- });
- return this.elements.length > 0;
+ // Fire tracking if errors were found
+ if (invalidFields !== "") {
+ trackEvent("form_error", {
+ form_field_error_field: invalidFields.slice(0, -1),
+ form_field_error_value: errors.slice(0, -1),
+ // Tealium isn't loaded on every page (e.g. QCB iframes);
+ // fall back to empty string instead of throwing.
+ form_name: typeof utag_data !== "undefined" ? utag_data.page_name.slice(0, -2) : "",
+ form_type: pageJson.pageType
+ });
}
- run() {
- const actions = [];
- // Create an array of actions for each element we have
- this.elements.forEach((el) => {
- // Mapping to an object with the class name, field name(s), and type
- const classNames = el.className.split(" ");
- const matchingClass = classNames.find((className) => /^engrid__supporterquestions\d+(__supporterquestions\d+)*-(present|absent)$/.test(className));
- if (!matchingClass)
- return null;
- const typeIndex = matchingClass.lastIndexOf("-");
- const type = matchingClass.substring(typeIndex + 1);
- // Getting an array of the matching input names
- // e.g. engrid__supporterquestions12345-present => ['supporter.questions.12345']
- // e.g. engrid__supporterquestions12345__supporterquestions67890-present => ['supporter.questions.12345', 'supporter.questions.67890']
- const inputIds = matchingClass
- .substring(8, typeIndex)
- .split("__")
- .map((id) => `supporter.questions.${id.substring(18)}`);
- actions.push({
- class: matchingClass,
- fieldNames: inputIds,
- type: type,
- });
- });
- //Process the actions
- actions.forEach((action) => {
- const inputElements = action.fieldNames.map((fieldName) => document.getElementsByName(fieldName)[0]);
- const elements = document.querySelectorAll(`.${action.class}`);
- const areAllInputsPresent = inputElements.every((input) => !!input);
- const areAllInputsAbsent = inputElements.every((input) => !input);
- // Hide the elements based on AND conditions
- if ((action.type === "present" && areAllInputsAbsent) ||
- (action.type === "absent" && areAllInputsPresent)) {
- this.logger.log(`Conditions not met, hiding elements with class ${action.class}`);
- elements.forEach((el) => {
- el.style.display = "none";
- });
- }
- });
+ }, 500);
+}
+function trackProcessingErrors(App) {
+ const errorList = document.querySelector(".en__errorList");
+ if (errorList && errorList.textContent.trim() !== "") {
+ trackEvent("form_error", {
+ form_field_error_field: "payment error",
+ form_field_error_value: "payment error",
+ payment_type: App.getPaymentType(),
+ form_name: typeof utag_data !== "undefined" ? utag_data.page_name.slice(0, -2) : "",
+ form_type: pageJson.pageType
+ });
+ }
+}
+function trackUrlParams() {
+ const params = new URLSearchParams(location.search);
+ const trackers = ["src", "vid", "vid2", "en_txn1", "en_txn2", "en_txn3", "en_txn4", "en_txn5", "en_txn7", "en_txn8", "en_txn9", "en_txn10"];
+ let visitData = sessionStorage.getItem("visitData") ? JSON.parse(sessionStorage.getItem("visitData")) : {};
+ trackers.forEach(tracker => {
+ if (params.has(tracker)) {
+ visitData[tracker] = params.get(tracker);
}
+ });
+ sessionStorage.setItem("visitData", JSON.stringify(visitData));
}
+function trackUserInteractions() {
+ // Track clicks on social share buttons
+ document.querySelectorAll(".en__socialShare__image").forEach(el => {
+ el.addEventListener("click", e => {
+ trackEvent("social_share", {
+ social_share_id: `preserve.nature.org.share.${e.target.parentElement.dataset.enshare}`,
+ social_share_platform: e.target.parentElement.dataset.enshare
+ });
+ });
+ });
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/en-validators.js
-// This component uses EN's Custom Validators on the client side to validate form fields.
-// It's currently behind a feature flag, so it's not enabled by default.
-// To enable it, add the following to your options:
-// ENValidators: true
+ // Track clicks on footer links
+ document.querySelectorAll(".main-page-footer a").forEach(el => {
+ el.addEventListener("click", e => {
+ trackEvent("footer_nav_click", {
+ nav_click_location: `preserve.nature.org.fnav.${e.target.textContent.toLowerCase()}`
+ });
+ });
+ });
-class ENValidators {
- constructor() {
- this._form = en_form_EnForm.getInstance();
- this._enElements = null;
- this.logger = new logger_EngridLogger("ENValidators", "white", "darkolivegreen", "π§");
- if (!this.loadValidators()) {
- // This is an error to flag a racing condition. If the script is loaded before the validators are loaded, it will not work.
- this.logger.error("Not Loaded");
- return;
- }
- if (!this.shouldRun()) {
- // If there's no custom validators, get out
- this.logger.log("Not Needed");
- return;
- }
- this._form.onValidate.subscribe(this.enOnValidate.bind(this));
- }
- loadValidators() {
- if (!engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enValidation", "validation", "validators")) {
- return false;
- }
- // Loop through the array validators and add them to this._enElements
- const validators = window.EngagingNetworks.require._defined.enValidation.validation
- .validators;
- this._enElements = validators.reduce((acc, validator) => {
- if ("type" in validator && validator.type === "CUST") {
- const container = document.querySelector(".en__field--" + validator.field);
- const field = container
- ? container.querySelector("input, select, textarea")
- : null;
- if (field) {
- field.addEventListener("input", this.liveValidate.bind(this, container, field, validator.regex, validator.message));
- acc.push({
- container: container,
- field: field,
- regex: validator.regex,
- message: validator.message,
- });
- }
- }
- return acc;
- }, []);
- return true;
- }
- // Should we run the script?
- shouldRun() {
- return (engrid_ENGrid.getOption("ENValidators") &&
- this._enElements &&
- this._enElements.length > 0);
- }
- // Don't submit the form if any of the fields are invalid
- enOnValidate() {
- if (!this._enElements || this._form.validate === false) {
- return;
- }
- this._enElements.forEach((element) => {
- const fieldValidation = this.liveValidate(element.container, element.field, element.regex, element.message);
- if (!fieldValidation) {
- this._form.validate = false;
- element.field.focus();
- return;
- }
+ // Track en upsell modal opening
+ const observer = new MutationObserver((mutationsList, observer) => {
+ for (const mutation of mutationsList) {
+ if (mutation.addedNodes) {
+ mutation.addedNodes.forEach(node => {
+ if (node.firstChild && node.firstChild.id === "en__upsellModal") {
+ //Track lightbox opened
+ trackEvent("lightbox_impression", {
+ lightbox_name: "sustainer upsell"
+ });
+ //Track if 'yes' is clicked on lightbox
+ document.getElementById("en__upsellModal__yes").addEventListener("click", () => {
+ trackEvent("lightbox_click", {
+ lightbox_name: "sustainer upsell"
+ });
+ });
+ observer.disconnect();
+ }
});
- this._form.validate = true;
- }
- // Validate the field on the fly
- liveValidate(container, field, regex, message) {
- const value = engrid_ENGrid.getFieldValue(field.getAttribute("name") || "");
- // Do not validate empty fields, that's the job of the required validator
- if (value === "") {
- return true;
- }
- this.logger.log(`Live Validate ${field.getAttribute("name")} with ${regex}`);
- // compare the value of the field with the regex
- if (!value.match(regex)) {
- // If the value is not valid, add the error message
- engrid_ENGrid.setError(container, message);
- return false;
- }
- // If the value is valid, remove the error message
- engrid_ENGrid.removeError(container);
- return true;
+ }
}
+ });
+ observer.observe(document, {
+ childList: true,
+ subtree: true
+ });
}
+;// CONCATENATED MODULE: ./src/scripts/main.js
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/modal.js
+const main_tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
+const customScript = function (App, DonationFrequency, DonationAmount) {
+ const freq = DonationFrequency.getInstance();
+ const amt = DonationAmount.getInstance();
+ console.log("ENGrid client scripts are executing");
+ // Add your client scripts here
+ var checkForServerError = document.querySelector(".en__errorList *");
+ if (checkForServerError) {
+ console.log("Has server error!");
+ } else {
+ console.log("Does not have a server error!");
-class Modal {
- constructor(options) {
- this.modal = null;
- this.defaultOptions = {
- onClickOutside: "close",
- addCloseButton: false,
- closeButtonLabel: "Okay!",
- customClass: "",
- showCloseX: true,
- };
- this.focusTrapHandler = (e) => {
- const modalElement = this.modal;
- const focusableElements = [
- ...modalElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),
- ];
- const firstFocusable = focusableElements[0];
- const lastFocusable = focusableElements[focusableElements.length - 1];
- const isTabPressed = e.key === "Tab";
- if (!isTabPressed) {
- return;
- }
- if (e.shiftKey) {
- if (document.activeElement === firstFocusable) {
- e.preventDefault();
- lastFocusable.focus();
- }
- }
- else {
- if (document.activeElement === lastFocusable) {
- e.preventDefault();
- firstFocusable.focus();
- }
- }
- };
- this.options = Object.assign(Object.assign({}, this.defaultOptions), options);
- this.modalContent = this.getModalContent();
- this.createModal();
- }
- createModal() {
- var _a;
- this.modal = document.createElement("div");
- this.modal.classList.add("engrid-modal", "modal--hidden");
- if (this.options.customClass && this.options.customClass !== "") {
- this.options.customClass.split(" ").forEach((customClass) => {
- if (!customClass)
- return;
- this.modal.classList.add(customClass);
- });
- }
- if (this.options.showCloseX) {
- this.modal.classList.add("engrid-modal--close-x");
- }
- this.modal.setAttribute("aria-hidden", "true");
- this.modal.setAttribute("role", "dialog");
- this.modal.setAttribute("aria-modal", "true");
- this.modal.setAttribute("tabindex", "-1");
- this.modal.innerHTML = `
-
- `;
- (_a = document.getElementById("engrid")) === null || _a === void 0 ? void 0 : _a.appendChild(this.modal);
- const modalBody = this.modal.querySelector(".engrid-modal__body");
- if (this.modalContent instanceof NodeList) {
- this.modalContent.forEach((content) => {
- modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(content);
- });
- }
- else if (typeof this.modalContent === "string") {
- modalBody === null || modalBody === void 0 ? void 0 : modalBody.insertAdjacentHTML("beforeend", this.modalContent);
- }
- else {
- modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(this.modalContent);
- }
- if (this.options.addCloseButton) {
- const button = document.createElement("button");
- button.classList.add("engrid-modal__button");
- button.textContent = this.options.closeButtonLabel;
- button.addEventListener("click", () => {
- this.close();
- });
- modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(button);
+ // Check if the first field is in the viewport
+ let firstElement = document.querySelector(".en__component--formblock");
+ if (firstElement) {
+ firstElement.id = "firstElement";
+ let bounding = firstElement.getBoundingClientRect();
+ if (bounding.top >= 0 && bounding.left >= 0 && bounding.right <= window.innerWidth && bounding.bottom <= window.innerHeight) {
+ console.log("First field is in the viewport!");
+ } else {
+ console.log("First field is NOT in the viewport! Add hover button");
+ const floatingButton = document.createElement("div");
+ const floatingButtonLabelElement = document.querySelector(".floating-button-label");
+ const floatingButtonLabel = floatingButtonLabelElement?.innerText ?? "Take Action";
+ floatingButton.id = "floating-button";
+ floatingButton.className = "arrow";
+ floatingButton.innerHTML = ``;
+ const advRow = document.querySelector(".en__component--advrow");
+ if (advRow) {
+ advRow.append(floatingButton);
}
- this.addEventListeners();
- }
- addEventListeners() {
- var _a, _b, _c, _d, _e;
- // Close event on top X
- (_b = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector(".engrid-modal__close")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", () => {
- this.close();
- });
- // Bounce scale when clicking outside of modal
- (_d = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector(".engrid-modal__overlay")) === null || _d === void 0 ? void 0 : _d.addEventListener("click", (event) => {
- if (event.target === event.currentTarget) {
- if (this.options.onClickOutside === "close") {
- this.close();
- }
- else if (this.options.onClickOutside === "bounce") {
- const modal = document.querySelector(".engrid-modal");
- if (modal) {
- modal.classList.remove("engrid-modal--scale");
- void modal.clientWidth;
- modal.classList.add("engrid-modal--scale");
- }
- }
- }
+ floatingButton.querySelector(".pseduo__en__submit_button").addEventListener("click", function (e) {
+ e.preventDefault();
+ document.querySelector("#firstElement").scrollIntoView({
+ behavior: "smooth",
+ block: "center"
+ });
});
- // Close on "modal__close" click
- const closeEls = (_e = this.modal) === null || _e === void 0 ? void 0 : _e.querySelectorAll(".modal__close");
- closeEls === null || closeEls === void 0 ? void 0 : closeEls.forEach((el) => {
- el.addEventListener("click", () => {
- this.close();
- });
+ document.addEventListener("scroll", function (e) {
+ const button = document.querySelector("#floating-button");
+ if (window.scrollY < 100) {
+ button.classList.add("show");
+ } else {
+ button.classList.remove("show");
+ }
});
+ window.setTimeout(() => {
+ if (window.scrollY < 100) {
+ floatingButton.classList.add("show");
+ }
+ }, 200);
+ }
}
- open() {
- var _a, _b, _c, _d;
- engrid_ENGrid.setBodyData("has-lightbox", "true");
- (_a = this.modal) === null || _a === void 0 ? void 0 : _a.classList.remove("modal--hidden");
- (_b = this.modal) === null || _b === void 0 ? void 0 : _b.removeAttribute("aria-hidden");
- const container = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector(".engrid-modal__container");
- container === null || container === void 0 ? void 0 : container.focus({ preventScroll: true });
- (_d = this.modal) === null || _d === void 0 ? void 0 : _d.addEventListener("keydown", this.focusTrapHandler);
- }
- close() {
- var _a, _b, _c;
- engrid_ENGrid.setBodyData("has-lightbox", false);
- (_a = this.modal) === null || _a === void 0 ? void 0 : _a.classList.add("modal--hidden");
- (_b = this.modal) === null || _b === void 0 ? void 0 : _b.setAttribute("aria-hidden", "true");
- (_c = this.modal) === null || _c === void 0 ? void 0 : _c.removeEventListener("keydown", this.focusTrapHandler);
+ }
+
+ ////////////////////////////////////////////
+ // START ENGRID TRANSITION SCRIPTS
+ ////////////////////////////////////////////
+ const texts = {
+ en: {
+ emailFieldNotice: "You'll receive email updates from The Nature Conservancy. You can unsubscribe at any time.",
+ phoneNumberNotice: "By sharing your phone number, you give The Nature Conservancy permission to contact you with updates via phone and text.",
+ cvvTooltipLabel: "What is a CVV number?",
+ cvvTooltip: "The CVV is a 3- or 4-digit code printed on your credit card. It's a fraud-prevention measure designed to make it harder to use info stolen in a data breach.",
+ bankNumberTooltipLabel: "What is this?",
+ bankNumberTooltip: "Your routing number is the 9-digit number at the bottom left of your check."
+ },
+ es: {
+ emailFieldNotice: "RecibirΓ‘s noticias de TNC periΓ³dicamente. Puedes cancelar tu suscripciΓ³n en cualquier momento.",
+ phoneNumberNotice: "Al compartir tu nΓΊmero telefΓ³nico, autorizas a TNC a contactarte y enviarte noticias por telΓ©fono o por mensaje de texto.",
+ cvvTooltipLabel: "ΒΏQuΓ© es un CVV?",
+ cvvTooltip: "El CVV es un cΓ³digo de 3 Γ³ 4 dΓgitos impreso en su tarjeta de crΓ©dito. Es una medida de prevenciΓ³n de fraude diseΓ±ada para dificultar el uso de informaciΓ³n robada en filtraciones de datos.",
+ bankNumberTooltipLabel: "ΒΏQuΓ© es esto?",
+ bankNumberTooltip: "Su nΓΊmero de ruta es el nΓΊmero de 9 dΓgitos que aparece en la parte inferior izquierda de su cheque."
}
- getModalContent() {
- return "Default Modal Content ";
+ };
+ const text = texts[window.pageJson.locale.slice(0, 2)] ?? texts.en;
+
+ // Position monthly upsell after the recurring frequency field
+ let inlineMonthlyUpsell = document.querySelector(".move-after--transaction-recurrfreq");
+ let recurrFrequencyField = document.querySelector(".en__field--recurrfreq");
+ if (inlineMonthlyUpsell && recurrFrequencyField) {
+ recurrFrequencyField.insertAdjacentElement("beforeend", inlineMonthlyUpsell);
+ }
+ const emailField = document.querySelector('[name="supporter.emailAddress"]');
+ if (emailField && emailField.type !== "hidden") {
+ // Add a notice to the email field
+ App.addHtml(`${text.emailFieldNotice}
`, '[name="supporter.emailAddress"]', "after");
+ }
+
+ // Add a notice to the phone number field
+ App.addHtml(`${text.phoneNumberNotice}
`, '[name="supporter.phoneNumber2"]', "after");
+
+ /**
+ * Add a Tippy tooltip to a field
+ * @param {HTMLElement} labelElement
+ * @param {string} fieldName
+ * @param {string} labelText
+ * @param {string} tooltipText
+ */
+ function addTooltip(labelElement, fieldName, labelText, tooltipText) {
+ if (!labelElement) {
+ return;
}
-}
+ let link = document.createElement("a");
+ link.href = "#";
+ link.id = fieldName + "-tooltip";
+ link.className = fieldName + "-tooltip tippy-label";
+ link.tabIndex = -1;
+ link.innerText = labelText;
+ link.addEventListener("click", e => e.preventDefault());
+ labelElement.insertAdjacentElement("afterend", link);
+ let wrapper = document.createElement("span");
+ wrapper.className = "label-wrapper";
+ labelElement.parentNode.insertBefore(wrapper, labelElement);
+ wrapper.appendChild(labelElement);
+ wrapper.appendChild(link);
+ main_tippy("#" + fieldName + "-tooltip", {
+ content: tooltipText,
+ theme: "light-border"
+ });
+ }
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/postal-code-validator.js
+ // Add a tooltip for the CVV number
+ addTooltip(document.querySelector(".en__field--ccvv > label"), "cvv", text.cvvTooltipLabel, text.cvvTooltip);
+ // Add a tooltip for the bank routing number
+ addTooltip(document.querySelector(".en__field--bankRoutingNumber > label"), "bankNumber", text.bankNumberTooltipLabel, text.bankNumberTooltip);
+ // Add a tooltip for Title
+ addTooltip(document.querySelector(".en__field--title > label"), "title", "Why do you ask for this?", "Many of our online actions link up with public officials' web mail forms in order to deliver your message on your behalf. Many of these public officials' forms require the Mr./Mrs./Miss field and, unfortunately, we do not have control over which of these titles are presented as options. We must adhere to what the officials are using in order for your message to be delivered.");
-// Conditionally validates the postcode field for a US format zip code
-// If US is selected as the country, a country has not been selected yet
-// or if there is no country field
-// Allows blank zip code if zip code is not required.
-class PostalCodeValidator {
- constructor() {
- var _a, _b;
- this.postalCodeField = engrid_ENGrid.getField("supporter.postcode");
- this._form = en_form_EnForm.getInstance();
- this.logger = new logger_EngridLogger("Postal Code Validator", "white", "red", "π¬");
- this.supportedSeparators = ["+", "-", " "];
- this.separator = this.getSeparator();
- this.regexSeparator = this.getRegexSeparator(this.separator);
- if (this.shouldRun()) {
- (_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.addEventListener("blur", () => this.validate());
- (_b = this.postalCodeField) === null || _b === void 0 ? void 0 : _b.addEventListener("input", () => this.liveValidate());
- this._form.onValidate.subscribe(() => {
- if (!this._form.validate)
- return;
- this.liveValidate();
- // It seems like we need some delay or EN removes our error message.
- setTimeout(() => {
- this.validate();
- }, 100);
- // We dont need to validate the zip code, or it is valid
- const postalCodeValid = !this.shouldValidateUSZipCode() || this.isValidUSZipCode();
- this._form.validate = postalCodeValid;
- if (!postalCodeValid) {
- this.logger.log(`Invalid Zip Code ${this.postalCodeField.value}`);
- this.postalCodeField.scrollIntoView({ behavior: "smooth" });
- }
- return postalCodeValid;
- });
- }
- }
- shouldRun() {
- return !!(engrid_ENGrid.getOption("PostalCodeValidator") && this.postalCodeField);
- }
- validate() {
- if (this.shouldValidateUSZipCode() && !this.isValidUSZipCode()) {
- engrid_ENGrid.setError(".en__field--postcode", `Please enter a valid ZIP Code of ##### or #####${this.separator}####`);
- }
- else {
- engrid_ENGrid.removeError(".en__field--postcode");
- }
- }
- isValidUSZipCode() {
- var _a, _b;
- const zipCodeRequired = !!document.querySelector(".en__field--postcode.en__mandatory");
- // If zip code is not required in EN Form Block and the field is empty, it is valid
- if (!zipCodeRequired && ((_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.value) === "") {
- return true;
- }
- const postalCodeRegex = new RegExp(`^\\d{5}(${this.regexSeparator}\\d{4})?$`);
- return !!((_b = this.postalCodeField) === null || _b === void 0 ? void 0 : _b.value.match(postalCodeRegex));
+ /**
+ * Set the visibility of the premium field based on the donation frequency and amount
+ * Visibility is set by adding/removing the "engrid-premium-donation" data attr on the body
+ * @param {string} frequency
+ * @param {number} amount
+ */
+ function setPremiumVisibility(frequency, amount) {
+ const monthlyPremiumMinimum = window?.donationSettings?.monthlyPremiumMinimum;
+ const onetimePremiumMinimum = window?.donationSettings?.onetimePremiumMinimum;
+ if (!monthlyPremiumMinimum || !onetimePremiumMinimum) {
+ return;
}
- /**
- * Formats the zip code to #####-#### as the user inputs it
- * The separator is determined by the TidyContact option, but defaults to "-"
- */
- liveValidate() {
- var _a;
- if (!this.shouldValidateUSZipCode())
- return;
- let value = (_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.value;
- // If the value is 5 characters or less, remove all non-numeric characters
- if (value.length <= 5) {
- value = value.replace(/\D/g, "");
- }
- // If one of the supported separators is endered as the 6th character, replace it with the official separator
- else if (value.length === 6 &&
- this.supportedSeparators.includes(value[5])) {
- // Removing all non-numeric characters
- value = value.replace(/\D/g, "") + this.separator;
- }
- else {
- // Removing all non-numeric characters
- value = value.replace(/\D/g, "");
- // Adding the separator after the 5th character
- value = value.replace(/(\d{5})(\d)/, `$1${this.separator}$2`);
- }
- //set field value with max 10 characters
- this.postalCodeField.value = value.slice(0, 10);
+ const monthlyPremiumField = App.getField("supporter.questions.1362488");
+ const premiumVisibleField = App.getField("supporter.questions.1366068");
+ if (!monthlyPremiumField || !premiumVisibleField) {
+ return;
}
- shouldValidateUSZipCode() {
- // Validating US zip code only if country is US, country has not yet been selected
- // or if there is no country field
- const country = engrid_ENGrid.getField("supporter.country")
- ? engrid_ENGrid.getFieldValue("supporter.country")
- : "US";
- return ["us", "united states", "usa", ""].includes(country.toLowerCase());
+ if (frequency === "monthly" && amount >= monthlyPremiumMinimum) {
+ App.setBodyData("premium-donation", "active");
+ monthlyPremiumField.checked = true;
+ premiumVisibleField.checked = true;
+ App.enParseDependencies();
+ } else if ((frequency === "onetime" || frequency === "annual") && amount >= onetimePremiumMinimum) {
+ App.setBodyData("premium-donation", "active");
+ monthlyPremiumField.checked = false;
+ premiumVisibleField.checked = true;
+ App.enParseDependencies();
+ } else {
+ App.setBodyData("premium-donation", "inactive");
+ monthlyPremiumField.checked = false;
+ premiumVisibleField.checked = false;
+ App.enParseDependencies();
}
- getSeparator() {
- const tidyContact = engrid_ENGrid.getOption("TidyContact");
- if (tidyContact &&
- tidyContact.us_zip_divider &&
- this.supportedSeparators.includes(tidyContact.us_zip_divider)) {
- return tidyContact.us_zip_divider;
+ }
+ function keepScrollPosition(elementBlock, direction = "up") {
+ if (!elementBlock) return;
+ const scrollY = window.scrollY;
+ const elementStyle = window.getComputedStyle(elementBlock);
+ const elementSize = parseInt(elementStyle.height, 10) + parseInt(elementStyle.marginTop.replace("px", "")) + parseInt(elementStyle.marginBottom.replace("px", ""));
+ window.setTimeout(() => {
+ window.scrollTo(0, direction === "up" ? scrollY - elementSize : scrollY + elementSize);
+ }, 100);
+ console.log(elementSize);
+ }
+
+ // If the frequency is annual, move the premium container content below the #en__field_auto_renew container
+ // If frequency is not annual, move the premium container content back to premium container
+ function movePremiumContainerContent(direction = "up") {
+ const premiumContainerContent = document.querySelector(".premium-container-content");
+ if (!premiumContainerContent) return;
+ const autoRenewField = document.getElementById("en__field_auto_renew");
+ const autoRenewContainer = autoRenewField?.closest(".en__component");
+ if (direction === "down") {
+ if (autoRenewContainer) {
+ autoRenewContainer.insertAdjacentElement("afterend", premiumContainerContent);
+ const multistepStep = autoRenewContainer.getAttribute("data-multistep-step");
+ if (multistepStep) {
+ premiumContainerContent.setAttribute("data-multistep-step", multistepStep);
}
- return "-";
+ }
+ } else {
+ const premiumContainer = document.querySelector(".premium-container");
+ // If the premium container is not found, or the premium container already contains the premium container content, return
+ if (!premiumContainer || premiumContainer.querySelector(".en__component--premiumgiftblock")) return;
+ premiumContainer.appendChild(premiumContainerContent);
+ premiumContainerContent.removeAttribute("data-multistep-step");
}
- getRegexSeparator(separator) {
- switch (separator) {
- case "+":
- return "\\+";
- case "-":
- return "-";
- case " ":
- return "\\s";
- default:
- this.logger.log(`Invalid separator "${separator}" provided to PostalCodeValidator, falling back to "-".`);
- return "-";
- }
+ }
+
+ // Listen for changes to the donation frequency and amount
+ freq.onFrequencyChange.subscribe(frequency => {
+ setPremiumVisibility(frequency, amt.amount);
+ if (frequency !== "annual") {
+ window.setTimeout(() => {
+ movePremiumContainerContent("up");
+ }, 100);
}
-}
+ });
+ amt.onAmountChange.subscribe(amount => {
+ setPremiumVisibility(freq.frequency, amount);
+ });
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/vgs.js
-// This component allows you to customize the VGS theme options
-//
-// It is used in the following way:
-//
-// VGS: {
-// "transaction.ccnumber": {
-// showCardIcon: true,
-// placeholder: "β’β’β’β’ β’β’β’β’ β’β’β’β’ β’β’β’β’",
-// icons: {
-// (icons can't be urls, they have to be base64 encoded images)
-// cardPlaceholder: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%233BBF45'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z'/%3E%3C/svg%3E"
-// visa: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath fill='%233BBF45' d='M384 32H0v448h384V32z'/%3E%3Cpath fill='white' d='M128.5 352.5l-32-192h-32l32 192zm96-192l-32 192h-32l32-192z'/%3E%3C/svg%3E",
-// },
-// },
-// "transaction.ccvv": {
-// showCardIcon: false,
-// placeholder: "CVV",
-// hideValue: false,
-// },
-// },
-//
-// The VGS component can also be set at the page level, if necessary
-//
+ // Move Premium donation elements into their container
+ let premiumDonationEls = document.querySelectorAll(".move-into--engrid-premium-container");
+ let premiumDonationContainer = document.querySelector(".engrid-premium-container");
+ if (premiumDonationEls.length > 0 && premiumDonationContainer) {
+ premiumDonationEls.forEach(el => {
+ premiumDonationContainer.appendChild(el);
+ });
+ }
-class VGS {
- constructor() {
- this.logger = new logger_EngridLogger("VGS", "black", "pink", "π³");
- this.vgsField = document.querySelector(".en__field--vgs");
- this.options = engrid_ENGrid.getOption("VGS");
- this.paymentTypeField = document.querySelector("#en__field_transaction_paymenttype");
- this._form = en_form_EnForm.getInstance();
- this.field_expiration_month = null;
- this.field_expiration_year = null;
- this.handleExpUpdate = (e) => {
- if (!this.field_expiration_month || !this.field_expiration_year)
- return;
- const current_date = new Date();
- const current_month = current_date.getMonth() + 1;
- const current_year = parseInt(this.field_expiration_year[this.field_expiration_year.length - 1].value) > 2000
- ? current_date.getFullYear()
- : current_date.getFullYear() - 2000;
- // handle if year is changed to current year (disable all months less than current month)
- // handle if month is changed to less than current month (disable current year)
- if (e == "month") {
- let selected_month = parseInt(this.field_expiration_month.value);
- let disable = selected_month < current_month;
- this.logger.log(`month disable ${disable}`);
- this.logger.log(`selected_month ${selected_month}`);
- for (let i = 0; i < this.field_expiration_year.options.length; i++) {
- // disable or enable current year
- if (parseInt(this.field_expiration_year.options[i].value) <= current_year) {
- if (disable) {
- this.field_expiration_year.options[i].setAttribute("disabled", "disabled");
- }
- else {
- this.field_expiration_year.options[i].disabled = false;
- }
- }
- }
- }
- else if (e == "year") {
- let selected_year = parseInt(this.field_expiration_year.value);
- let disable = selected_year == current_year;
- this.logger.log(`year disable ${disable}`);
- this.logger.log(`selected_year ${selected_year}`);
- for (let i = 0; i < this.field_expiration_month.options.length; i++) {
- // disable or enable all months less than current month
- if (parseInt(this.field_expiration_month.options[i].value) < current_month) {
- if (disable) {
- this.field_expiration_month.options[i].setAttribute("disabled", "disabled");
- }
- else {
- this.field_expiration_month.options[i].disabled = false;
- }
- }
- }
- }
- };
- if (!this.shouldRun())
- return;
- this.setPaymentType();
- this.setDefaults();
- this.dumpGlobalVar();
- const expireFiels = document.getElementsByName("transaction.ccexpire");
- if (expireFiels) {
- this.field_expiration_month = expireFiels[0];
- this.field_expiration_year = expireFiels[1];
+ // Make body-banner and images with attribution attribution clickable
+ const bbTippy = document.querySelectorAll(".body-banner figattribution, img.img-with-attribution[alt] + figattribution");
+ if (bbTippy) {
+ bbTippy.forEach(el => {
+ const tippyInstance = el?._tippy;
+ if (tippyInstance) {
+ tippyInstance.setProps({
+ arrow: false,
+ trigger: "click"
+ });
+ }
+ });
+ }
+
+ // Add data-thank-you attribute to body of final page
+ if (pageJson && pageJson.pageNumber === pageJson.pageCount && pageJson.pageCount > 1) {
+ App.setBodyData("thank-you", "true");
+ } else {
+ App.setBodyData("thank-you", "false");
+ }
+
+ // Auto renew
+ const autoRenew = document.getElementById("en__field_auto_renew");
+ if (autoRenew) {
+ const annualFrequencyOption = document.querySelector('input[name="transaction.recurrfreq"][value="ANNUAL"]');
+ const extRef2Input = document.querySelector('[name="en_txn2"]');
+ if (!annualFrequencyOption || !extRef2Input) {
+ // if recurring frequency option for annual is not found, we remove the auto renew checkbox and stop here
+ console.error("ENgrid: Annual frequency option or external reference field not found. Removing Auto Renew checkbox to prevent failed donations.");
+ autoRenew.closest(".en__field--auto-renew").remove();
+ } else {
+ annualFrequencyOption.parentElement.classList.add("hide");
+ App.setBodyData("auto-renew-on-page", "true");
+ App.setBodyData("auto-renew-active", autoRenew.checked.toString());
+ extRef2Input.value = autoRenew.checked ? "auto_renew" : "";
+ autoRenew.addEventListener("change", () => {
+ const autoRenewActive = autoRenew.checked;
+ if (autoRenewActive) {
+ movePremiumContainerContent("down");
}
- // Add event listeners to the expiration fields
- if (this.field_expiration_month && this.field_expiration_year) {
- ["change"].forEach((event) => {
- var _a, _b;
- (_a = this.field_expiration_month) === null || _a === void 0 ? void 0 : _a.addEventListener(event, () => {
- this.handleExpUpdate("month");
- });
- (_b = this.field_expiration_year) === null || _b === void 0 ? void 0 : _b.addEventListener(event, () => {
- this.handleExpUpdate("year");
- });
- });
+ });
+ freq.onFrequencyChange.subscribe(frequency => {
+ if (frequency === "annual") {
+ App.setBodyData("auto-renew-active", "true");
+ extRef2Input.value = "auto_renew";
+ } else {
+ App.setBodyData("auto-renew-active", "false");
+ extRef2Input.value = "";
}
- this._form.onValidate.subscribe(() => {
- if (this._form.validate) {
- const isValid = this.validate();
- this.logger.log(`Form Validation: ${isValid}`);
- this._form.validate = isValid;
- }
- });
- }
- shouldRun() {
- // Only run if the vgs field is present
- if (!this.vgsField)
- return false;
- return true;
+ });
}
- setDefaults() {
- //EN attempts to define a few default styles for VGS fields based on our text field styling
- //This does not always work, so we will provide our own defaults
- const bodyStyles = getComputedStyle(document.body);
- const styles = {
- fontFamily: bodyStyles.getPropertyValue("--input_font-family") ||
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'",
- fontSize: bodyStyles.getPropertyValue("--input_font-size") || "16px",
- color: bodyStyles.getPropertyValue("--input_color") || "#000",
- padding: bodyStyles.getPropertyValue("--input_padding") || "10px",
- "&::placeholder": {
- color: bodyStyles.getPropertyValue("--input_placeholder-color") || "#a9a9a9",
- opacity: bodyStyles.getPropertyValue("--input_placeholder-opacity") || "1",
- fontWeight: bodyStyles.getPropertyValue("--input_placeholder-font-weight") ||
- "normal",
- },
- };
- const options = this.options;
- const defaultOptions = {
- "transaction.ccnumber": {
- showCardIcon: true,
- placeholder: "β’β’β’β’ β’β’β’β’ β’β’β’β’ β’β’β’β’",
- icons: {
- cardPlaceholder: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAYAAADHl1ErAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB8ElEQVR4nO2c4W3CMBBGz1H/NyNkAzoCo2SDrkI3YJSOABt0g9IJXBnOqUkMyifUqkrek04RlvMjT2c7sc6EGKPBfBpcaSBMBGEiCBNBmAjCRBAmgjARhIkgTARhIggTQZhK2q0Yh5l1ZrYzs0PqsrI4+LN3VTeThkvntUm6Fbuxn2E/LITQmtm7mW08Sb/MbO9tpxhjui6WEMLWzJKDdO3N7Nmf9ZjaYoyn8y8X1o6GXxLV1lJyDeE+9oWPQ/ZRG4b9WkVVpqe+8LLLo7ErM6t248qllZnWBc+uV5+zumGsQjm3f/ic9tb4JGeeXcga4U723rptilVx0avgg2Q3m/JNn+y6zeAm+GSWUi/c7L5yfB77RJhACOHs6WnuLfmGpTI3YditEEGYCMJEECaCMJHZqySvHRfIMBGEiSBMBGEiCBNBmAjCRBAmgjARhIkgTGT2t+R/59EdYXZcfwmEiSBMBGEiCBNZzCr5VzvCZJjIIMxrPKFC6abMsHbaFcZuGq8StqKwDqZkN8emKBbrvawHCtxJ7y1nVxQF34lxUXBupOy8EtWy88jBhknUDjbkPhyd+Xn2l9lHZ8rgcNZVTA5nTYRFjv/dPf7HvzuJ8C0pgjARhIkgTARhIggTQZgIwkQQJoIwEYSJIEwEYQpm9g2Ro5zhLcuLBwAAAABJRU5ErkJggg==",
- },
- css: styles,
- // Autocomplete is not customizable
- autoComplete: "cc-number",
- validations: ["required", "validCardNumber"],
- validCardBrands: null
- },
- "transaction.ccvv": {
- showCardIcon: false,
- placeholder: "CVV",
- hideValue: false,
- // Autocomplete is not customizable
- autoComplete: "cc-csc",
- validations: ["required", "validCardSecurityCode"],
- css: styles,
- },
- "transaction.ccexpire": {
- placeholder: "MM/YY",
- autoComplete: "cc-exp",
- validations: ["required", "validCardExpirationDate"],
- css: styles,
- },
- };
- // Override the validCardBrands if set in the theme options, as this should not be deep merged.
- if (options &&
- options["transaction.ccnumber"] &&
- options["transaction.ccnumber"].validCardBrands) {
- defaultOptions["transaction.ccnumber"].validCardBrands = options["transaction.ccnumber"].validCardBrands;
- }
- // Deep merge the default options with the options set in the theme
- this.options = engrid_ENGrid.deepMerge(defaultOptions, options);
- this.logger.log("Options", this.options);
+ }
+
+ ////////////////////////////////////////////
+ // Spanish translation tweaks
+
+ // Translate recurring status
+ const recurringStatus = document.querySelector(".js-recurring-status");
+ if (recurringStatus) {
+ if (window.navigator.language === "es-MX" || window.location.href.indexOf("locale=es-MX") > -1 || pageJson.locale === "es-MX") {
+ console.log(recurringStatus.textContent);
+ switch (recurringStatus.textContent) {
+ case "MONTHLY":
+ recurringStatus.textContent = "Mensual";
+ break;
+ case "ANNUAL":
+ recurringStatus.textContent = "Anual";
+ break;
+ default:
+ recurringStatus.textContent = "Una vez";
+ }
+ } else {
+ switch (recurringStatus.textContent) {
+ case "MONTHLY":
+ recurringStatus.textContent = "Monthly";
+ break;
+ case "ANNUAL":
+ recurringStatus.textContent = "Annual";
+ break;
+ default:
+ recurringStatus.textContent = "One-time";
+ }
}
- setPaymentType() {
- // If there's no default payment type, set the default to card
- if (engrid_ENGrid.getPaymentType() === "") {
- engrid_ENGrid.setPaymentType("card");
- }
+ }
+ if (window?.pageJson?.locale === "es-MX") {
+ const donationAmountField = document.querySelector(".en__field--donationAmt");
+ if (donationAmountField) {
+ donationAmountField.style.setProperty("--give-monthly-donation-amount-appended-label", '"/MES"');
}
- dumpGlobalVar() {
- // Dump the global variable for the VGS options
- window.enVGSFields = this.options;
- // EN is not reading the global variable because their JS file loads before ENgrid, so we're going to HACK TOWN
- // Clean up the VGS iFrames
- window.setTimeout(() => {
- const vgsIElements = document.querySelectorAll(".en__field__input--vgs");
- if (vgsIElements.length > 0) {
- // Create a mutation observer that cleans the VGS Elements before anything is rendered
- const observer = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- var _a;
- if (mutation.type === "childList" &&
- mutation.addedNodes.length > 0) {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeName === "IFRAME" &&
- mutation.previousSibling &&
- mutation.previousSibling.nodeName === "IFRAME") {
- // Delete the previous sibling
- mutation.previousSibling.remove();
- }
- });
- }
- // Check if the VGS Element is valid, and remove any validation classes and errors
- if (mutation.type === "attributes" &&
- mutation.attributeName === "class") {
- const target = mutation.target;
- if (target.classList.contains("vgs-collect-container__valid")) {
- const fieldWrapper = target.closest(".en__field--vgs");
- fieldWrapper === null || fieldWrapper === void 0 ? void 0 : fieldWrapper.classList.remove("en__field--validationFailed");
- (_a = fieldWrapper === null || fieldWrapper === void 0 ? void 0 : fieldWrapper.querySelector(".en__field__error")) === null || _a === void 0 ? void 0 : _a.remove();
- }
- }
- });
- });
- // Observe the VGS Elements
- vgsIElements.forEach((vgsIElement) => {
- observer.observe(vgsIElement, {
- childList: true,
- attributeFilter: ["class"],
- });
- });
- if (engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "vgs")) {
- window.EngagingNetworks.require._defined.enjs.vgs.init();
- }
- else {
- this.logger.log("VGS is not defined");
- }
- }
- }, 1000);
+ }
+
+ // END Spanish translation tweaks
+
+ ////////////////////////////////////////////
+ // END ENGRID TRANSITION SCRIPTS
+ ////////////////////////////////////////////
+
+ /*
+ * Conditional content via URL parameters
+ * js-zcc--param--value
+ * ?crid=1234
+ * Will reveal all elements with class js-zcc--crid--1234
+ */
+ const urlParams = new URLSearchParams(window.location.search);
+ urlParams.forEach((value, param) => {
+ value = value.replace(/[^_a-zA-Z0-9-]/g, "_").toLowerCase();
+ param = param.replace(/[^_a-zA-Z0-9-]/g, "_").toLowerCase();
+ const conditionalElements = document.querySelectorAll(`.js-zcc--${param}--${value}`);
+ if (conditionalElements.length > 0) {
+ conditionalElements.forEach(el => {
+ el.classList.remove(`js-zcc--${param}--${value}`);
+ });
+ } else {
+ // If there no elements with the specified value, reveal all default elements for that parameter.
+ const defaultElements = document.querySelectorAll(`[class="js-zcc--${param}--default"]`);
+ defaultElements.forEach(el => {
+ el.classList.remove(`js-zcc--${param}--default`);
+ });
}
- validate() {
- if (this.paymentTypeField.value.toLowerCase() === "card" ||
- this.paymentTypeField.value.toLowerCase() === "visa" ||
- this.paymentTypeField.value.toLowerCase() === "vi") {
- const cardContainer = document.querySelector(".en__field--vgs.en__field--ccnumber");
- const cardEmpty = cardContainer === null || cardContainer === void 0 ? void 0 : cardContainer.querySelector(".vgs-collect-container__empty");
- const cvvContainer = document.querySelector(".en__field--vgs.en__field--ccvv");
- const cvvEmpty = cvvContainer === null || cvvContainer === void 0 ? void 0 : cvvContainer.querySelector(".vgs-collect-container__empty");
- if (cardContainer && cardEmpty) {
- window.setTimeout(() => {
- engrid_ENGrid.setError(cardContainer, "Please enter a valid card number");
- // Scroll to the error
- cardContainer.scrollIntoView({ behavior: "smooth" });
- }, 100);
- return false;
- }
- if (cvvContainer && cvvEmpty) {
- window.setTimeout(() => {
- engrid_ENGrid.setError(cvvContainer, "Please enter a valid CVV");
- // Scroll to the error
- cvvContainer.scrollIntoView({ behavior: "smooth" });
- }, 100);
- return false;
- }
- }
- return true;
+ });
+ // If there is no URL parameter, reveal all elements with class js-zcc--paramName--default class
+ const conditionalElements = document.querySelectorAll(`[class*="js-zcc--"]`);
+ conditionalElements.forEach(el => {
+ const className = [...el.classList].find(className => className.startsWith("js-zcc--") && className.endsWith("--default"));
+ if (!className) return;
+ const paramName = className.split("--")[1];
+ if (!urlParams.has(paramName)) {
+ el.classList.remove(className);
}
-}
+ });
+ // If there are any extra banner image elements being controlled by the URL parameters,
+ // we will remove them from the page (extra banner images inside body-banner will prevent the image showing)
+ const extraBannerImages = document.querySelectorAll(".body-banner img[class*='js-zcc--']");
+ extraBannerImages.forEach(img => {
+ img?.closest(".en__component--imageblock")?.remove();
+ });
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/country-redirect.js
-// This component allows you to redirect the user to a different page based on their country.
-// It works by checking the country field on the page and comparing it to the list of countries in the CountryRedirect option.
-// If the country matches one of the countries in the list, the user is redirected to the specified URL only if the URL is not the same as the current page.
-// The CountryRedirect option is an object with the country as the key and the URL as the value.
-// Example:
-//
-// CountryRedirect: {
-// US: "https://example.com/us",
-// CA: "https://example.com/ca",
-// GB: "https://example.com/gb",
-// },
-// The country codes must match the country codes in the country field
-// The CountryRedirect component can also be set at the page level. Useful for Regional Pages, with a Code Block like this:
-//
-//
-//
-// This will override the default CountryRedirect options for that page.
-//
+ /*
+ * Lock gift designation field when a specific value is passed in the URL
+ * and we are using the gift designation form block
+ */
+ const giftDesignationField = document.querySelector(".engrid-gift-designation #en__field_supporter_appealCode");
+ const appealCode = urlParams.get("supporter.appealCode");
+ if (giftDesignationField && appealCode) {
+ const giftDesignationNeededMostCheckbox = document.querySelector("#en__field_supporter_questions_8785940");
+ const giftDesignationChooseCheckbox = document.querySelector("#en__field_supporter_questions_8785941");
+ if (giftDesignationNeededMostCheckbox && giftDesignationChooseCheckbox) {
+ giftDesignationChooseCheckbox.addEventListener("change", () => {
+ if (giftDesignationChooseCheckbox.checked) {
+ giftDesignationField.value = appealCode;
+ }
+ });
+ }
+ // if the gift designation field is a select field,
+ // and it doesnt have the url param value in its options, make that option and select it
+ if (giftDesignationField.tagName === "SELECT") {
+ let option = giftDesignationField.querySelector(`option[value="${appealCode}"]`);
+ if (!option) {
+ option = document.createElement("option");
+ option.value = appealCode;
+ option.text = appealCode;
+ giftDesignationField.appendChild(option);
+ giftDesignationField.value = appealCode;
+ giftDesignationChooseCheckbox.checked = true;
+ }
+ giftDesignationField.closest(".en__field")?.classList.add("hide");
+ const label = document.querySelector("[for='en__field_supporter_questions_8785941']");
+ if (label) {
+ label.innerHTML = `I would like to designate my gift to ${option.innerText}.`;
+ }
+ }
+ }
-class CountryRedirect {
- constructor() {
- this.logger = new logger_EngridLogger("CountryRedirect", "white", "brown", "π«");
- this._country = Country.getInstance();
- if (!this.shouldRun())
- return;
- this._country.onCountryChange.subscribe((country) => {
- this.checkRedirect(country);
+ /*
+ * Make image selects on surveys into checkboxes
+ * "engrid-checkboxes" needs to be somewhere inside the "reference name" field of the question
+ */
+ const imageSelectQuestions = document.querySelectorAll(".en__field--imgselect[class*='engrid-checkboxes']");
+ imageSelectQuestions.forEach((question, i) => {
+ const inputs = question.querySelectorAll("input[type='radio']");
+ if (inputs.length === 0) return;
+ question.className.split(" ").forEach(className => {
+ // Remove the en__field--numbers class to prevent validation
+ if (className.match(/en__field--\d+/)) {
+ question.classList.remove(className);
+ }
+ });
+ const hiddenInput = App.createHiddenInput(inputs[0].name);
+ question.appendChild(hiddenInput);
+ inputs.forEach(input => {
+ input.type = "checkbox";
+ input.name = `${input.name}-${i}`;
+ input.addEventListener("change", () => {
+ const checkedValues = [];
+ inputs.forEach(input => {
+ if (input.checked) {
+ checkedValues.push(input.value);
+ }
+ hiddenInput.value = checkedValues.join(",");
});
- this.checkRedirect(this._country.country); // This will check the redirect when the page loads
+ });
+ });
+ });
+
+ // Select donation amount based on URL parameter
+ const donationIndex = new URLSearchParams(window.location.search).get("donationIndex");
+ if (donationIndex) {
+ const donationAmounts = document.querySelectorAll('input[name="transaction.donationAmt"]');
+ if (donationAmounts[donationIndex]) {
+ amt.setAmount(donationAmounts[donationIndex].value);
}
- shouldRun() {
- // Only run if the CountryRedirect option is not false and the country field is present
- if (!engrid_ENGrid.getOption("CountryRedirect") || !this._country.countryField) {
- return false;
+ }
+ const bannerImageSrc = document.querySelector(".body-banner img")?.src;
+ const bodyBanner = document.querySelector(".body-banner");
+ if (bodyBanner && bannerImageSrc) {
+ bodyBanner.style.setProperty("--banner-image-src", `url(${bannerImageSrc})`);
+ }
+
+ // Set the donation amount in sessionStorage when the mobile wallet iframe is focused
+ const mobileWalletContainer = document.getElementById("en__digitalWallet");
+ if (mobileWalletContainer) {
+ const dataListener = () => {
+ const iframe = mobileWalletContainer.getElementsByTagName("iframe");
+ if (document.activeElement === iframe[0]) {
+ setDonationDataSessionStorage(App, DonationAmount);
+ window.removeEventListener("blur", dataListener);
+ }
+ };
+ window.addEventListener("blur", dataListener);
+ }
+
+ // Set the donation amount in sessionStorage when DAF (Chariot) button is clicked
+ const chariotButton = document.getElementById("chariot-button");
+ if (chariotButton) {
+ chariotButton.addEventListener("click", () => {
+ setDonationDataSessionStorage(App, DonationAmount);
+ });
+ } else {
+ const chariotObserver = new MutationObserver(mutationsList => {
+ for (const mutation of mutationsList) {
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+ mutation.addedNodes.forEach(node => {
+ if (node.nodeType === Node.ELEMENT_NODE && node.id && node.id === "chariot-button") {
+ node.addEventListener("click", () => {
+ setDonationDataSessionStorage(App, DonationAmount);
+ });
+ chariotObserver.disconnect();
+ }
+ });
}
- return true;
+ }
+ });
+ chariotObserver.observe(document.querySelector(".en__component--page"), {
+ childList: true,
+ subtree: true
+ });
+ }
+
+ // Accordion functionality
+ const accordion = document.querySelectorAll(".accordion-header");
+ accordion.forEach(button => {
+ button.addEventListener("click", function () {
+ const button = this.querySelector(".accordion-button");
+ button.classList.toggle("collapsed");
+ const panel = this.nextElementSibling;
+ panel.classList.toggle("show");
+ document.querySelectorAll(".accordion-item").forEach(el => {
+ if (el.contains(button)) return;
+ el.querySelector(".accordion-button").classList.add("collapsed");
+ el.querySelector(".accordion-collapse").classList.remove("show");
+ });
+ });
+ });
+ const premiumHeader2 = document.querySelector(".premium-theme-2 .premium-theme-2-header");
+ const premiumHeader3 = document.querySelector(".premium-theme-3 .premium-theme-3-header");
+ const maxMyGift = () => {
+ // If the selectedPremiumId is zero, we will maximize the gift
+ const maxRadio = document.querySelector(".en__pg:last-child input[type='radio'][name='en__pg'][value='0']");
+ const premiumTheme3Image = document.querySelector(".premium-theme-3 .premium-theme-3-image");
+ if (maxRadio) {
+ maxRadio.checked = true;
+ maxRadio.click();
+ setTimeout(() => {
+ App.setFieldValue("transaction.selprodvariantid", "");
+ }, 150);
}
- checkRedirect(country) {
- const countryRedirect = engrid_ENGrid.getOption("CountryRedirect");
- // Check if the country is in the list and if the current URL is not the same as the redirect URL
- // We are using includes because the URL might have query parameters
- if (countryRedirect &&
- country in countryRedirect &&
- window.location.href.includes(countryRedirect[country]) === false) {
- this.logger.log(`${country}: Redirecting to ${countryRedirect[country]}`);
- let redirectUrl = new URL(countryRedirect[country]);
- // If the redirect URL doesn't contain "?chain", add it
- if (!redirectUrl.search.includes("chain")) {
- redirectUrl.search += (redirectUrl.search ? "&" : "?") + "chain";
- }
- window.location.href = redirectUrl.href;
+ if (premiumTheme3Image) {
+ premiumTheme3Image.style.backgroundImage = "var(--premium_image_theme_3)";
+ }
+ };
+ const setDefaultPremium = () => {
+ if ("selectedPremiumId" in window) {
+ if (window.selectedPremiumId > 0) {
+ // We will not maximize the gift if the selectedPremiumId is already set
+ const premiumFound = selectPremiumById(window.selectedPremiumId);
+ if (!premiumFound) {
+ const firstGift = document.querySelector(".en__pg:first-child input[type='radio'][name='en__pg']");
+ if (firstGift && firstGift.value) selectPremiumById(firstGift.value);
}
+ return;
+ } else {
+ // If the selectedPremiumId is zero, we will maximize the gift
+ maxMyGift();
+ }
+ } else {
+ // If the selectedPremiumId is not set, we will select the first gift
+ const firstGift = document.querySelector(".en__pg:first-child input[type='radio'][name='en__pg']");
+ if (firstGift && firstGift.value) selectPremiumById(firstGift.value);
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/welcome-back.js
-/**
- * This component adds a welcome back message and a personal details summary to the page.
- * It depends on the "fast-personal-details" functionality from the FastFormFill component.
- * The component will only run, when the "WelcomeBack" option is set,
- * if the "fast-personal-details" class is present on the page and the FastFormFill conditions
- * are met (all mandatory inputs in that block are filled).
- *
- * All the text content and positioning is configurable through the "WelcomeBack" option.
- */
+ };
+ const selectPremiumById = premiumId => {
+ const selectedGift = document.querySelector(`input[type="radio"][name="en__pg"][value="${premiumId}"]`);
+ if (selectedGift) {
+ window.setTimeout(() => {
+ selectedGift.click();
+ }, 10);
+ const engridPremiumYes = document.querySelector("#engrid_premium_yes");
+ const engridPremiumNo = document.querySelector("#engrid_premium_no");
+ if (engridPremiumNo) {
+ engridPremiumNo.checked = false;
+ }
+ if (engridPremiumYes) {
+ engridPremiumYes.checked = true;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ };
+ const premiumBlock = document.querySelector(".en__component--premiumgiftblock");
+ if (premiumBlock) {
+ // Create a Premium Container
+ const premiumContainer = document.createElement("div");
+ premiumContainer.classList.add("premium-container");
+ premiumContainer.classList.add("en__component");
+ const premiumContainerContent = document.createElement("div");
+ premiumContainerContent.classList.add("premium-container-content");
+ premiumContainerContent.classList.add("en__component");
+ premiumContainer.appendChild(premiumContainerContent);
+ // Add the Premium Container after the Premium Block, then move the Premium Block inside the Premium Container
+ premiumBlock.insertAdjacentElement("afterend", premiumContainer);
+ premiumContainerContent.appendChild(premiumBlock);
+ //listen for the change event of name "en__pg" using event delegation
+ let selectedPremiumId = "selectedPremiumId" in window ? window.selectedPremiumId : null;
+ let selectedVariantId = null;
+ ["change", "click"].forEach(event => {
+ premiumBlock.addEventListener(event, e => {
+ setTimeout(() => {
+ const selectedGift = document.querySelector('[name="en__pg"]:checked');
+ if (selectedGift) {
+ const selectedGiftImage = selectedGift.closest(".en__pg").querySelector("img");
+ const premiumTheme3Image = document.querySelector(".premium-theme-3 .premium-theme-3-image");
+ if (premiumTheme3Image) {
+ premiumTheme3Image.dataset.selectedGift = selectedGift.value;
+ if (selectedGiftImage) {
+ premiumTheme3Image.style.backgroundImage = `url(${selectedGiftImage.src})`;
+ } else {
+ premiumTheme3Image.style.backgroundImage = "var(--premium_image_theme_3)";
+ }
+ }
+ selectedPremiumId = selectedGift.value;
+ selectedVariantId = App.getFieldValue("transaction.selprodvariantid");
+ sessionStorage.setItem("selectedPremiumId", selectedPremiumId);
+ sessionStorage.setItem("selectedVariantId", selectedVariantId);
+ if (parseInt(selectedPremiumId) > 0) window.selectedPremiumId = selectedPremiumId;
+ }
+ }, 250);
+ });
+ });
-class WelcomeBack {
- constructor() {
- var _a;
- this._form = en_form_EnForm.getInstance();
- this.supporterDetails = {};
- this.options = (_a = engrid_ENGrid.getOption("WelcomeBack")) !== null && _a !== void 0 ? _a : false;
- this.rememberMeEvents = RememberMeEvents.getInstance();
- this.hasRun = false;
- if (!this.shouldRun())
- return;
- if (engrid_ENGrid.getOption("RememberMe")) {
- this.rememberMeEvents.onLoad.subscribe(() => {
- this.run();
- });
- this.rememberMeEvents.onClear.subscribe(() => {
- this.resetWelcomeBack();
- });
+ // Mutation observer to check if the "Maximized Their Gift" radio button is present. If it is, hide it.
+ const observer = new MutationObserver(mutationsList => {
+ //loop over the mutations and if we're adding a radio with the "checked" attribute, remove that attribute so nothing gets re-selected
+ //when the premiums list is re-rendered
+ for (const mutation of mutationsList) {
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+ mutation.addedNodes.forEach(node => {
+ if (typeof node.querySelector !== "function") return;
+ const preSelectedRadio = node.querySelector("input[checked]");
+ if (preSelectedRadio) {
+ preSelectedRadio.removeAttribute("checked");
+ }
+ });
}
- else {
- this.run();
+ }
+ if (mutationsList.some(mutation => mutation.type === "childList")) {
+ // Re-select the previously selected gift when gift list is re-rendered
+ // If gift no longer exists, choose maximize my gift
+ if (selectedPremiumId && selectedVariantId) {
+ const selectedGift = document.querySelector(`input[type="radio"][name="en__pg"][value="${selectedPremiumId}"]`);
+ if (selectedGift) {
+ selectedGift.click();
+ window.setTimeout(() => {
+ App.setFieldValue("transaction.selprodvariantid", selectedVariantId);
+ }, 100);
+ } else {
+ setDefaultPremium();
+ }
+ } else {
+ setDefaultPremium();
+ }
+ }
+ });
+ // Start observing the target node for configured mutations
+ observer.observe(premiumBlock, {
+ attributes: true,
+ childList: true,
+ subtree: true
+ });
+ }
+ // Premium Gifts Theme 2 Script
+ if (premiumHeader2) {
+ const yesButton = premiumHeader2.querySelector("#engrid_premium_yes");
+ const noButton = premiumHeader2.querySelector("#engrid_premium_no");
+ if (yesButton && noButton) {
+ yesButton.addEventListener("click", function () {
+ const yesChecked = yesButton.checked;
+ noButton.checked = !yesChecked;
+ if (!yesChecked) {
+ maxMyGift();
+ } else {
+ setDefaultPremium();
+ }
+ });
+ noButton.addEventListener("click", function () {
+ const noChecked = noButton.checked;
+ yesButton.checked = !noChecked;
+ if (noChecked) {
+ maxMyGift();
}
+ });
}
- run() {
- if (this.hasRun)
- return;
- this.hasRun = true;
- this.supporterDetails = {
- firstName: engrid_ENGrid.getFieldValue("supporter.firstName"),
- lastName: engrid_ENGrid.getFieldValue("supporter.lastName"),
- emailAddress: engrid_ENGrid.getFieldValue("supporter.emailAddress"),
- address1: engrid_ENGrid.getFieldValue("supporter.address1"),
- address2: engrid_ENGrid.getFieldValue("supporter.address2"),
- city: engrid_ENGrid.getFieldValue("supporter.city"),
- region: engrid_ENGrid.getFieldValue("supporter.region"),
- postcode: engrid_ENGrid.getFieldValue("supporter.postcode"),
- country: engrid_ENGrid.getFieldValue("supporter.country"),
- mobilePhone: engrid_ENGrid.getFieldValue("supporter.phoneNumber2"),
- };
- this.addWelcomeBack();
- this.addPersonalDetailsSummary();
- this.addEventListeners();
- }
- shouldRun() {
- return (!!document.querySelector(".fast-personal-details") &&
- engrid_ENGrid.getBodyData("embedded") !== "thank-you-page-donation" &&
- this.options !== false);
- }
- addWelcomeBack() {
- var _a;
- if (typeof this.options !== "object" ||
- !this.options.welcomeBackMessage.display)
- return;
- const options = this.options.welcomeBackMessage;
- const welcomeBack = document.createElement("div");
- welcomeBack.classList.add("engrid-welcome-back", "showif-fast-personal-details");
- const title = options.title.replace("{firstName}", this.supporterDetails["firstName"]);
- welcomeBack.innerHTML = `
- ${title}
- ${options.editText}
-
`;
- (_a = document
- .querySelector(options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(options.placement, welcomeBack);
+ const premiumContainerContent = document.querySelector(".premium-container-content");
+ if (premiumContainerContent) {
+ // Move premiumHeader2 to the start of the premiumContainerContent
+ premiumContainerContent.insertBefore(premiumHeader2, premiumContainerContent.firstChild);
}
- resetWelcomeBack() {
- const inputs = document.querySelectorAll(".fast-personal-details .en__field__input");
- inputs.forEach((input) => {
- if (input.type === "checkbox" || input.type === "radio") {
- input.checked = false;
- }
- else {
- input.value = "";
- }
- });
- this.supporterDetails = {};
- engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
- remove("engrid-autofill");
+ }
+ // END Premium Gifts Theme 2 Script
+ // Premium Gifts Theme 3 Script
+ if (premiumHeader3) {
+ const premium3ItemsContainer = document.querySelector(".premium-theme-3 .premium-theme-3-items-container");
+ const premiumgiftblock = document.querySelector(".en__component--premiumgiftblock");
+ const premiumContainerContent = document.querySelector(".premium-container-content");
+ // Move premium gift block to the premium items container
+ if (premiumgiftblock && premium3ItemsContainer) {
+ premium3ItemsContainer.innerHTML = "";
+ premium3ItemsContainer.appendChild(premiumgiftblock);
+ if (premiumContainerContent) {
+ premiumContainerContent.appendChild(premiumHeader3);
+ }
}
- addPersonalDetailsSummary() {
- var _a;
- if (typeof this.options !== "object" ||
- !this.options.personalDetailsSummary.display)
- return;
- let options = this.options.personalDetailsSummary;
- const personalDetailsSummary = document.createElement("div");
- personalDetailsSummary.classList.add("engrid-personal-details-summary", "showif-fast-personal-details");
- personalDetailsSummary.innerHTML = `${options.title} `;
- personalDetailsSummary.insertAdjacentHTML("beforeend", `
-
- ${this.supporterDetails["firstName"]} ${this.supporterDetails["lastName"]}
-
- ${this.supporterDetails["emailAddress"]}
- ${this.supporterDetails["mobilePhone"] && options.showPhoneNumber
- ? ` ${this.supporterDetails["mobilePhone"]}`
- : ""}
-
- `);
- if (this.supporterDetails["address1"] &&
- this.supporterDetails["city"] &&
- this.supporterDetails["region"] &&
- this.supporterDetails["postcode"]) {
- personalDetailsSummary.insertAdjacentHTML("beforeend", `
-
- ${this.supporterDetails["address1"]} ${this.supporterDetails["address2"]}
-
- ${this.supporterDetails["city"]}, ${this.supporterDetails["region"]}
- ${this.supporterDetails["postcode"]}
-
- `);
+ }
+ // END Premium Gifts Theme 3 Script
+ // Limit premium availability to U.S. addresses only - START
+ if ("pageJson" in window && "pageType" in window.pageJson && window.pageJson.pageType === "premiumgift") {
+ const country = App.getField("supporter.country");
+ const selectPremiumFromSession = () => {
+ const selectedPremiumId = window.selectedPremiumId || sessionStorage.getItem("selectedPremiumId") || null;
+ const selectedVariantId = sessionStorage.getItem("selectedVariantId");
+ if (selectedPremiumId && selectedVariantId) {
+ const selectedGift = document.querySelector(`input[type="radio"][name="en__pg"][value="${selectedPremiumId}"]`);
+ if (selectedGift) {
+ selectedGift.click();
+ window.setTimeout(() => {
+ App.setFieldValue("transaction.selprodvariantid", selectedVariantId);
+ }, 100);
}
- personalDetailsSummary.insertAdjacentHTML("beforeend", `
- ${options.editText}
- `);
- (_a = document
- .querySelector(options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(options.placement, personalDetailsSummary);
- }
- addEventListeners() {
- document
- .querySelectorAll(".engrid-reset-welcome-back")
- .forEach((element) => {
- element.addEventListener("click", () => {
- this.resetWelcomeBack();
- });
- });
- this._form.onValidate.subscribe(this.enOnValidate.bind(this));
- this._form.onValidate.subscribe(() => {
- window.setTimeout(this.doubleCheckValidation.bind(this), 150);
- });
+ }
+ };
+ const disablePremiumBlock = (message = "Gifts Disabled") => {
+ const premiumBlock = document.querySelector(".premium-theme-3-header, .en__component--premiumgiftblock");
+ if (!premiumBlock || premiumBlock.dataset.dataAnnualDisabled === "true") {
+ return;
+ }
+ if (!premiumBlock.hasAttribute("disabled")) {
+ // Keep the page scroll position when the premium block is disabled (hidden)
+ keepScrollPosition(premiumBlock, "up");
+ premiumBlock.setAttribute("disabled", "disabled");
+ premiumBlock.setAttribute("aria-disabled", "true");
+ premiumBlock.setAttribute("data-disabled-message", message);
+ }
+ };
+ const enablePremiumBlock = () => {
+ const premiumBlock = document.querySelector(".premium-theme-3-header, .en__component--premiumgiftblock");
+ if (!premiumBlock || premiumBlock.dataset.dataAnnualDisabled === "true") {
+ return;
+ }
+ if (premiumBlock.hasAttribute("disabled")) {
+ // Keep the page scroll position when the premium block is enabled (shown)
+ const scrollY = window.scrollY;
+ const premiumStyle = window.getComputedStyle(premiumBlock);
+ premiumBlock.removeAttribute("disabled");
+ premiumBlock.removeAttribute("aria-disabled");
+ premiumBlock.removeAttribute("data-disabled-message");
+ const premiumSize = parseInt(premiumStyle.height, 10) + parseInt(premiumStyle.marginTop.replace("px", "")) + parseInt(premiumStyle.marginBottom.replace("px", ""));
+ window.scrollTo(0, scrollY + premiumSize);
+ console.log(premiumSize);
+ }
+ };
+ const addCountryNotice = () => {
+ if (!document.querySelector(".en__field--country .en__field__notice")) {
+ App.addHtml('Note: We are unable to mail thank-you gifts to donors outside the United States and its territories and have selected the "Maximize my gift" option for you.
', ".en__field--country .en__field__element", "after");
+ }
+ };
+ const removeCountryNotice = () => {
+ App.removeHtml(".en__field--country .en__field__notice");
+ };
+ if (!window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed()) {
+ setDefaultPremium();
+ } else {
+ window.setTimeout(() => {
+ selectPremiumFromSession();
+ }, 1000);
}
- enOnValidate() {
- if (!this._form.validate) {
- // Disable the fast personal details if the form is invalidated by other components running before
- engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
- return;
- }
- const regionField = engrid_ENGrid.getField("supporter.region");
- const regionFieldValue = regionField ? regionField.value : "";
- const regionFieldType = regionField === null || regionField === void 0 ? void 0 : regionField.tagName.toLowerCase();
- const regionFieldLabel = document.querySelector(".en__field--region label");
- if (regionFieldType === "select" &&
- regionFieldLabel &&
- regionFieldValue === "") {
- engrid_ENGrid.setError(".en__field--region", `${regionFieldLabel.innerText} is required`);
- engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
- this._form.validate = false;
+ if (App.getUrlParameter("premium") !== "international" && country) {
+ if (country.value !== "US") {
+ const countryText = country.options[country.selectedIndex].text;
+ setDefaultPremium();
+ disablePremiumBlock(`Gifts Disabled in ${countryText}`);
+ addCountryNotice();
+ }
+ country.addEventListener("change", () => {
+ if (country.value !== "US") {
+ const countryText = country.options[country.selectedIndex].text;
+ setDefaultPremium();
+ disablePremiumBlock(`Gifts Disabled in ${countryText}`);
+ addCountryNotice();
+ } else {
+ enablePremiumBlock();
+ removeCountryNotice();
}
- else {
- // Remove the error message if the region field is filled
- engrid_ENGrid.removeError(".en__field--region");
+ });
+ freq.onFrequencyChange.subscribe(s => {
+ if (country.value !== "US") {
+ const countryText = country.options[country.selectedIndex].text;
+ setDefaultPremium();
+ disablePremiumBlock(`Gifts Disabled in ${countryText}`);
+ } else {
+ enablePremiumBlock();
}
+ });
}
- doubleCheckValidation() {
- // Disable the fast personal details if the form is invalidated by other components running AFTER
- // the fast personal details component
- const validationError = document.querySelector(".fast-personal-details .en__field--validationFailed");
- if (validationError) {
- engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
- validationError.scrollIntoView({
- behavior: "smooth",
- block: "center",
- });
- }
- return;
+ // Look for a .no-premium-image image, if found set the --maximize_my_donation_image and delete the .no-premium-image image block (which is the closest .en__component--imageblock)
+ const noPremiumImage = document.querySelector(".no-premium-image");
+ if (noPremiumImage) {
+ const premiumImageContainer = document.querySelector(".en__component--premiumgiftblock, .premium-theme-3-image");
+ premiumImageContainer.style.setProperty("--maximize_my_donation_image", `url(${noPremiumImage.src})`);
+ premiumImageContainer.style.setProperty("--premium_image_theme_3", `url(${noPremiumImage.src})`);
+ noPremiumImage.closest(".en__component--imageblock")?.remove();
}
-}
+ }
+ // Limit premium availability to U.S. addresses only - END
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/ecard-to-target-options.js
-const EcardToTargetOptionsDefaults = {
- targetName: "",
- targetEmail: "",
- hideSendDate: true,
- hideTarget: true,
- hideMessage: true,
- addSupporterNameToMessage: false,
- targets: [],
-};
+ // Premium form shipping block - START
+ const shippingCheckbox = document.querySelector("#en__field_supporter_questions_2133569");
+ shippingCheckbox?.addEventListener("change", function () {
+ const shippingEnabled = document.querySelector("#en__field_transaction_shipenabled");
+ if (shippingEnabled) {
+ shippingEnabled.checked = !this.checked;
+ shippingEnabled.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ }
+ });
+ // Premium form shipping block - END
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/ecard-to-target.js
-/**
- * This component adjusts an ecard form to target a specific recipient,
- * defined in a code block
- */
+ // Move text to below the Premium Gift Header.
+ const pgInfo = document.querySelector(".insert-after--pg-header");
+ const pgHeader = document.querySelector(".en__pgHeader");
+ if (pgHeader && pgInfo) {
+ pgHeader.insertAdjacentElement("afterend", pgInfo);
+ }
+ // Set specific placeholders
+ const creditCardField = document.querySelector('input[name="supporter.creditCardHolderName"]');
+ if (creditCardField) {
+ creditCardField.setAttribute("placeholder", "Card Holder Name");
+ }
+ const accountHolderField = document.querySelector('input[name="supporter.NOT_TAGGED_79"]');
+ if (accountHolderField) {
+ accountHolderField.setAttribute("placeholder", "Account Holder's Name");
+ }
+ const bankNameField = document.querySelector('input[name="transaction.bankname"]');
+ if (bankNameField) {
+ bankNameField.setAttribute("placeholder", "Bank Name");
+ }
+ // Add placeholder to the Mobile Phone Field
+ let enFieldMobilePhone = document.querySelector("input#en__field_supporter_phoneNumber2");
+ if (enFieldMobilePhone) {
+ enFieldMobilePhone.placeholder = enFieldMobilePhone.closest(".en__field")?.classList.contains("en__mandatory") ? "Mobile / Phone" : "Mobile / Phone (Optional)";
+ }
+ const observerConfig = {
+ attributes: true,
+ attributeFilter: ["placeholder", "aria-required"],
+ subtree: true
+ };
+ const updatePlaceholder = field => {
+ if (field.name === "transaction.donationAmt.other") {
+ return; // Exclude specific field
+ }
+ const isFieldRequired = field.required || field.getAttribute("aria-required") === "true" || field.closest(".en__component--formblock.i-required");
+ const placeholder = field.getAttribute("placeholder");
+ if (placeholder) {
+ if (isFieldRequired && !placeholder.endsWith("*")) {
+ field.setAttribute("placeholder", `${placeholder}*`);
+ } else if (!isFieldRequired && placeholder.endsWith("*")) {
+ field.setAttribute("placeholder", placeholder.slice(0, -1));
+ }
+ }
+ };
+ // Update required fields
+ const fields = document.querySelectorAll("input[placeholder], textarea[placeholder]");
+ fields.forEach(field => {
+ updatePlaceholder(field);
+ // Observe placeholder and aria-required changes
+ const observer = new MutationObserver(() => updatePlaceholder(field));
+ observer.observe(field, observerConfig);
+ });
+ //Allow override of pre-selected NSG amount
+ function setPreselectedAmountFromUrl() {
+ const hiddenInput = document.querySelector('input[name="transaction.donationAmt.sgid"]');
-class EcardToTarget {
- constructor() {
- this.options = EcardToTargetOptionsDefaults;
- this.logger = new logger_EngridLogger("EcardToTarget", "DarkBlue", "Azure", "π§");
- this._form = en_form_EnForm.getInstance();
- this.supporterNameAddedToMessage = false;
- if (!this.shouldRun())
- return;
- this.options = Object.assign(Object.assign({}, this.options), window.EngridEcardToTarget);
- this.logger.log("EcardToTarget running. Options:", this.options);
- this.setTarget();
- this.hideElements();
- this.addSupporterNameToMessage();
- }
- shouldRun() {
- return (window.hasOwnProperty("EngridEcardToTarget") &&
- typeof window.EngridEcardToTarget === "object" &&
- ((window.EngridEcardToTarget.hasOwnProperty("targetName") &&
- window.EngridEcardToTarget.hasOwnProperty("targetEmail")) ||
- (window.EngridEcardToTarget.hasOwnProperty("targets") &&
- window.EngridEcardToTarget.targets.length > 0)));
- }
- setTarget() {
- const targetNameField = document.querySelector(".en__ecardrecipients__name input");
- const targetEmailField = document.querySelector(".en__ecardrecipients__email input");
- const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
- if (!targetNameField || !targetEmailField || !addRecipientButton) {
- this.logger.error("Could not add recipient. Required elements not found.");
- return;
- }
- let targets = this.options.targets;
- // BC support for targetName and targetEmail
- if (this.options.targetName && this.options.targetEmail) {
- targets.push({
- targetName: this.options.targetName,
- targetEmail: this.options.targetEmail,
- });
- }
- // Remove duplicates from targets array
- targets = targets.filter((target, index, self) => index ===
- self.findIndex((t) => t.targetName === target.targetName &&
- t.targetEmail === target.targetEmail));
- targets.forEach((target) => {
- const targetName = target.targetName;
- const targetEmail = target.targetEmail;
- if (!targetName || !targetEmail) {
- this.logger.error("Could not add recipient. Target name or email is empty.");
- return;
- }
- targetNameField.value = targetName;
- targetEmailField.value = targetEmail;
- addRecipientButton === null || addRecipientButton === void 0 ? void 0 : addRecipientButton.click();
- this.logger.log("Added recipient", targetName, targetEmail);
- });
+ // If the hidden input is already present, the EN NSG script has already run, set the amount immediately
+ if (hiddenInput) {
+ setTimeout(() => amt.setAmount(urlParams.get("transaction.donationAmt")), 1000);
+ return;
}
- hideElements() {
- const messageBlock = document.querySelector(".en__ecardmessage");
- const sendDateBlock = document.querySelector(".en__ecardrecipients__futureDelivery");
- const targetBlock = document.querySelector(".en__ecardrecipients");
- if (this.options.hideMessage && messageBlock) {
- messageBlock.classList.add("hide");
- }
- if (this.options.hideSendDate && sendDateBlock) {
- sendDateBlock.classList.add("hide");
- }
- if (this.options.hideTarget && targetBlock) {
- targetBlock.classList.add("hide");
+
+ // Otherwise, we will use a mutation observer to wait for the hidden input to be added to the DOM
+ const observer = new MutationObserver((mutationsList, observer) => {
+ for (const mutation of mutationsList) {
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+ const hiddenInput = document.querySelector('input[name="transaction.donationAmt.sgid"]');
+ if (hiddenInput) {
+ setTimeout(() => amt.setAmount(urlParams.get("transaction.donationAmt")), 1000);
+ observer.disconnect();
+ }
}
- }
- addSupporterNameToMessage() {
- if (!this.options.addSupporterNameToMessage)
- return;
- this._form.onSubmit.subscribe(() => {
- if (!this._form.submit)
- return;
- if (!this.supporterNameAddedToMessage) {
- this.supporterNameAddedToMessage = true;
- const supporterName = `${engrid_ENGrid.getFieldValue("supporter.firstName")} ${engrid_ENGrid.getFieldValue("supporter.lastName")}`;
- const messageField = document.querySelector("[name='transaction.comments']");
- if (!messageField)
- return;
- messageField.value = `${messageField.value}\n${supporterName}`;
- this.logger.log("Added supporter name to personalized message", supporterName);
- }
- });
- }
-}
+ }
+ });
+ const pageForm = document.querySelector("form.en__component--page");
+ if (!pageForm) return;
+ observer.observe(pageForm, {
+ childList: true,
+ subtree: true
+ });
+ }
+ if (urlParams.has("transaction.donationAmt") && window.EngagingNetworks.suggestedGift && window.EngagingNetworks.suggestedGift.single && window.EngagingNetworks.suggestedGift.recurring) {
+ setPreselectedAmountFromUrl();
+ }
+ document.querySelectorAll("h2.alt-ways-give-accordion, h2.by-the-num-accordion").forEach(title => {
+ title.addEventListener("click", () => {
+ const items = title.nextElementSibling;
+ if (!items || !items.classList.contains("pre-footer-items") && !items.classList.contains("contact-us")) return;
+ items.classList.toggle("hide");
+ });
+ });
+ function toggleClickToExpand() {
+ const clickToExpandElements = document.querySelectorAll(".click-to-expand-tnc-toggle");
+ clickToExpandElements.forEach(el => {
+ el.insertAdjacentHTML("afterend", 'Read Less
');
+ const closeButton = el.parentElement.querySelector(".click-to-expand-close");
+ closeButton.addEventListener("click", () => {
+ el.classList.remove("expanded");
+ });
+ });
+ }
+ toggleClickToExpand();
+ function addEcardAltTags() {
+ const ecardImages = [...document.querySelectorAll(".en__ecarditems__thumb img")];
+ const altTexts = [...document.querySelectorAll(".engrid-ecard-alt-tags p")];
+ ecardImages.forEach((img, index) => {
+ if (altTexts[index]) {
+ img.setAttribute("alt", altTexts[index].textContent);
+ }
+ });
+ }
+ addEcardAltTags();
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/deprecated.js
+// A way to gracefully handle deprecation.
+// Find and replace HTML Elements, Classes, and more after the DOM is loaded but before any other Javascript fires.
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/interfaces/embedded-ecard-options.js
-const EmbeddedEcardOptionsDefaults = {
- pageUrl: "",
- headerText: "Send an Ecard notification of your gift",
- checkboxText: "Yes, I would like to send an ecard to announce my gift.",
- anchor: ".en__field--donationAmt",
- placement: "afterend",
- requireInMemCheckbox: false,
+class deprecated_Deprecated {
+ constructor() {
+ let deprecated;
+ let replacement;
+ // Checks for body-side class
+ deprecated = document.querySelector(".body-side");
+ if (deprecated) {
+ this.warning(deprecated);
+ }
+ // Checks for backgroundImage class
+ deprecated = document.querySelector(".backgroundImage");
+ if (deprecated) {
+ replacement = "background-image";
+ this.replace(deprecated, replacement);
+ }
+ // Checks for backgroundImageOverlay class
+ deprecated = document.querySelector(".backgroundImageOverlay");
+ if (deprecated) {
+ replacement = "background-image-overlay";
+ this.replace(deprecated, replacement);
+ }
+ }
+ warning(deprecated) {
+ if (ENGrid.debug) console.log("Deprecated: '" + deprecated + "' was detected and nothing was done.");
+ }
+ replace(deprecated, replacement) {
+ if (ENGrid.debug) console.log("Deprecated: '" + deprecated + "' was detected and replaced with '" + replacement + "'.");
+ deprecated.classList.add(replacement);
+ deprecated.classList.remove(deprecated);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/options.js
+const options_OptionsDefaults = {
+ backgroundImage: "",
+ MediaAttribution: true,
+ applePay: false,
+ CapitalizeFields: false,
+ ClickToExpand: true,
+ CurrencySymbol: "$",
+ CurrencyCode: "USD",
+ AddCurrencySymbol: true,
+ ThousandsSeparator: "",
+ DecimalSeparator: ".",
+ DecimalPlaces: 2,
+ MinAmount: 1,
+ MaxAmount: 100000,
+ MinAmountMessage: "Amount must be at least $1",
+ MaxAmountMessage: "Amount must be less than $100,000",
+ UseAmountValidatorFromEN: false,
+ SkipToMainContentLink: true,
+ SrcDefer: true,
+ SuppressPurchaseEcard: false,
+ NeverBounceAPI: null,
+ NeverBounceDateField: null,
+ NeverBounceStatusField: null,
+ NeverBounceDateFormat: "MM/DD/YYYY",
+ NeverBounceTimeout: 10000,
+ FreshAddress: false,
+ ProgressBar: false,
+ AutoYear: false,
+ TranslateFields: true,
+ Debug: false,
+ RememberMe: false,
+ TidyContact: false,
+ RegionLongFormat: "",
+ CountryDisable: [],
+ Placeholders: false,
+ ENValidators: false,
+ MobileCTA: false,
+ CustomCurrency: false,
+ CustomPremium: false,
+ VGS: false,
+ PostalCodeValidator: false,
+ CountryRedirect: false,
+ WelcomeBack: false,
+ OptInLadder: false,
+ StickyNSG: false,
+ StickyPrepopulation: false,
+ PreferredPaymentMethod: false,
+ PageLayouts: ["leftleft1col", "centerleft1col", "centercenter1col", "centercenter2col", "centerright1col", "rightright1col", "none"]
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/upsell-options.js
+const upsell_options_UpsellOptionsDefaults = {
+ image: "https://picsum.photos/480/650",
+ imagePosition: "left",
+ title: "Will you change your gift to just {new-amount} a month to boost your impact?",
+ paragraph: "Make a monthly pledge today to support us with consistent, reliable resources during emergency moments.",
+ yesLabel: "Yes! Process My {new-amount} monthly gift",
+ noLabel: "No, thanks. Continue with my {old-amount} one-time gift",
+ otherAmount: true,
+ otherLabel: "Or enter a different monthly amount:",
+ upsellOriginalGiftAmountFieldName: "",
+ amountRange: [{
+ max: 10,
+ suggestion: 5
+ }, {
+ max: 15,
+ suggestion: 7
+ }, {
+ max: 20,
+ suggestion: 8
+ }, {
+ max: 25,
+ suggestion: 9
+ }, {
+ max: 30,
+ suggestion: 10
+ }, {
+ max: 35,
+ suggestion: 11
+ }, {
+ max: 40,
+ suggestion: 12
+ }, {
+ max: 50,
+ suggestion: 14
+ }, {
+ max: 100,
+ suggestion: 15
+ }, {
+ max: 200,
+ suggestion: 19
+ }, {
+ max: 300,
+ suggestion: 29
+ }, {
+ max: 500,
+ suggestion: "Math.ceil((amount / 12)/5)*5"
+ }],
+ minAmount: 0,
+ canClose: true,
+ submitOnClose: false,
+ oneTime: true,
+ annual: false,
+ disablePaymentMethods: [],
+ skipUpsell: false,
+ conversionField: "",
+ upsellCheckbox: false
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/translate-options.js
+const translate_options_ptbrTranslation = [{
+ field: "supporter.firstName",
+ translation: "Nome"
+}, {
+ field: "supporter.lastName",
+ translation: "Sobrenome"
+}, {
+ field: "supporter.phoneNumber",
+ translation: "Celular"
+}, {
+ field: "supporter.address1",
+ translation: "EndereΓ§o"
+}, {
+ field: "supporter.address2",
+ translation: "Complemento"
+}, {
+ field: "supporter.postcode",
+ translation: "CEP"
+}, {
+ field: "supporter.city",
+ translation: "Cidade"
+}, {
+ field: "supporter.region",
+ translation: "Estado"
+}, {
+ field: "supporter.country",
+ translation: "PaΓs"
+}];
+const translate_options_deTranslation = [{
+ field: "supporter.address1",
+ translation: "StraΓe, Hausnummer"
+}, {
+ field: "supporter.postcode",
+ translation: "Postleitzahl"
+}, {
+ field: "supporter.city",
+ translation: "Ort"
+}, {
+ field: "supporter.region",
+ translation: "Bundesland"
+}, {
+ field: "supporter.country",
+ translation: "Land"
+}];
+const translate_options_frTranslation = [{
+ field: "supporter.address1",
+ translation: "Adresse"
+}, {
+ field: "supporter.postcode",
+ translation: "Code Postal"
+}, {
+ field: "supporter.city",
+ translation: "Ville"
+}, {
+ field: "supporter.region",
+ translation: "RΓ©gion"
+}, {
+ field: "supporter.country",
+ translation: "Country"
+}];
+const translate_options_nlTranslation = [{
+ field: "supporter.address1",
+ translation: "Adres"
+}, {
+ field: "supporter.postcode",
+ translation: "Postcode"
+}, {
+ field: "supporter.city",
+ translation: "Woonplaats"
+}, {
+ field: "supporter.region",
+ translation: "Provincie"
+}, {
+ field: "supporter.country",
+ translation: "Country"
+}];
+const translate_options_TranslateOptionsDefaults = {
+ BR: translate_options_ptbrTranslation,
+ BRA: translate_options_ptbrTranslation,
+ DE: translate_options_deTranslation,
+ DEU: translate_options_deTranslation,
+ FR: translate_options_frTranslation,
+ FRA: translate_options_frTranslation,
+ NL: translate_options_nlTranslation,
+ NLD: translate_options_nlTranslation
};
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/embedded-ecard.js
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/exit-intent-options.js
+const exit_intent_options_ExitIntentOptionsDefaults = {
+ enabled: false,
+ title: "We are sad that you are leaving",
+ text: "Would you mind telling us why you are leaving this page?",
+ buttonText: "Send us your comments",
+ buttonLink: "https://www.4sitestudios.com/",
+ cookieName: "engrid-exit-intent-lightbox",
+ cookieDuration: 30,
+ triggers: {
+ visibilityState: true,
+ mousePosition: true
+ }
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/frequency-upsell-options.js
+const frequency_upsell_options_FrequencyUpsellOptionsDefaults = {
+ title: "Before we process your donation...",
+ paragraph: "Would you like to make it an annual gift?",
+ yesButton: "YES! Process my gift as an annual gift of ${upsell_amount}",
+ noButton: "NO! Process my gift as a one-time gift of ${current_amount}",
+ upsellFrequency: "annual",
+ upsellFromFrequency: ["onetime"],
+ customClass: "",
+ upsellAmount: currentAmount => currentAmount,
+ onOpen: () => {},
+ onAccept: () => {},
+ onDecline: () => {}
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/iframe-queue-options.js
/**
- * This class handles adding a checkbox to a form that, when checked, will display an embedded ecard form.
- * The embedded ecard form is hosted on a separate page and is displayed in an iframe.
- * The form data is saved in session storage and is submitted when the thank you page is loaded.
- * Options can set on the page via window.EngridEmbeddedEcard.
+ * Configuration interfaces for the Iframe Queue component.
+ *
+ * The Iframe Queue loads a sequence of embedded Engaging Networks pages
+ * one at a time, passes field values into them via `postMessage`, and
+ * exposes a global `IframeQueueEvents` instance so external code can
+ * subscribe to chain-completion. See iframe-queue.ts for the component.
+ *
+ * Configuration may be supplied either programmatically (via
+ * `IframeQueue.getInstance().enqueue(...).process()`) or declaratively
+ * by setting `window.EngridIframeQueue` on the host EN page before
+ * the ENgrid bundle loads.
*/
+const interfaces_iframe_queue_options_IframeQueueOptionsDefaults = {
+ items: [],
+ autoStart: true
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/loader.js
+// Ref: https://app.getguru.com/card/iMgx968T/ENgrid-Loader
-
-class EmbeddedEcard {
- constructor() {
- this.logger = new logger_EngridLogger("Embedded Ecard", "#D95D39", "#0E1428", "π§");
- this.options = EmbeddedEcardOptionsDefaults;
- this._form = en_form_EnForm.getInstance();
- this.isSubmitting = false;
- this.ecardFormActive = false;
- this.iframe = null;
- // For the page hosting the embedded ecard
- if (this.onHostPage()) {
- // Clean up session variables if the page is reloaded, and it isn't a submission failure
- const submissionFailed = !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") &&
- window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
- if (!submissionFailed) {
- sessionStorage.removeItem("engrid-embedded-ecard");
- sessionStorage.removeItem("engrid-send-embedded-ecard");
- }
- this.options = Object.assign(Object.assign({}, EmbeddedEcardOptionsDefaults), window.EngridEmbeddedEcard);
- const pageUrl = new URL(this.options.pageUrl);
- pageUrl.searchParams.append("data-engrid-embedded-ecard", "true");
- pageUrl.searchParams.append("chain", "");
- this.options.pageUrl = pageUrl.href;
- this.logger.log("Running Embedded Ecard component", this.options);
- this.embedEcard();
- this.addEventListeners();
- }
- // For the thank you page - after the host page form has been submitted
- // Only runs if eCard was selected on the main page
- if (this.onPostActionPage()) {
- engrid_ENGrid.setBodyData("embedded-ecard-sent", "true");
- this.submitEcard();
- }
- // For the page that is embedded
- if (this.onEmbeddedEcardPage()) {
- this.setupEmbeddedPage();
- }
+class loader_Loader {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Loader", "gold", "black", "π");
+ this.cssElement = document.querySelector('link[href*="engrid."][rel="stylesheet"]');
+ this.jsElement = document.querySelector('script[src*="engrid."]');
+ }
+ // Returns true if ENgrid should reload (that means the current ENgrid is not the right one)
+ // Returns false if ENgrid should not reload (that means the current ENgrid is the right one)
+ reload() {
+ var _a, _b, _c;
+ const assets = this.getOption("assets");
+ const isLoaded = dist_engrid_ENGrid.getBodyData("loaded");
+ let shouldSkipCss = this.getOption("engridcss") === "false";
+ let shouldSkipJs = this.getOption("engridjs") === "false";
+ if (isLoaded || !assets) {
+ if (shouldSkipCss && this.cssElement) {
+ this.logger.log("engridcss=false | Removing original stylesheet:", this.cssElement);
+ this.cssElement.remove();
+ }
+ if (shouldSkipJs && this.jsElement) {
+ this.logger.log("engridjs=false | Removing original script:", this.jsElement);
+ this.jsElement.remove();
+ }
+ if (shouldSkipCss) {
+ this.logger.log("engridcss=false | adding top banner CSS");
+ this.addENgridCSSUnloadedCSS();
+ }
+ if (shouldSkipJs) {
+ this.logger.log("engridjs=false | Skipping JS load.");
+ this.logger.success("LOADED");
+ return true;
+ }
+ this.logger.success("LOADED");
+ return false;
}
- onHostPage() {
- return (window.hasOwnProperty("EngridEmbeddedEcard") &&
- typeof window.EngridEmbeddedEcard === "object" &&
- window.EngridEmbeddedEcard.hasOwnProperty("pageUrl") &&
- window.EngridEmbeddedEcard.pageUrl !== "");
+ // Load the right ENgrid
+ this.logger.log("RELOADING");
+ dist_engrid_ENGrid.setBodyData("loaded", "true"); // Set the loaded flag, so the next time we don't reload
+ // Fetch the desired repo, assets location, and override JS/CSS
+ const theme = dist_engrid_ENGrid.getBodyData("theme");
+ const engrid_repo = (_a = this.getOption("repo-name")) !== null && _a !== void 0 ? _a : `engrid-${theme}`;
+ let engrid_js_url = "";
+ let engrid_css_url = "";
+ switch (assets) {
+ case "local":
+ this.logger.log("LOADING LOCAL");
+ dist_engrid_ENGrid.setBodyData("assets", "local");
+ engrid_js_url = `https://${engrid_repo}.test/dist/engrid.js`;
+ engrid_css_url = `https://${engrid_repo}.test/dist/engrid.css`;
+ break;
+ case "flush":
+ this.logger.log("FLUSHING CACHE");
+ const timestamp = Date.now();
+ const jsCurrentURL = new URL(((_b = this.jsElement) === null || _b === void 0 ? void 0 : _b.getAttribute("src")) || "");
+ jsCurrentURL.searchParams.set("v", timestamp.toString());
+ engrid_js_url = jsCurrentURL.toString();
+ const cssCurrentURL = new URL(((_c = this.cssElement) === null || _c === void 0 ? void 0 : _c.getAttribute("href")) || "");
+ cssCurrentURL.searchParams.set("v", timestamp.toString());
+ engrid_css_url = cssCurrentURL.toString();
+ break;
+ default:
+ this.logger.log("LOADING EXTERNAL");
+ engrid_js_url = `https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${engrid_repo}/${assets}/engrid.js`;
+ engrid_css_url = `https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${engrid_repo}/${assets}/engrid.css`;
}
- onEmbeddedEcardPage() {
- return engrid_ENGrid.getPageType() === "ECARD" && engrid_ENGrid.hasBodyData("embedded") && engrid_ENGrid.getPageNumber() === 1;
+ if (shouldSkipCss && this.cssElement) {
+ this.logger.log("engridcss=false | Removing original stylesheet:", this.cssElement);
+ this.cssElement.remove();
}
- onPostActionPage() {
- return (sessionStorage.getItem("engrid-embedded-ecard") !== null &&
- sessionStorage.getItem("engrid-send-embedded-ecard") !== null &&
- !this.onHostPage() &&
- !this.onEmbeddedEcardPage());
+ if (shouldSkipCss && engrid_css_url && engrid_css_url !== "") {
+ this.logger.log("engridcss=false | Skipping injection of stylesheet:", engrid_css_url);
}
- embedEcard() {
- var _a;
- const container = document.createElement("div");
- container.classList.add("engrid--embedded-ecard");
- const heading = document.createElement("h3");
- heading.textContent = this.options.headerText;
- heading.classList.add("engrid--embedded-ecard-heading");
- container.appendChild(heading);
- const checkbox = document.createElement("div");
- checkbox.classList.add("pseudo-en-field", "en__field", "en__field--checkbox", "en__field--000000", "en__field--embedded-ecard");
- checkbox.innerHTML = `
-
-
-
- ${this.options.checkboxText}
-
-
`;
- container.appendChild(checkbox);
- this.iframe = this.createIframe(this.options.pageUrl);
- container.appendChild(this.iframe);
- (_a = document
- .querySelector(this.options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(this.options.placement, container);
+ if (shouldSkipCss) {
+ this.logger.log("engridcss=false | adding top banner CSS");
+ this.addENgridCSSUnloadedCSS();
+ } else {
+ this.setCssFile(engrid_css_url);
}
- createIframe(url) {
- const iframe = document.createElement("iframe");
- iframe.src = url;
- iframe.setAttribute("src", url);
- iframe.setAttribute("width", "100%");
- iframe.setAttribute("scrolling", "no");
- iframe.setAttribute("frameborder", "0");
- iframe.setAttribute("title", "Ecard iframe");
- iframe.classList.add("engrid-iframe", "engrid-iframe--embedded-ecard");
- iframe.style.display = "none";
- return iframe;
+ if (shouldSkipJs && this.jsElement) {
+ this.logger.log("engridjs=false | Removing original script:", this.jsElement);
+ this.jsElement.remove();
}
- addEventListeners() {
- var _a;
- const sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
- if (this.options.requireInMemCheckbox) {
- const inMemoriamCheckbox = document.getElementById("en__field_transaction_inmem");
- inMemoriamCheckbox === null || inMemoriamCheckbox === void 0 ? void 0 : inMemoriamCheckbox.addEventListener("change", (e) => {
- const checkbox = e.target;
- const _sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
- this.toggleEcardForm(checkbox.checked && _sendEcardCheckbox.checked);
- });
- this.toggleEcardForm(((_a = inMemoriamCheckbox === null || inMemoriamCheckbox === void 0 ? void 0 : inMemoriamCheckbox.checked) !== null && _a !== void 0 ? _a : true) && sendEcardCheckbox.checked);
+ if (shouldSkipJs && engrid_js_url && engrid_js_url !== "") {
+ this.logger.log("engridjs=false | Skipping injection of script:", engrid_js_url);
+ }
+ if (!shouldSkipJs) {
+ this.setJsFile(engrid_js_url);
+ }
+ // If custom assets aren't defined, we don't need to reload.
+ if (!assets) {
+ return false;
+ }
+ return true;
+ }
+ getOption(key) {
+ const urlParam = dist_engrid_ENGrid.getUrlParameter(key);
+ if (urlParam && ["assets", "engridcss", "engridjs"].includes(key)) {
+ return urlParam;
+ } else if (window.EngridLoader && window.EngridLoader.hasOwnProperty(key)) {
+ return window.EngridLoader[key];
+ } else if (this.jsElement && this.jsElement.hasAttribute("data-" + key)) {
+ return this.jsElement.getAttribute("data-" + key);
+ }
+ return null;
+ }
+ setCssFile(url) {
+ if (url === "") {
+ return;
+ }
+ if (this.cssElement) {
+ this.logger.log("Replacing stylesheet:", url);
+ this.cssElement.setAttribute("href", url);
+ } else {
+ this.logger.log("Injecting stylesheet:", url);
+ const link = document.createElement("link");
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("type", "text/css");
+ link.setAttribute("media", "all");
+ link.setAttribute("href", url);
+ document.head.appendChild(link);
+ }
+ }
+ setJsFile(url) {
+ if (url === "") {
+ return;
+ }
+ this.logger.log("Injecting script:", url);
+ const script = document.createElement("script");
+ script.setAttribute("src", url);
+ document.head.appendChild(script);
+ }
+ addENgridCSSUnloadedCSS() {
+ document.body.insertAdjacentHTML("beforeend", ``);
+ }
+}
+// EXTERNAL MODULE: ../engrid/packages/scripts/node_modules/strongly-typed-events/dist/index.js
+var strongly_typed_events_dist = __webpack_require__(4386);
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/en-form.js
+
+
+class events_en_form_EnForm {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("EnForm");
+ this._onIntentSubmit = new strongly_typed_events_dist/* SignalDispatcher */.UD();
+ this._onSubmit = new strongly_typed_events_dist/* SignalDispatcher */.UD();
+ this._onValidate = new strongly_typed_events_dist/* SignalDispatcher */.UD();
+ this._onError = new strongly_typed_events_dist/* SignalDispatcher */.UD();
+ this.submit = true;
+ this.submitPromise = false;
+ this.validate = true;
+ this.validatePromise = false;
+ }
+ static getInstance() {
+ if (!events_en_form_EnForm.instance) {
+ events_en_form_EnForm.instance = new events_en_form_EnForm();
+ }
+ return events_en_form_EnForm.instance;
+ }
+ dispatchIntentSubmit() {
+ this._onIntentSubmit.dispatch();
+ this.logger.log("dispatchIntentSubmit");
+ }
+ dispatchSubmit() {
+ this._onSubmit.dispatch();
+ this.logger.log("dispatchSubmit");
+ }
+ dispatchValidate() {
+ this._onValidate.dispatch();
+ this.logger.log("dispatchValidate");
+ }
+ dispatchError() {
+ this._onError.dispatch();
+ this.logger.log("dispatchError");
+ }
+ submitForm() {
+ const enForm = document.querySelector("form .en__submit button");
+ if (enForm) {
+ // Add submitting class to modal
+ const enModal = document.getElementById("enModal");
+ if (enModal) enModal.classList.add("is-submitting");
+ enForm.click();
+ this.logger.log("submitForm");
}
- setEmbeddedEcardSessionData() {
- let ecardVariant = document.querySelector("[name='friend.ecard']");
- let ecardSendDate = document.querySelector("[name='ecard.schedule']");
- let ecardMessage = document.querySelector("[name='transaction.comments']");
- //add "chain" param to window.location.href if it doesnt have it
- const pageUrl = new URL(window.location.href);
- if (!pageUrl.searchParams.has("chain")) {
- pageUrl.searchParams.append("chain", "");
+ }
+ /**
+ * onIntentSubmit is dispatched when a submit button is clicked,
+ * or a digital wallet submission is initiated,
+ * but before server-side validation or the actual submit event.
+ * This allows you to run code at the moment the user intends to submit,
+ * such as triggering data formatting, analytics events, or other pre-submit actions.
+ * Actions that rely on fully processed form data or validation results should use the onSubmit event instead.
+ * Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
+ */
+ get onIntentSubmit() {
+ return this._onIntentSubmit.asEvent();
+ }
+ /**
+ * onSubmit is dispatched when the form is submitted, after validation has passed.
+ * This is the main event to listen to for form submissions, as it indicates that the user has successfully submitted the form and all validation checks have been passed.
+ * This event uses window.enOnSubmit, which is called by Engaging Networks' JavaScript when the form is submitted.
+ * At the time of writing, enOnSubmit does not trigger when a user submits via a digital wallet, use onIntentSubmit to listen for those submission attempts.
+ * Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
+ */
+ get onSubmit() {
+ return this._onSubmit.asEvent();
+ }
+ /**
+ * onValidate is dispatched using window.enOnValidate, which is called by Engaging Networks' JavaScript
+ * when the form is being validated, before submission. This only occurs after ENgrid's client-side validation has passed, but before server-side validation.
+ */
+ get onValidate() {
+ return this._onValidate.asEvent();
+ }
+ /**
+ * onError is dispatched using window.enOnError, which is called by Engaging Networks' JavaScript when a server-side validation error occurs on form submission.
+ * This allows you to listen for validation errors and respond accordingly, such as displaying custom error messages or triggering analytics events.
+ */
+ get onError() {
+ return this._onError.asEvent();
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/donation-amount.js
+
+
+class donation_amount_DonationAmount {
+ constructor(radios = "transaction.donationAmt", other = "transaction.donationAmt.other") {
+ this._onAmountChange = new strongly_typed_events_dist/* SimpleEventDispatcher */.IL();
+ this._amount = 0;
+ this._radios = "";
+ this._other = "";
+ this._dispatch = true;
+ this._other = other;
+ this._radios = radios;
+ // Watch Radios Inputs for Changes
+ document.addEventListener("change", e => {
+ const element = e.target;
+ if (element) {
+ if (element.name == radios) {
+ this.amount = parseFloat(element.value);
+ } else if (element.name == other) {
+ const cleanedAmount = dist_engrid_ENGrid.cleanAmount(element.value);
+ element.value = cleanedAmount % 1 != 0 ? cleanedAmount.toFixed(2) : cleanedAmount.toString();
+ this.amount = cleanedAmount;
}
- const embeddedEcardData = {
- pageUrl: pageUrl.href,
- formData: {
- ecardVariant: (ecardVariant === null || ecardVariant === void 0 ? void 0 : ecardVariant.value) || "",
- ecardSendDate: (ecardSendDate === null || ecardSendDate === void 0 ? void 0 : ecardSendDate.value) || "",
- ecardMessage: (ecardMessage === null || ecardMessage === void 0 ? void 0 : ecardMessage.value) || "",
- recipients: this.getEcardRecipients(),
- },
- };
- sessionStorage.setItem("engrid-embedded-ecard", JSON.stringify(embeddedEcardData));
+ }
+ });
+ // Watch Other Amount Field
+ const otherField = document.querySelector(`[name='${this._other}']`);
+ if (otherField) {
+ otherField.addEventListener("keyup", e => {
+ this.amount = dist_engrid_ENGrid.cleanAmount(otherField.value);
+ });
}
- getEcardRecipients() {
- const recipients = [];
- const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
- //Single recipient form where the "add recipient" button is hidden, and we use the recipient name and email fields
- const isSingleRecipientForm = !addRecipientButton || addRecipientButton.offsetHeight === 0;
- if (isSingleRecipientForm) {
- // When it is a single recipient form, we only need to get the recipient name and email from the input fields
- let recipientName = document.querySelector(".en__ecardrecipients__name > input");
- let recipientEmail = document.querySelector(".en__ecardrecipients__email > input");
- if (recipientName && recipientEmail) {
- recipients.push({
- name: recipientName.value,
- email: recipientEmail.value,
- });
- }
- return recipients;
+ // Load the current amount
+ this.load();
+ }
+ static getInstance(radios = "transaction.donationAmt", other = "transaction.donationAmt.other") {
+ if (!donation_amount_DonationAmount.instance) {
+ donation_amount_DonationAmount.instance = new donation_amount_DonationAmount(radios, other);
+ }
+ return donation_amount_DonationAmount.instance;
+ }
+ get amount() {
+ return this._amount;
+ }
+ // Every time we set an amount, trigger the onAmountChange event
+ set amount(value) {
+ this._amount = value || 0;
+ if (this._dispatch) this._onAmountChange.dispatch(this._amount);
+ }
+ get onAmountChange() {
+ return this._onAmountChange.asEvent();
+ }
+ // Set amount var with currently selected amount
+ load() {
+ const currentAmountField = document.querySelector('input[name="' + this._radios + '"]:checked');
+ if (currentAmountField) {
+ let currentAmountValue = parseFloat(currentAmountField.value || "");
+ if (currentAmountValue > 0) {
+ this.amount = parseFloat(currentAmountField.value);
+ } else {
+ const otherField = document.querySelector('input[name="' + this._other + '"]');
+ currentAmountValue = dist_engrid_ENGrid.cleanAmount(otherField.value);
+ this.amount = currentAmountValue;
+ }
+ } else if (dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationTotal") && dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationFee")) {
+ const total = window.EngagingNetworks.require._defined.enjs.getDonationTotal() - window.EngagingNetworks.require._defined.enjs.getDonationFee();
+ if (total) {
+ this.amount = total;
+ }
+ }
+ }
+ // Force a new amount
+ setAmount(amount, dispatch = true) {
+ // Run only if it is a Donation Page with a Donation Amount field
+ if (!document.getElementsByName(this._radios).length) {
+ return;
+ }
+ // Set dispatch to be checked by the SET method
+ this._dispatch = dispatch;
+ // Search for the current amount on radio boxes
+ let found = Array.from(document.querySelectorAll('input[name="' + this._radios + '"]')).filter(el => el instanceof HTMLInputElement && parseInt(el.value) == amount);
+ // We found the amount on the radio boxes, so check it
+ if (found.length) {
+ const amountField = found[0];
+ amountField.checked = true;
+ // Change Event
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true
+ });
+ amountField.dispatchEvent(event);
+ // Clear OTHER text field
+ this.clearOther();
+ } else {
+ const otherField = document.querySelector('input[name="' + this._other + '"]');
+ if (otherField) {
+ const enFieldOtherAmountRadio = document.querySelector(`.en__field--donationAmt.en__field--withOther .en__field__item:nth-last-child(2) input[name="${this._radios}"]`);
+ if (enFieldOtherAmountRadio) {
+ enFieldOtherAmountRadio.checked = true;
}
- // For multiple recipient forms, we need to get the recipient name and email from each recipient in the recipient list
- const recipientList = document.querySelector(".en__ecardrecipients__list");
- recipientList === null || recipientList === void 0 ? void 0 : recipientList.querySelectorAll(".en__ecardrecipients__recipient").forEach((el) => {
- const recipientName = el.querySelector(".ecardrecipient__name");
- const recipientEmail = el.querySelector(".ecardrecipient__email");
- if (recipientName && recipientEmail) {
- recipients.push({
- name: recipientName.value,
- email: recipientEmail.value,
- });
- }
+ otherField.value = parseFloat(amount.toString()).toFixed(2);
+ // Change Event
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true
});
- return recipients;
+ otherField.dispatchEvent(event);
+ const otherWrapper = otherField.parentNode;
+ otherWrapper.classList.remove("en__field__item--hidden");
+ }
}
- setupEmbeddedPage() {
- let ecardVariant = document.querySelector("[name='friend.ecard']");
- let ecardSendDate = document.querySelector("[name='ecard.schedule']");
- let ecardMessage = document.querySelector("[name='transaction.comments']");
- let recipientName = document.querySelector(".en__ecardrecipients__name > input");
- let recipientEmail = document.querySelector(".en__ecardrecipients__email > input");
- [
- ecardVariant,
- ecardSendDate,
- ecardMessage,
- recipientName,
- recipientEmail,
- ].forEach((el) => {
- el.addEventListener("input", () => {
- if (this.isSubmitting)
- return;
- this.setEmbeddedEcardSessionData();
- });
- });
- // MutationObserver to detect changes in the recipient list and update the session data
- const observer = new MutationObserver((mutationsList) => {
- for (let mutation of mutationsList) {
- if (mutation.type === "childList") {
- if (this.isSubmitting)
- return;
- this.setEmbeddedEcardSessionData();
+ // Set the new amount and trigger all live variables
+ this.amount = amount;
+ // Revert dispatch to default value (true)
+ this._dispatch = true;
+ }
+ // Clear Other Field
+ clearOther() {
+ const otherField = document.querySelector('input[name="' + this._other + '"]');
+ otherField.value = "";
+ const otherWrapper = otherField.parentNode;
+ otherWrapper.classList.add("en__field__item--hidden");
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/engrid.js
+class dist_engrid_ENGrid {
+ constructor() {
+ if (!dist_engrid_ENGrid.enForm) {
+ throw new Error("Engaging Networks Form Not Found!");
+ }
+ }
+ static get enForm() {
+ return document.querySelector("form.en__component");
+ }
+ static get debug() {
+ return !!this.getOption("Debug");
+ }
+ static get demo() {
+ return this.getUrlParameter("mode") === "DEMO";
+ }
+ // Return any parameter from the URL
+ static getUrlParameter(name) {
+ const searchParams = new URLSearchParams(window.location.search);
+ // Add support for array on the name ending with []
+ if (name.endsWith("[]")) {
+ let values = [];
+ searchParams.forEach((value, key) => {
+ if (key.startsWith(name.replace("[]", ""))) {
+ values.push(new Object({
+ [key]: value
+ }));
+ }
+ });
+ return values.length > 0 ? values : null;
+ }
+ if (searchParams.has(name)) {
+ return searchParams.get(name) || true;
+ }
+ return null;
+ }
+ static getField(name) {
+ // Get the field by name
+ return document.querySelector(`[name="${name}"]`);
+ }
+ // Return the field value from its name. It works on any field type.
+ // Multiple values (from checkboxes or multi-select) are returned as single string
+ // Separated by ,
+ static getFieldValue(name) {
+ return new FormData(this.enForm).getAll(name).join(",");
+ }
+ // Set a value to any field. If it's a dropdown, radio or checkbox, it selects the proper option matching the value
+ static setFieldValue(name, value, parseENDependencies = true, dispatchEvents = false) {
+ if (value === dist_engrid_ENGrid.getFieldValue(name)) return;
+ document.getElementsByName(name).forEach(field => {
+ if ("type" in field) {
+ switch (field.type) {
+ case "select-one":
+ case "select-multiple":
+ for (const option of field.options) {
+ if (option.value == value) {
+ option.selected = true;
+ if (dispatchEvents) {
+ field.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
}
+ }
}
- });
- const recipientList = document.querySelector(".en__ecardrecipients__list");
- if (recipientList) {
- observer.observe(recipientList, { childList: true });
- }
- document.querySelectorAll(".en__ecarditems__thumb").forEach((el) => {
- // Making sure the session value is changed when this is clicked
- el.addEventListener("click", () => {
- ecardVariant.dispatchEvent(new Event("input"));
- });
- });
- // Remove the recipient error message when the user starts typing in the recipient fields
- [recipientName, recipientEmail].forEach((el) => {
- el.addEventListener("input", () => {
- const recipientDetails = document.querySelector(".en__ecardrecipients__detail");
- const error = document.querySelector(".engrid__recipient__error");
- recipientDetails === null || recipientDetails === void 0 ? void 0 : recipientDetails.classList.remove("validationFail");
- error === null || error === void 0 ? void 0 : error.classList.add("hide");
+ break;
+ case "checkbox":
+ case "radio":
+ if (field.value == value) {
+ field.checked = true;
+ if (dispatchEvents) {
+ field.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ }
+ }
+ break;
+ case "textarea":
+ case "text":
+ default:
+ field.value = value;
+ if (dispatchEvents) {
+ field.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ field.dispatchEvent(new Event("blur", {
+ bubbles: true
+ }));
+ }
+ }
+ field.setAttribute("engrid-value-changed", "");
+ }
+ });
+ if (parseENDependencies) this.enParseDependencies();
+ return;
+ }
+ // Create a hidden input field
+ static createHiddenInput(name, value = "") {
+ var _a;
+ const formBlock = document.createElement("div");
+ formBlock.classList.add("en__component", "en__component--formblock", "hide");
+ const textField = document.createElement("div");
+ textField.classList.add("en__field", "en__field--text");
+ const textElement = document.createElement("div");
+ textElement.classList.add("en__field__element", "en__field__element--text");
+ const inputField = document.createElement("input");
+ inputField.classList.add("en__field__input", "en__field__input--text", "engrid-added-input");
+ inputField.setAttribute("name", name);
+ inputField.setAttribute("type", "hidden");
+ inputField.setAttribute("value", value);
+ textElement.appendChild(inputField);
+ textField.appendChild(textElement);
+ formBlock.appendChild(textField);
+ const submitElement = document.querySelector(".en__submit");
+ if (submitElement) {
+ const lastFormComponent = submitElement.closest(".en__component");
+ if (lastFormComponent) {
+ // Insert the new field after the submit button
+ (_a = lastFormComponent.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(formBlock, lastFormComponent.nextSibling);
+ }
+ } else {
+ dist_engrid_ENGrid.enForm.appendChild(formBlock);
+ }
+ return inputField;
+ }
+ // Trigger EN Dependencies
+ static enParseDependencies() {
+ var _a, _b, _c, _d, _e, _f;
+ if (window.EngagingNetworks && typeof ((_e = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enDependencies) === null || _d === void 0 ? void 0 : _d.dependencies) === null || _e === void 0 ? void 0 : _e.parseDependencies) === "function") {
+ const customDependencies = [];
+ if ("dependencies" in window.EngagingNetworks) {
+ const amountContainer = document.querySelector(".en__field--donationAmt");
+ if (amountContainer) {
+ let amountID = ((_f = [...amountContainer.classList.values()].filter(v => v.startsWith("en__field--") && Number(v.substring(11)) > 0).toString().match(/\d/g)) === null || _f === void 0 ? void 0 : _f.join("")) || "";
+ if (amountID) {
+ window.EngagingNetworks.dependencies.forEach(dependency => {
+ if ("actions" in dependency && dependency.actions.length > 0) {
+ let amountIdFound = false;
+ dependency.actions.forEach(action => {
+ if ("target" in action && action.target == amountID) {
+ amountIdFound = true;
+ }
+ });
+ if (!amountIdFound) {
+ customDependencies.push(dependency);
+ }
+ }
});
- });
- window.addEventListener("message", (e) => {
- if (e.origin !== location.origin || !e.data.action)
- return;
- this.logger.log("Received post message", e.data);
- switch (e.data.action) {
- case "submit_form":
- this.isSubmitting = true;
- let embeddedEcardData = JSON.parse(sessionStorage.getItem("engrid-embedded-ecard") || "{}");
- if (ecardVariant) {
- ecardVariant.value = embeddedEcardData.formData["ecardVariant"];
- }
- if (ecardSendDate) {
- ecardSendDate.value = embeddedEcardData.formData["ecardSendDate"];
- }
- if (ecardMessage) {
- ecardMessage.value = embeddedEcardData.formData["ecardMessage"];
- }
- const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
- embeddedEcardData.formData.recipients.forEach((recipient) => {
- recipientName.value = recipient.name;
- recipientEmail.value = recipient.email;
- addRecipientButton === null || addRecipientButton === void 0 ? void 0 : addRecipientButton.click();
- });
- const form = en_form_EnForm.getInstance();
- form.submitForm();
- sessionStorage.removeItem("engrid-embedded-ecard");
- sessionStorage.removeItem("engrid-send-embedded-ecard");
- break;
- case "set_recipient":
- recipientName.value = e.data.name;
- recipientEmail.value = e.data.email;
- recipientName.dispatchEvent(new Event("input"));
- recipientEmail.dispatchEvent(new Event("input"));
- break;
- case "recipient_error":
- const recipientDetails = document.querySelector(".en__ecardrecipients__detail");
- const error = document.querySelector(".engrid__recipient__error");
- if (error) {
- error.classList.remove("hide");
- }
- else {
- recipientDetails === null || recipientDetails === void 0 ? void 0 : recipientDetails.insertAdjacentHTML("afterend", "Please provide the details for your eCard recipient
");
- }
- recipientDetails === null || recipientDetails === void 0 ? void 0 : recipientDetails.classList.add("validationFail");
- window.dispatchEvent(new Event("resize"));
- break;
+ if (customDependencies.length > 0) {
+ window.EngagingNetworks.require._defined.enDependencies.dependencies.parseDependencies(customDependencies);
+ if (dist_engrid_ENGrid.getOption("Debug")) console.log("EN Dependencies Triggered", customDependencies);
}
- });
- this.sendPostMessage("parent", "ecard_form_ready");
+ }
+ }
+ }
+ }
+ }
+ // Return the status of the gift process (true if a donation has been made, otherwise false)
+ static getGiftProcess() {
+ if ("pageJson" in window) return window.pageJson.giftProcess;
+ return null;
+ }
+ // Return the page count
+ static getPageCount() {
+ if ("pageJson" in window) return window.pageJson.pageCount;
+ return null;
+ }
+ // Return the current page number
+ static getPageNumber() {
+ if ("pageJson" in window) return window.pageJson.pageNumber;
+ return null;
+ }
+ static isThankYouPage() {
+ return this.getPageNumber() === this.getPageCount();
+ }
+ // Return the current page ID
+ static getPageID() {
+ if ("pageJson" in window) return window.pageJson.campaignPageId;
+ return 0;
+ }
+ /**
+ * Parse the numeric Page ID out of a Engaging Networks URL.
+ * EN page URLs follow the pattern `https:///page///...`.
+ * Used by the Iframe Queue component to match Thank-You-page pings from
+ * embedded iframes against the queued URL that was submitted.
+ *
+ * @param url Full URL string to parse.
+ * @returns The numeric Page ID, or 0 if it could not be parsed.
+ */
+ static getPageIdFromUrl(url) {
+ if (!url) return 0;
+ const match = url.match(/\/page\/(\d+)(?:\/|$|\?|#)/);
+ if (!match) return 0;
+ const id = parseInt(match[1], 10);
+ return Number.isFinite(id) ? id : 0;
+ }
+ // Return the client ID
+ static getClientID() {
+ if ("pageJson" in window) return window.pageJson.clientId;
+ return 0;
+ }
+ //returns 'us or 'ca' based on the client ID
+ static getDataCenter() {
+ return dist_engrid_ENGrid.getClientID() >= 10000 ? "us" : "ca";
+ }
+ // Return the current page type
+ static getPageType() {
+ if ("pageJson" in window && "pageType" in window.pageJson) {
+ switch (window.pageJson.pageType) {
+ case "p2pcheckout":
+ case "p2pdonation":
+ case "donation":
+ case "premiumgift":
+ return "DONATION";
+ break;
+ case "e-card":
+ return "ECARD";
+ break;
+ case "otherdatacapture":
+ case "survey":
+ return "SURVEY";
+ break;
+ case "emailtotarget":
+ return "EMAILTOTARGET";
+ break;
+ case "advocacypetition":
+ return "ADVOCACY";
+ break;
+ case "emailsubscribeform":
+ return "SUBSCRIBEFORM";
+ break;
+ case "event":
+ return "EVENT";
+ break;
+ case "supporterhub":
+ return "SUPPORTERHUB";
+ break;
+ case "unsubscribe":
+ return "UNSUBSCRIBE";
+ break;
+ case "tweetpage":
+ return "TWEETPAGE";
+ break;
+ default:
+ return "UNKNOWN";
+ }
+ } else {
+ return "UNKNOWN";
+ }
+ }
+ // Set body engrid data attributes
+ static setBodyData(dataName, value) {
+ const body = document.querySelector("body");
+ // If value is boolean
+ if (typeof value === "boolean" && value === false) {
+ body.removeAttribute(`data-engrid-${dataName}`);
+ return;
+ }
+ body.setAttribute(`data-engrid-${dataName}`, value.toString());
+ }
+ // Get body engrid data attributes
+ static getBodyData(dataName) {
+ const body = document.querySelector("body");
+ return body.getAttribute(`data-engrid-${dataName}`);
+ }
+ // Check if body has engrid data attributes
+ static hasBodyData(dataName) {
+ const body = document.querySelector("body");
+ return body.hasAttribute(`data-engrid-${dataName}`);
+ }
+ // Return the option value
+ static getOption(key) {
+ return window.EngridOptions[key] || null;
+ }
+ // Load an external script
+ static loadJS(url, onload = null, head = true) {
+ const scriptTag = document.createElement("script");
+ scriptTag.src = url;
+ scriptTag.onload = onload;
+ if (head) {
+ document.head.appendChild(scriptTag);
+ return;
+ }
+ document.body.appendChild(scriptTag);
+ return;
+ }
+ // Format a number
+ static formatNumber(number, decimals = 2, dec_point = ".", thousands_sep = ",") {
+ // Strip all characters but numerical ones.
+ number = (number + "").replace(/[^0-9+\-Ee.]/g, "");
+ const n = !isFinite(+number) ? 0 : +number;
+ const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
+ const sep = typeof thousands_sep === "undefined" ? "," : thousands_sep;
+ const dec = typeof dec_point === "undefined" ? "." : dec_point;
+ let s = [];
+ const toFixedFix = function (n, prec) {
+ const k = Math.pow(10, prec);
+ return "" + Math.round(n * k) / k;
+ };
+ // Fix for IE parseFloat(0.55).toFixed(0) = 0;
+ s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split(".");
+ if (s[0].length > 3) {
+ s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
+ }
+ if ((s[1] || "").length < prec) {
+ s[1] = s[1] || "";
+ s[1] += new Array(prec - s[1].length + 1).join("0");
+ }
+ return s.join(dec);
+ }
+ // Clean an Amount
+ static cleanAmount(amount) {
+ // Split the number
+ const valueArray = amount.replace(/[^0-9,\.]/g, "").split(/[,.]+/);
+ const delimArray = amount.replace(/[^.,]/g, "").split("");
+ // Handle values with no decimal places and non-numeric values
+ if (valueArray.length === 1) {
+ return parseInt(valueArray[0]) || 0;
+ }
+ // Ignore invalid numbers
+ if (valueArray.map((x, index) => {
+ return index > 0 && index + 1 !== valueArray.length && x.length !== 3 ? true : false;
+ }).includes(true)) {
+ return 0;
+ }
+ // Multiple commas is a bad thing? So edgy.
+ if (delimArray.length > 1 && !delimArray.includes(".")) {
+ return 0;
+ }
+ // Handle invalid decimal and comma formatting
+ if ([...new Set(delimArray.slice(0, -1))].length > 1) {
+ return 0;
+ }
+ // If there are cents
+ if (valueArray[valueArray.length - 1].length <= 2) {
+ const cents = valueArray.pop() || "00";
+ return parseInt(cents) > 0 ? parseFloat(Number(parseInt(valueArray.join("")) + "." + cents).toFixed(2)) : parseInt(valueArray.join(""));
+ }
+ return parseInt(valueArray.join(""));
+ }
+ static disableSubmit(label = "") {
+ const submit = document.querySelector(".en__submit button");
+ if (!submit) return false;
+ let submitButtonProcessingHTML = `${label} `;
+ if (submit.innerHTML.includes("loader-wrapper")) {
+ // If we are already processing, don't override the originalText again
+ return false;
+ }
+ submit.dataset.originalText = submit.innerHTML;
+ submit.disabled = true;
+ submit.innerHTML = submitButtonProcessingHTML;
+ return true;
+ }
+ static enableSubmit() {
+ const submit = document.querySelector(".en__submit button");
+ if (!submit) return false;
+ if (submit.dataset.originalText) {
+ submit.disabled = false;
+ submit.innerHTML = submit.dataset.originalText;
+ delete submit.dataset.originalText;
+ return true;
+ }
+ return false;
+ }
+ static formatDate(date, format = "MM/DD/YYYY") {
+ const dateAray = date.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit"
+ }).split("/");
+ const dateString = format.replace(/YYYY/g, dateAray[2]).replace(/MM/g, dateAray[0]).replace(/DD/g, dateAray[1]).replace(/YY/g, dateAray[2].substr(2, 2));
+ return dateString;
+ }
+ /**
+ * Check if the provided object has ALL the provided properties
+ * Example: checkNested(EngagingNetworks, 'require', '_defined', 'enjs', 'checkSubmissionFailed')
+ * will return true if EngagingNetworks.require._defined.enjs.checkSubmissionFailed is defined
+ */
+ static checkNested(obj, ...args) {
+ for (let i = 0; i < args.length; i++) {
+ if (!obj || !obj.hasOwnProperty(args[i])) {
+ return false;
+ }
+ obj = obj[args[i]];
+ }
+ return true;
+ }
+ // Deep merge two objects
+ static deepMerge(target, source) {
+ for (const key in source) {
+ if (source[key] instanceof Object) Object.assign(source[key], dist_engrid_ENGrid.deepMerge(target[key], source[key]));
+ }
+ Object.assign(target || {}, source);
+ return target;
+ }
+ static setError(element, errorMessage) {
+ const errorElement = typeof element === "string" ? document.querySelector(element) : element;
+ if (errorElement) {
+ errorElement.classList.add("en__field--validationFailed");
+ let errorMessageElement = errorElement.querySelector(".en__field__error");
+ if (!errorMessageElement) {
+ errorMessageElement = document.createElement("div");
+ errorMessageElement.classList.add("en__field__error");
+ errorMessageElement.innerHTML = errorMessage;
+ errorElement.insertBefore(errorMessageElement, errorElement.firstChild);
+ } else {
+ errorMessageElement.innerHTML = errorMessage;
+ }
+ }
+ }
+ static removeError(element) {
+ const errorElement = typeof element === "string" ? document.querySelector(element) : element;
+ if (errorElement) {
+ errorElement.classList.remove("en__field--validationFailed");
+ const errorMessageElement = errorElement.querySelector(".en__field__error");
+ if (errorMessageElement) {
+ errorElement.removeChild(errorMessageElement);
+ }
}
- submitEcard() {
- var _a;
- const embeddedEcardData = JSON.parse(sessionStorage.getItem("engrid-embedded-ecard") || "{}");
- this.logger.log("Submitting ecard", embeddedEcardData);
- const iframe = this.createIframe(embeddedEcardData.pageUrl);
- (_a = document.querySelector(".body-main")) === null || _a === void 0 ? void 0 : _a.appendChild(iframe);
- window.addEventListener("message", (e) => {
- if (e.origin !== location.origin || !e.data.action)
- return;
- if (e.data.action === "ecard_form_ready") {
- this.sendPostMessage(iframe, "submit_form");
- }
+ }
+ static isVisible(element) {
+ if (!element) {
+ return false;
+ }
+ return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
+ }
+ static getCurrencySymbol() {
+ const currencyField = dist_engrid_ENGrid.getField("transaction.paycurrency");
+ if (currencyField) {
+ // Check if the selected currency field option have a data-currency-symbol attribute
+ const selectedOption = currencyField.tagName === "SELECT" ? currencyField.options[currencyField.selectedIndex] : currencyField;
+ if (selectedOption.dataset.currencySymbol) {
+ return selectedOption.dataset.currencySymbol;
+ }
+ const currencyArray = {
+ USD: "$",
+ EUR: "β¬",
+ GBP: "Β£",
+ AUD: "$",
+ CAD: "$",
+ JPY: "Β₯"
+ };
+ return currencyArray[currencyField.value] || "$";
+ }
+ return dist_engrid_ENGrid.getOption("CurrencySymbol") || "$";
+ }
+ static getCurrencyCode() {
+ const currencyField = dist_engrid_ENGrid.getField("transaction.paycurrency");
+ if (currencyField) {
+ return currencyField.value || "USD";
+ }
+ return dist_engrid_ENGrid.getOption("CurrencyCode") || "USD";
+ }
+ static addHtml(html, target = "body", position = "before") {
+ var _a, _b;
+ const targetElement = document.querySelector(target);
+ if (typeof html === "object") {
+ html = html.outerHTML;
+ }
+ if (targetElement) {
+ const htmlElement = document.createRange().createContextualFragment(html);
+ if (position === "before") {
+ (_a = targetElement.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(htmlElement, targetElement);
+ } else {
+ (_b = targetElement.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(htmlElement, targetElement.nextSibling);
+ }
+ }
+ }
+ static removeHtml(target) {
+ const targetElement = document.querySelector(target);
+ if (targetElement) {
+ targetElement.remove();
+ }
+ }
+ static slugify(text) {
+ return text.toString().toLowerCase().replace(/\s+/g, "-") // Replace spaces with -
+ .replace(/[^\w\-]+/g, "") // Remove all non-word chars
+ .replace(/\-\-+/g, "-") // Replace multiple - with single -
+ .replace(/^-+/, "") // Trim - from start of text
+ .replace(/-+$/, ""); // Trim - from end of text
+ }
+ // This function is used to run a callback function when an error is displayed on the page
+ static watchForError(callback) {
+ const errorElement = document.querySelector(".en__errorList");
+ const capitalize = word => word.charAt(0).toUpperCase() + word.slice(1);
+ // Avoid duplicate callbacks
+ let callbackType = callback.toString();
+ if (callbackType.indexOf("function") === 0) {
+ callbackType = callbackType.replace("function ", "");
+ }
+ if (callbackType.indexOf("(") > 0) {
+ callbackType = callbackType.substring(0, callbackType.indexOf("("));
+ }
+ // Remove invalid characters
+ callbackType = callbackType.replace(/[^a-zA-Z0-9]/g, "");
+ // Limit to 20 characters and add prefix
+ callbackType = callbackType.substring(0, 20);
+ callbackType = "engrid" + capitalize(callbackType);
+ if (errorElement && !errorElement.dataset[callbackType]) {
+ errorElement.dataset[callbackType] = "true";
+ const observer = new MutationObserver(function (mutations) {
+ mutations.forEach(function (mutation) {
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+ callback();
+ }
});
+ });
+ observer.observe(errorElement, {
+ childList: true
+ });
}
- sendPostMessage(target, action, data = {}) {
- var _a;
- if (!target)
- return;
- const message = Object.assign({ action }, data);
- if (target === "parent") {
- window.parent.postMessage(message, location.origin);
- }
- else {
- (_a = target.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, location.origin);
- }
+ }
+ // Get the Payment Type
+ static getPaymentType() {
+ return dist_engrid_ENGrid.getFieldValue("transaction.paymenttype");
+ }
+ // Set the Payment Type
+ static setPaymentType(paymentType) {
+ const enFieldPaymentType = dist_engrid_ENGrid.getField("transaction.paymenttype");
+ if (enFieldPaymentType) {
+ const paymentTypeOption = Array.from(enFieldPaymentType.options).find(option => paymentType.toLowerCase() === "card" ? ["card", "visa", "vi"].includes(option.value.toLowerCase()) : paymentType.toLowerCase() === option.value.toLowerCase());
+ if (paymentTypeOption) {
+ paymentTypeOption.selected = true;
+ enFieldPaymentType.value = paymentTypeOption.value;
+ } else {
+ enFieldPaymentType.value = paymentType;
+ }
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true
+ });
+ enFieldPaymentType.dispatchEvent(event);
}
+ }
+ static isInViewport(element) {
+ const rect = element.getBoundingClientRect();
+ return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */ && rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */;
+ }
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/donation-frequency.js
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/us-only-form.js
-/*
- * This class disables the country field and fixes the country to "United States"
- */
-class UsOnlyForm {
- constructor() {
- if (!this.shouldRun())
- return;
- if (!document.querySelector(".en__field--country .en__field__notice")) {
- engrid_ENGrid.addHtml('Note: This action is limited to U.S. addresses.
', ".us-only-form .en__field--country .en__field__element", "after");
- }
- const countrySelect = engrid_ENGrid.getField("supporter.country");
- countrySelect.setAttribute("disabled", "disabled");
- let countryValue = "United States";
- if ([...countrySelect.options].some((o) => o.value === "US")) {
- countryValue = "US";
- }
- else if ([...countrySelect.options].some((o) => o.value === "USA")) {
- countryValue = "USA";
+class donation_frequency_DonationFrequency {
+ constructor() {
+ this._onFrequencyChange = new strongly_typed_events_dist/* SimpleEventDispatcher */.IL();
+ this._frequency = "onetime";
+ this._recurring = "n";
+ this._dispatch = true;
+ // Watch the Radios for Changes
+ document.addEventListener("change", e => {
+ const element = e.target;
+ if (element && element.name == "transaction.recurrpay") {
+ this.recurring = element.value;
+ // When this element is a radio, that means you're between onetime and monthly only
+ if (element.type == "radio") {
+ this.frequency = element.value.toLowerCase() == "n" ? "onetime" : "monthly";
+ // This field is hidden when transaction.recurrpay is radio
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrfreq", this.frequency.toUpperCase());
}
- engrid_ENGrid.setFieldValue("supporter.country", countryValue);
- engrid_ENGrid.createHiddenInput("supporter.country", countryValue);
- countrySelect.addEventListener("change", () => {
- countrySelect.value = countryValue;
- });
+ }
+ if (element && element.name == "transaction.recurrfreq") {
+ this.frequency = element.value;
+ }
+ });
+ //Thank you page handling for utility classes
+ if (dist_engrid_ENGrid.getGiftProcess()) {
+ dist_engrid_ENGrid.setBodyData("transaction-recurring-frequency", sessionStorage.getItem("engrid-transaction-recurring-frequency") || "onetime");
+ dist_engrid_ENGrid.setBodyData("transaction-recurring", window.pageJson.recurring ? "y" : "n");
+ }
+ }
+ static getInstance() {
+ if (!donation_frequency_DonationFrequency.instance) {
+ donation_frequency_DonationFrequency.instance = new donation_frequency_DonationFrequency();
+ }
+ return donation_frequency_DonationFrequency.instance;
+ }
+ get frequency() {
+ return this._frequency;
+ }
+ // Every time we set a frequency, trigger the onFrequencyChange event
+ set frequency(value) {
+ this._frequency = value.toLowerCase() || "onetime";
+ if (this._dispatch) this._onFrequencyChange.dispatch(this._frequency);
+ dist_engrid_ENGrid.setBodyData("transaction-recurring-frequency", this._frequency);
+ sessionStorage.setItem("engrid-transaction-recurring-frequency", this._frequency);
+ }
+ get recurring() {
+ return this._recurring;
+ }
+ set recurring(value) {
+ this._recurring = value.toLowerCase() || "n";
+ dist_engrid_ENGrid.setBodyData("transaction-recurring", this._recurring);
+ }
+ get onFrequencyChange() {
+ return this._onFrequencyChange.asEvent();
+ }
+ // Set amount var with currently selected amount
+ load() {
+ var _a;
+ this.frequency = dist_engrid_ENGrid.getFieldValue("transaction.recurrfreq") || sessionStorage.getItem("engrid-transaction-recurring-frequency") || "onetime";
+ const recurrField = dist_engrid_ENGrid.getField("transaction.recurrpay");
+ if (recurrField) {
+ this.recurring = dist_engrid_ENGrid.getFieldValue("transaction.recurrpay");
+ } else if (dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getSupporterData")) {
+ this.recurring = ((_a = window.EngagingNetworks.require._defined.enjs.getSupporterData("recurrpay")) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "n";
+ }
+ // ENGrid.enParseDependencies();
+ }
+ // Force a new recurrency
+ setRecurrency(recurr, dispatch = true) {
+ // Run only if it is a Donation Page with a Recurrency
+ if (!document.getElementsByName("transaction.recurrpay").length) {
+ return;
}
- shouldRun() {
- return !!document.querySelector(".en__component--formblock.us-only-form .en__field--country");
+ // Set dispatch to be checked by the SET method
+ this._dispatch = dispatch;
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrpay", recurr.toUpperCase());
+ // Revert dispatch to default value (true)
+ this._dispatch = true;
+ }
+ // Force a new frequency
+ setFrequency(freq, dispatch = true) {
+ // Run only if it is a Donation Page with a Frequency
+ if (!document.getElementsByName("transaction.recurrfreq").length) {
+ return;
}
+ // Set dispatch to be checked by the SET method
+ this._dispatch = dispatch;
+ // Search for the current amount on radio boxes
+ let found = Array.from(document.querySelectorAll('input[name="transaction.recurrfreq"]')).filter(el => el instanceof HTMLInputElement && el.value == freq.toUpperCase());
+ // We found the amount on the radio boxes, so check it
+ if (found.length) {
+ const freqField = found[0];
+ freqField.checked = true;
+ this.frequency = freq.toLowerCase();
+ if (this.frequency === "onetime") {
+ this.setRecurrency("N", dispatch);
+ } else {
+ this.setRecurrency("Y", dispatch);
+ }
+ }
+ // Revert dispatch to default value (true)
+ this._dispatch = true;
+ }
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/processing-fees.js
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/thank-you-page-conditional-content.js
-class ThankYouPageConditionalContent {
- constructor() {
- this.logger = new logger_EngridLogger("ThankYouPageConditionalContent");
- if (!this.shouldRun())
- return;
- this.applyShowHideRadioCheckboxesState();
+
+class processing_fees_ProcessingFees {
+ constructor() {
+ this._onFeeChange = new strongly_typed_events_dist/* SimpleEventDispatcher */.IL();
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._form = events_en_form_EnForm.getInstance();
+ this._fee = 0;
+ this._field = null;
+ // console.log('%c Processing Fees Constructor', 'font-size: 30px; background-color: #000; color: #FF0');
+ // Run only if it is a Donation Page with a Donation Amount field
+ if (!document.getElementsByName("transaction.donationAmt").length) {
+ return;
}
- getShowHideRadioCheckboxesState() {
- var _a;
- try {
- const plainState = (_a = window.sessionStorage.getItem(`engrid_ShowHideRadioCheckboxesState`)) !== null && _a !== void 0 ? _a : "";
- return JSON.parse(plainState);
- }
- catch (err) {
- return [];
+ this._field = this.isENfeeCover() ? document.querySelector("#en__field_transaction_feeCover") : document.querySelector('input[name="supporter.processing_fees"]');
+ // Watch the Radios for Changes
+ if (this._field instanceof HTMLInputElement) {
+ // console.log('%c Processing Fees Start', 'font-size: 30px; background-color: #000; color: #FF0');
+ this._field.addEventListener("change", e => {
+ if (this._field instanceof HTMLInputElement && this._field.checked && !this._subscribe) {
+ this._subscribe = this._form.onSubmit.subscribe(() => this.addFees());
}
+ this._onFeeChange.dispatch(this.fee);
+ // // console.log('%c Processing Fees Script Applied', 'font-size: 30px; background-color: #000; color: #FF0');
+ });
}
- applyShowHideRadioCheckboxesState() {
- const state = this.getShowHideRadioCheckboxesState();
- if (state) {
- state.forEach((item) => {
- this.logger.log("Processing TY page conditional content item:", item);
- if (engrid_ENGrid.getPageID() === item.page) {
- document
- .querySelectorAll(`[class*="${item.class}"]`)
- .forEach((el) => {
- el.classList.add("hide");
- });
- document
- .querySelectorAll(`.${item.class}${item.value}`)
- .forEach((el) => {
- el.classList.remove("hide");
- });
- }
- });
- }
- this.deleteShowHideRadioCheckboxesState();
+ // this._amount = amount;
+ }
+ static getInstance() {
+ if (!processing_fees_ProcessingFees.instance) {
+ processing_fees_ProcessingFees.instance = new processing_fees_ProcessingFees();
}
- deleteShowHideRadioCheckboxesState() {
- window.sessionStorage.removeItem(`engrid_ShowHideRadioCheckboxesState`);
+ return processing_fees_ProcessingFees.instance;
+ }
+ get onFeeChange() {
+ return this._onFeeChange.asEvent();
+ }
+ get fee() {
+ return this.calculateFees();
+ }
+ // Every time we set a frequency, trigger the onFrequencyChange event
+ set fee(value) {
+ this._fee = value;
+ this._onFeeChange.dispatch(this._fee);
+ }
+ calculateFees(amount = 0) {
+ var _a;
+ if (this._field instanceof HTMLInputElement && this._field.checked) {
+ if (this.isENfeeCover()) {
+ return amount > 0 ? window.EngagingNetworks.require._defined.enjs.feeCover.fee(amount) : window.EngagingNetworks.require._defined.enjs.getDonationFee();
+ }
+ const fees = Object.assign({
+ processingfeepercentadded: "0",
+ processingfeefixedamountadded: "0"
+ }, (_a = this._field) === null || _a === void 0 ? void 0 : _a.dataset);
+ const amountToFee = amount > 0 ? amount : this._amount.amount;
+ const processing_fee = parseFloat(fees.processingfeepercentadded) / 100 * amountToFee + parseFloat(fees.processingfeefixedamountadded);
+ return Math.round(processing_fee * 100) / 100;
+ }
+ return 0;
+ }
+ // Add Fees to Amount
+ addFees() {
+ if (this._form.submit && !this.isENfeeCover()) {
+ this._amount.setAmount(this._amount.amount + this.fee, false);
+ }
+ }
+ // Remove Fees From Amount
+ removeFees() {
+ if (!this.isENfeeCover()) this._amount.setAmount(this._amount.amount - this.fee);
+ }
+ // Check if this is a Processing Fee from EN
+ isENfeeCover() {
+ if ("feeCover" in window.EngagingNetworks) {
+ for (const key in window.EngagingNetworks.feeCover) {
+ if (window.EngagingNetworks.feeCover.hasOwnProperty(key)) {
+ return true;
+ }
+ }
}
- shouldRun() {
- return engrid_ENGrid.getGiftProcess();
+ return false;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/remember-me-events.js
+/**
+ * This class is responsible for managing events related to the "Remember Me" functionality.
+ * It uses the Singleton design pattern to ensure only one instance of this class exists.
+ * It provides methods for dispatching load and clear events, and getters for accessing these events.
+ */
+
+
+class remember_me_events_RememberMeEvents {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("RememberMeEvents");
+ this._onLoad = new strongly_typed_events_dist/* SimpleEventDispatcher */.IL();
+ this._onClear = new strongly_typed_events_dist/* SignalDispatcher */.UD();
+ this.hasData = false;
+ }
+ static getInstance() {
+ if (!remember_me_events_RememberMeEvents.instance) {
+ remember_me_events_RememberMeEvents.instance = new remember_me_events_RememberMeEvents();
}
+ return remember_me_events_RememberMeEvents.instance;
+ }
+ dispatchLoad(hasData) {
+ this.hasData = hasData;
+ this._onLoad.dispatch(hasData);
+ this.logger.log(`dispatchLoad: ${hasData}`);
+ }
+ dispatchClear() {
+ this._onClear.dispatch();
+ this.logger.log("dispatchClear");
+ }
+ get onLoad() {
+ return this._onLoad.asEvent();
+ }
+ get onClear() {
+ return this._onClear.asEvent();
+ }
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/iframe-queue-events.js
+/**
+ * Singleton event hub for the Iframe Queue component.
+ *
+ * Mirrors the structure of RememberMeEvents: private constructor,
+ * static `getInstance()`, internal dispatchers exposed via `.asEvent()`
+ * getters, and `dispatch*` methods called by the IframeQueue class.
+ *
+ * External code subscribes to these events to react to queue
+ * lifecycle without holding a reference to the IframeQueue itself.
+ * The TNC Bequest Lightbox, for example, will subscribe to
+ * `onChainComplete` so it only opens after the QCB opt-in chain has
+ * finished submitting.
+ *
+ * @example
+ * IframeQueueEvents.getInstance().onChainComplete.subscribe(() => {
+ * openBequestLightbox();
+ * });
+ */
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/checkbox-label.js
-// Component to allow the user to set custom labels for the checkboxes,
-// you can customize the checkbox label on a per-page basis, which is not possible with Engaging Networks
-// The .checkbox-label element should be placed right before the checkbox form block
-class CheckboxLabel {
- constructor() {
- this.logger = new logger_EngridLogger("CheckboxLabel", "#00CC95", "#2C3E50", "β
");
- this.checkBoxesLabels = document.querySelectorAll(".checkbox-label");
- if (!this.shoudRun())
- return;
- this.logger.log(`Found ${this.checkBoxesLabels.length} custom labels`);
- this.run();
+class events_iframe_queue_events_IframeQueueEvents {
+ constructor() {
+ this.logger = new EngridLogger("IframeQueueEvents");
+ this._onChainComplete = new SignalDispatcher();
+ this._onChainError = new SimpleEventDispatcher();
+ this._onItemStart = new SimpleEventDispatcher();
+ this._onItemComplete = new SimpleEventDispatcher();
+ this._onItemError = new SimpleEventDispatcher();
+ }
+ /** Returns the shared IframeQueueEvents singleton. */
+ static getInstance() {
+ if (!events_iframe_queue_events_IframeQueueEvents.instance) {
+ events_iframe_queue_events_IframeQueueEvents.instance = new events_iframe_queue_events_IframeQueueEvents();
}
- shoudRun() {
- return this.checkBoxesLabels.length > 0;
+ return events_iframe_queue_events_IframeQueueEvents.instance;
+ }
+ /**
+ * Fires once when the entire queue completes successfully.
+ * Use to trigger work that must wait for all chained iframe submits
+ * (e.g. opening a bequest lightbox after QCB opt-ins are recorded).
+ */
+ get onChainComplete() {
+ return this._onChainComplete.asEvent();
+ }
+ /**
+ * Fires when the queue aborts due to an error (timeout, iframe load
+ * error, or error message from an embedded page). Carries the failed
+ * item (if known) and the underlying error.
+ */
+ get onChainError() {
+ return this._onChainError.asEvent();
+ }
+ /** Fires immediately before an item begins processing. */
+ get onItemStart() {
+ return this._onItemStart.asEvent();
+ }
+ /** Fires when an item completes (its iframe reached its Thank You page). */
+ get onItemComplete() {
+ return this._onItemComplete.asEvent();
+ }
+ /** Fires when an item fails. The queue aborts after this event. */
+ get onItemError() {
+ return this._onItemError.asEvent();
+ }
+ /** Internal β called by IframeQueue when the queue drains successfully. */
+ dispatchChainComplete() {
+ this.logger.log("dispatchChainComplete");
+ this._onChainComplete.dispatch();
+ }
+ /** Internal β called by IframeQueue when the queue aborts on error. */
+ dispatchChainError(payload) {
+ this.logger.log(`dispatchChainError: ${payload.message}`);
+ this._onChainError.dispatch(payload);
+ }
+ /** Internal β called by IframeQueue immediately before an item starts. */
+ dispatchItemStart(item) {
+ this.logger.log(`dispatchItemStart: ${item.url}`);
+ this._onItemStart.dispatch(item);
+ }
+ /** Internal β called by IframeQueue when an item finishes successfully. */
+ dispatchItemComplete(item) {
+ this.logger.log(`dispatchItemComplete: ${item.url}`);
+ this._onItemComplete.dispatch(item);
+ }
+ /** Internal β called by IframeQueue when an item errors. */
+ dispatchItemError(item, error) {
+ this.logger.log(`dispatchItemError: ${item.url} - ${error.message}`);
+ this._onItemError.dispatch({
+ item,
+ error
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/country.js
+
+
+class country_Country {
+ constructor() {
+ this._onCountryChange = new strongly_typed_events_dist/* SimpleEventDispatcher */.IL();
+ this._country = "";
+ this._field = null;
+ // Run only if it is a Page with a Country field
+ this._field = document.getElementById("en__field_supporter_country");
+ if (!this._field) {
+ return;
}
- run() {
- this.checkBoxesLabels.forEach((checkboxLabel) => {
- const labelHTML = checkboxLabel.innerHTML.trim();
- const checkboxContainer = checkboxLabel.nextElementSibling;
- const checkboxLabelElement = checkboxContainer.querySelector("label:last-child");
- if (!checkboxLabelElement || !labelHTML)
- return;
- checkboxLabelElement.innerHTML = `${labelHTML}
`;
- // Remove the original label element
- checkboxLabel.remove();
- this.logger.log(`Set checkbox label to "${labelHTML}"`);
- });
+ document.addEventListener("change", e => {
+ const element = e.target;
+ if (element && element.name == "supporter.country") {
+ this.country = element.value;
+ }
+ });
+ // Set the country to the current value on the field
+ this.country = dist_engrid_ENGrid.getFieldValue("supporter.country");
+ }
+ static getInstance() {
+ if (!country_Country.instance) {
+ country_Country.instance = new country_Country();
}
+ return country_Country.instance;
+ }
+ get countryField() {
+ return this._field;
+ }
+ get onCountryChange() {
+ return this._onCountryChange.asEvent();
+ }
+ get country() {
+ return this._country;
+ }
+ // Every time we set a country, trigger the onCountryChange event
+ set country(value) {
+ this._country = value;
+ this._onCountryChange.dispatch(this._country);
+ }
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/events/index.js
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/optin-ladder.js
-/**
- * Docs: https://engrid.4sitestudios.com/component/optin-ladder
- * This component is responsible for showing a ladder of checkboxes, one at a time, to the user.
- * If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit.
- * If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match.
- * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps.
- * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page.
- */
-class OptInLadder {
- constructor() {
- this.logger = new EngridLogger("OptInLadder", "lightgreen", "darkgreen", "β");
- this._form = EnForm.getInstance();
- if (!this.inIframe()) {
- this.runAsParent();
- }
- else if (ENGrid.getPageNumber() === 1) {
- this.runAsChildRegular();
- }
- else {
- this.runAsChildThankYou();
- }
+
+
+
+
+
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/app.js
+
+
+class app_App extends dist_engrid_ENGrid {
+ constructor(options) {
+ super();
+ // Events
+ this._form = events_en_form_EnForm.getInstance();
+ this._fees = processing_fees_ProcessingFees.getInstance();
+ this._amount = donation_amount_DonationAmount.getInstance("transaction.donationAmt", "transaction.donationAmt.other");
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._country = country_Country.getInstance();
+ this.logger = new dist_logger_EngridLogger("App", "black", "white", "π");
+ const loader = new loader_Loader();
+ this.options = Object.assign(Object.assign({}, options_OptionsDefaults), options);
+ // Add Options to window
+ window.EngridOptions = this.options;
+ this._dataLayer = data_layer_DataLayer.getInstance();
+ // If there's a ?pbedit query string, redirect to the page builder to edit on EN
+ if (dist_engrid_ENGrid.getUrlParameter("pbedit") === true || dist_engrid_ENGrid.getUrlParameter("pbedit") === "true") {
+ window.location.href = `https://${dist_engrid_ENGrid.getDataCenter()}.engagingnetworks.app/index.html#pages/${dist_engrid_ENGrid.getPageID()}/edit`;
+ return;
}
- runAsParent() {
- this.logger.log("Running as Parent");
- if (ENGrid.getPageNumber() > 1 &&
- ENGrid.getPageNumber() === ENGrid.getPageCount()) {
- // We are on the Thank You Page as a Parent
- // Check autoinject iFrame
- const optInLadderOptions = ENGrid.getOption("OptInLadder");
- if (!optInLadderOptions || !optInLadderOptions.iframeUrl) {
- this.logger.log("Options not found");
- return;
- }
- // Create an iFrame
- const iframe = document.createElement("iframe");
- iframe.src = optInLadderOptions.iframeUrl;
- iframe.style.width = "100%";
- iframe.style.height = "0";
- iframe.scrolling = "no";
- iframe.frameBorder = "0";
- iframe.allowFullscreen = true;
- iframe.allow = "payment";
- iframe.classList.add("opt-in-ladder-iframe");
- iframe.classList.add("engrid-iframe");
- iframe.setAttribute("title", "Optin Ladder iframe");
- // If the page already has an iFrame with the same class, we don't need to add another one
- const existingIframe = document.querySelector(".opt-in-ladder-iframe");
- if (existingIframe) {
- this.logger.log("iFrame already exists");
- return;
- }
- // Check if the current page is part of the excludePageIDs
- if (optInLadderOptions.excludePageIDs &&
- optInLadderOptions.excludePageIDs.includes(ENGrid.getPageID())) {
- this.logger.log("Current page is excluded");
- return;
- }
- // Append the iFrame to the proper placement
- const placementQuerySelector = optInLadderOptions.placementQuerySelector || ".body-top";
- const placement = document.querySelector(placementQuerySelector);
- if (!placement) {
- this.logger.error("Placement not found");
- return;
- }
- placement.appendChild(iframe);
- }
- else {
- // Grab all the checkboxes with the name starting with "supporter.questions"
- const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
- if (checkboxes.length === 0) {
- this.logger.log("No checkboxes found");
- return;
- }
- this._form.onSubmit.subscribe(() => {
- // Save the checkbox values to sessionStorage
- this.saveOptInsToSessionStorage("parent");
- });
- if (ENGrid.getPageNumber() === 1) {
- // Delete items from sessionStorage
- this.clearSessionStorage();
- }
- }
+ if (loader.reload()) return;
+ // Turn Debug ON if you use local assets
+ if (dist_engrid_ENGrid.getBodyData("assets") === "local" && dist_engrid_ENGrid.getUrlParameter("debug") !== "false" && dist_engrid_ENGrid.getUrlParameter("debug") !== "log") {
+ window.EngridOptions.Debug = true;
}
- runAsChildRegular() {
- if (!this.isEmbeddedThankYouPage()) {
- this.logger.log("Not Embedded on a Thank You Page");
- return;
- }
- const optInHeaders = document.querySelectorAll(".en__component--copyblock.optin-ladder");
- const optInFormBlocks = document.querySelectorAll(".en__component--formblock.optin-ladder");
- if (optInHeaders.length === 0 && optInFormBlocks.length === 0) {
- this.logger.log("No optin-ladder elements found");
- return;
- }
- // Check if the e-mail field exist and is not empty
- const emailField = ENGrid.getField("supporter.emailAddress");
- if (!emailField || !emailField.value) {
- this.logger.log("Email field is empty");
- // Since this is a OptInLadder page with no e-mail address, hide the page
- this.hidePage(true);
- return;
+ // Document Load
+ if (document.readyState !== "loading") {
+ this.run();
+ } else {
+ document.addEventListener("DOMContentLoaded", () => {
+ this.run();
+ });
+ }
+ // Window Resize
+ window.onresize = () => {
+ this.onResize();
+ };
+ }
+ run() {
+ if (!dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs")) {
+ this.logger.danger("Engaging Networks JS Framework NOT FOUND");
+ setTimeout(() => {
+ this.run();
+ }, 100);
+ return;
+ }
+ // If there's an option object on the page, override the defaults
+ if (window.hasOwnProperty("EngridPageOptions")) {
+ this.options = Object.assign(Object.assign({}, this.options), window.EngridPageOptions);
+ // Add Options to window
+ window.EngridOptions = this.options;
+ }
+ // If there's no pageJson.pageType, add a big red warning to the console
+ if (!dist_engrid_ENGrid.checkNested(window, "pageJson", "pageType")) {
+ window.setTimeout(() => {
+ console.log("%c βοΈ pageJson.pageType NOT FOUND - Go to the Account Settings and Expose the Transaction Details %s", "background-color: red; color: white; font-size: 22px; font-weight: bold;", "https://knowledge.engagingnetworks.net/datareports/expose-transaction-details-pagejson");
+ }, 2000);
+ }
+ if (this.options.Debug || app_App.getUrlParameter("debug") == "true")
+ // Enable debug if available is the first thing
+ app_App.setBodyData("debug", "");
+ new advocacy_Advocacy();
+ new input_placeholders_InputPlaceholders();
+ new input_has_value_and_focus_InputHasValueAndFocus();
+ // Give By Select
+ new give_by_select_GiveBySelect();
+ new show_hide_radio_checkboxes_ShowHideRadioCheckboxes("transaction.giveBySelect", "giveBySelect-");
+ new show_hide_radio_checkboxes_ShowHideRadioCheckboxes("transaction.inmem", "inmem-");
+ new show_hide_radio_checkboxes_ShowHideRadioCheckboxes("transaction.recurrpay", "recurrpay-");
+ new show_hide_radio_checkboxes_ShowHideRadioCheckboxes("transaction.shipenabled", "shipenabled-");
+ // Automatically show/hide all radios
+ let radioFields = [];
+ const allRadios = document.querySelectorAll("input[type=radio]");
+ allRadios.forEach(radio => {
+ if ("name" in radio && radioFields.includes(radio.name) === false) {
+ radioFields.push(radio.name);
+ }
+ });
+ radioFields.forEach(field => {
+ new show_hide_radio_checkboxes_ShowHideRadioCheckboxes(field, "engrid__" + field.replace(/\./g, "") + "-");
+ });
+ // Automatically show/hide all checkboxes
+ const allCheckboxes = document.querySelectorAll("input[type=checkbox]");
+ allCheckboxes.forEach(checkbox => {
+ if ("name" in checkbox) {
+ new show_hide_radio_checkboxes_ShowHideRadioCheckboxes(checkbox.name, "engrid__" + checkbox.name.replace(/\./g, "") + "-");
+ }
+ });
+ // Client onSubmit and onError functions
+ this._form.onIntentSubmit.subscribe(() => this.onIntentSubmit());
+ this._form.onSubmit.subscribe(() => this.onSubmit());
+ this._form.onError.subscribe(() => this.onError());
+ this._form.onValidate.subscribe(() => this.onValidate());
+ // Event Listener Examples
+ this._amount.onAmountChange.subscribe(s => this.logger.success(`Live Amount: ${s}`));
+ this._frequency.onFrequencyChange.subscribe(s => {
+ this.logger.success(`Live Frequency: ${s}`);
+ setTimeout(() => {
+ this._amount.load();
+ }, 150);
+ });
+ this._form.onSubmit.subscribe(s => this.logger.success("Submit: " + JSON.stringify(s)));
+ this._form.onError.subscribe(s => this.logger.danger("Error: " + JSON.stringify(s)));
+ this._country.onCountryChange.subscribe(s => this.logger.success(`Country: ${s}`));
+ window.enOnSubmit = () => {
+ this._form.submit = true;
+ this._form.submitPromise = false;
+ this._form.dispatchIntentSubmit();
+ this._form.dispatchSubmit();
+ dist_engrid_ENGrid.watchForError(dist_engrid_ENGrid.enableSubmit);
+ if (!this._form.submit) return false;
+ if (this._form.submitPromise) return this._form.submitPromise;
+ this.logger.success("enOnSubmit Success");
+ // If all validation passes, we'll watch for Digital Wallets Errors, which
+ // will not reload the page (thanks EN), so we will enable the submit button if
+ // an error is programmatically thrown by the Digital Wallets
+ return true;
+ };
+ window.enOnError = () => {
+ this._form.dispatchError();
+ };
+ window.enOnValidate = () => {
+ this._form.validate = true;
+ this._form.validatePromise = false;
+ this._form.dispatchValidate();
+ if (!this._form.validate) return false;
+ if (this._form.validatePromise) return this._form.validatePromise;
+ this.logger.success("Validation Passed");
+ return true;
+ };
+ new data_attributes_DataAttributes();
+ // Country Redirect
+ new country_redirect_CountryRedirect();
+ // iFrame Logic
+ new iframe_iFrame();
+ // Live Variables
+ new live_variables_LiveVariables(this.options);
+ // Dynamically set Recurrency Frequency
+ new set_recurr_freq_setRecurrFreq();
+ // Upsell Checkbox
+ new upsell_checkbox_UpsellCheckbox();
+ // Upsell Lightbox
+ new upsell_lightbox_UpsellLightbox();
+ // Amount Labels
+ new amount_label_AmountLabel();
+ // Engrid Data Replacement
+ new data_replace_DataReplace();
+ // ENgrid Hide Script
+ new data_hide_DataHide();
+ // Autosubmit script
+ new autosubmit_Autosubmit();
+ // Adjust display of event tickets.
+ new event_tickets_EventTickets();
+ // StickyNSG - Must load before SwapAmounts
+ new sticky_nsg_StickyNSG();
+ // Swap Amounts
+ new swap_amounts_SwapAmounts();
+ // On the end of the script, after all subscribers defined, let's load the current frequency
+ // The amount will be loaded by the frequency change event
+ // This timeout is needed because when you have alternative amounts, EN is slower than Engrid
+ // about 20% of the time and we get a race condition if the client is also using the SwapAmounts feature
+ window.setTimeout(() => {
+ this._frequency.load();
+ }, 1000);
+ // Fast Form Fill
+ new fast_form_fill_FastFormFill();
+ // Currency Related Components
+ new live_currency_LiveCurrency();
+ new custom_currency_CustomCurrency();
+ // Auto Country Select
+ new auto_country_select_AutoCountrySelect();
+ // Add Image Attribution
+ if (this.options.MediaAttribution) new media_attribution_MediaAttribution();
+ // Apple Pay
+ if (this.options.applePay) new apple_pay_ApplePay();
+ // Capitalize Fields
+ if (this.options.CapitalizeFields) new capitalize_fields_CapitalizeFields();
+ // Auto Year Class
+ if (this.options.AutoYear) new auto_year_AutoYear();
+ // Autocomplete Class
+ new autocomplete_Autocomplete();
+ // Ecard Class
+ new ecard_Ecard();
+ // Click To Expand
+ if (this.options.ClickToExpand) new click_to_expand_ClickToExpand();
+ if (this.options.SkipToMainContentLink) new skip_link_SkipToMainContentLink();
+ if (this.options.SrcDefer) new src_defer_SrcDefer();
+ // Progress Bar
+ if (this.options.ProgressBar) new progress_bar_ProgressBar();
+ // RememberMe
+ try {
+ // Accessing window.localStorage will throw an exception if it isn't permitted due to security reasons
+ // For example, this happens in Firefox when cookies are disabled. If it isn't available, we shouldn't
+ // bother with enabling RememberMe
+ if (this.options.RememberMe && typeof this.options.RememberMe === "object" && window.localStorage) {
+ new remember_me_RememberMe(this.options.RememberMe);
+ }
+ } catch (e) {}
+ if (this.options.NeverBounceAPI) new neverbounce_NeverBounce(this.options.NeverBounceAPI, this.options.NeverBounceDateField, this.options.NeverBounceStatusField, this.options.NeverBounceDateFormat);
+ // FreshAddress
+ if (this.options.FreshAddress) new freshaddress_FreshAddress();
+ new show_if_amount_ShowIfAmount();
+ new other_amount_OtherAmount();
+ new min_max_amount_MinMaxAmount();
+ new ticker_Ticker();
+ new a11y_A11y();
+ new add_name_to_message_AddNameToMessage();
+ new expand_region_name_ExpandRegionName();
+ // Page Background
+ new page_background_PageBackground();
+ // Url Params to Form Fields
+ new url_to_form_UrlToForm();
+ // Required if Visible Fields
+ new required_if_visible_RequiredIfVisible();
+ // EN Custom Validators (behind a feature flag, off by default)
+ new en_validators_ENValidators();
+ //Debug hidden fields
+ if (this.options.Debug) new debug_hidden_fields_DebugHiddenFields();
+ // TidyContact
+ if (this.options.TidyContact) new tidycontact_TidyContact();
+ // Translate Fields
+ if (this.options.TranslateFields) new translate_fields_TranslateFields();
+ // Country Disable
+ new country_disable_CountryDisable();
+ // Premium Gift Features
+ new premium_gift_PremiumGift();
+ // Custom Premium filtering (frequency/amount-based visibility)
+ new custom_premium_CustomPremium();
+ // Supporter Hub Features
+ new supporter_hub_SupporterHub();
+ // Digital Wallets Features
+ if (dist_engrid_ENGrid.getPageType() === "DONATION") {
+ new digital_wallets_DigitalWallets();
+ new preferred_payment_method_PreferredPaymentMethod();
+ }
+ // Mobile CTA
+ new mobile_cta_MobileCTA();
+ // Live Frequency
+ new live_frequency_LiveFrequency();
+ // Universal Opt In
+ new universal_opt_in_UniversalOptIn();
+ new stripe_financial_connections_StripeFinancialConnections();
+ //Exit Intent Lightbox
+ new exit_intent_lightbox_ExitIntentLightbox();
+ new url_params_to_body_attrs_UrlParamsToBodyAttrs();
+ new set_attr_SetAttr();
+ new show_if_present_ShowIfPresent();
+ new postal_code_validator_PostalCodeValidator();
+ // Very Good Security
+ new vgs_VGS();
+ new welcome_back_WelcomeBack();
+ new ecard_to_target_EcardToTarget();
+ new us_only_form_UsOnlyForm();
+ new thank_you_page_conditional_content_ThankYouPageConditionalContent();
+ new embedded_ecard_EmbeddedEcard();
+ new checkbox_label_CheckboxLabel();
+ new post_donation_embed_PostDonationEmbed();
+ new frequency_upsell_FrequencyUpsell();
+ new sticky_prepopulation_StickyPrepopulation();
+ //Debug panel
+ let showDebugPanel = this.options.Debug;
+ try {
+ // accessing storage can throw an exception if it isn't available in Firefox
+ if (!showDebugPanel && window.sessionStorage.hasOwnProperty(debug_panel_DebugPanel.debugSessionStorageKey)) {
+ showDebugPanel = true;
+ }
+ } catch (e) {}
+ if (showDebugPanel) {
+ new debug_panel_DebugPanel(this.options.PageLayouts);
+ }
+ if (dist_engrid_ENGrid.getUrlParameter("development") === "branding") {
+ new branding_html_BrandingHtml().show();
+ }
+ dist_engrid_ENGrid.setBodyData("js-loading", "finished");
+ window.EngridVersion = version_AppVersion;
+ this.logger.success(`VERSION: ${version_AppVersion}`);
+ // Window Load
+ let onLoad = typeof window.onload === "function" ? window.onload : null;
+ if (document.readyState !== "loading") {
+ this.onLoad();
+ } else {
+ window.onload = e => {
+ this.onLoad();
+ if (onLoad) {
+ onLoad.bind(window, e);
}
- const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
- let currentStep = 0;
- let totalSteps = optInHeaders.length;
- let currentHeader = null;
- let currentFormBlock = null;
- for (let i = 0; i < optInHeaders.length; i++) {
- const header = optInHeaders[i];
- // Get the optin number from the .optin-ladder-XXXX class
- const optInNumber = header.className.match(/optin-ladder-(\d+)/);
- if (!optInNumber) {
- this.logger.error(`No optin number found in ${header.innerText.trim()}`);
- return;
- }
- const optInIndex = optInNumber[1];
- // Get the checkbox FormBlock
- const formBlock = document.querySelector(`.en__component--formblock.optin-ladder:has(.en__field--${optInIndex})`);
- if (!formBlock) {
- this.logger.log(`No form block found for ${header.innerText.trim()}`);
- // Remove the header if there is no form block
- header.remove();
- // Increment the current step
- currentStep++;
- continue;
- }
- // Check if the optInIndex is in sessionStorage
- if (sessionStorageCheckboxValues[optInIndex] === "Y") {
- // If the checkbox is checked, remove the header and form block
- header.remove();
- formBlock.remove();
- // Increment the current step
- currentStep++;
- continue;
- }
- // If there's a header and a form block, end the loop
- currentHeader = header;
- currentFormBlock = formBlock;
- currentStep++;
- break;
+ };
+ }
+ }
+ onLoad() {
+ if (this.options.onLoad) {
+ this.options.onLoad();
+ }
+ }
+ onResize() {
+ if (this.options.onResize) {
+ this.options.onResize();
+ }
+ }
+ onValidate() {
+ if (this.options.onValidate) {
+ this.logger.log("Client onValidate Triggered");
+ this.options.onValidate();
+ }
+ }
+ onIntentSubmit() {
+ if (this.options.onIntentSubmit) {
+ this.logger.log("Client onIntentSubmit Triggered");
+ this.options.onIntentSubmit();
+ }
+ }
+ onSubmit() {
+ if (this.options.onSubmit) {
+ this.logger.log("Client onSubmit Triggered");
+ this.options.onSubmit();
+ }
+ }
+ onError() {
+ if (this.options.onError) {
+ this.logger.danger("Client onError Triggered");
+ this.options.onError();
+ }
+ }
+ static log(message) {
+ const logger = new dist_logger_EngridLogger("Client", "brown", "aliceblue", "πͺ");
+ logger.log(message);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/amount-label.js
+// This script checks if the donations amounts are numbers and if they are, appends the correct currency symbol
+
+class amount_label_AmountLabel {
+ constructor() {
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ if (!this.shouldRun()) {
+ // If we're not on a Donation Page, get out
+ return;
+ }
+ this._frequency.onFrequencyChange.subscribe(s => window.setTimeout(this.fixAmountLabels.bind(this), 100));
+ // Run the main function on page load so we can analyze the amounts of the current frequency
+ window.setTimeout(this.fixAmountLabels.bind(this), 300);
+ }
+ // Should we run the script?
+ shouldRun() {
+ return !!(dist_engrid_ENGrid.getPageType() === "DONATION" && dist_engrid_ENGrid.getOption("AddCurrencySymbol"));
+ }
+ // Fix Amount Labels
+ fixAmountLabels() {
+ let amounts = document.querySelectorAll(".en__field--donationAmt label");
+ const currencySymbol = dist_engrid_ENGrid.getCurrencySymbol() || "";
+ amounts.forEach(element => {
+ const amountText = element.innerText.replace(/,/g, "").replace(/\./g, "");
+ if (!isNaN(amountText)) {
+ element.innerText = currencySymbol + element.innerText;
+ }
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/apple-pay.js
+var apple_pay_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function (resolve) {
+ resolve(value);
+ });
+ }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
+ }
+ }
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
+ }
+ }
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+/*global window */
+const apple_pay_ApplePaySession = window.ApplePaySession;
+const apple_pay_merchantIdentifier = window.merchantIdentifier;
+const apple_pay_merchantDomainName = window.merchantDomainName;
+const apple_pay_merchantDisplayName = window.merchantDisplayName;
+const apple_pay_merchantSessionIdentifier = window.merchantSessionIdentifier;
+const apple_pay_merchantNonce = window.merchantNonce;
+const apple_pay_merchantEpochTimestamp = window.merchantEpochTimestamp;
+const apple_pay_merchantSignature = window.merchantSignature;
+const apple_pay_merchantCountryCode = window.merchantCountryCode;
+const apple_pay_merchantCurrencyCode = window.merchantCurrencyCode;
+const apple_pay_merchantSupportedNetworks = window.merchantSupportedNetworks;
+const apple_pay_merchantCapabilities = window.merchantCapabilities;
+const apple_pay_merchantTotalLabel = window.merchantTotalLabel;
+class apple_pay_ApplePay {
+ constructor() {
+ this.applePay = document.querySelector('.en__field__input.en__field__input--radio[value="applepay"]');
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._fees = processing_fees_ProcessingFees.getInstance();
+ this._form = events_en_form_EnForm.getInstance();
+ this.checkApplePay();
+ }
+ checkApplePay() {
+ return apple_pay_awaiter(this, void 0, void 0, function* () {
+ const pageform = document.querySelector("form.en__component--page");
+ if (!this.applePay || !window.hasOwnProperty("ApplePaySession")) {
+ const applePayContainer = document.querySelector(".en__field__item.applepay");
+ if (applePayContainer) applePayContainer.remove();
+ if (dist_engrid_ENGrid.debug) console.log("Apple Pay DISABLED");
+ return false;
+ }
+ const promise = apple_pay_ApplePaySession.canMakePaymentsWithActiveCard(apple_pay_merchantIdentifier);
+ let applePayEnabled = false;
+ yield promise.then(canMakePayments => {
+ applePayEnabled = canMakePayments;
+ if (canMakePayments) {
+ let input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("name", "PkPaymentToken");
+ input.setAttribute("id", "applePayToken");
+ pageform.appendChild(input);
+ this._form.onSubmit.subscribe(() => this.onPayClicked());
}
- if (!currentHeader || !currentFormBlock) {
- this.logger.log("No optin-ladder elements found");
- // Set the current step to the total steps to avoid redirecting to the first page
- currentStep = totalSteps;
- this.saveStepToSessionStorage(currentStep, totalSteps);
- // hide the page
- this.hidePage();
- return;
+ });
+ if (dist_engrid_ENGrid.debug) console.log("applePayEnabled", applePayEnabled);
+ let applePayWrapper = this.applePay.closest(".en__field__item");
+ if (applePayEnabled) {
+ // Set Apple Pay Class
+ applePayWrapper === null || applePayWrapper === void 0 ? void 0 : applePayWrapper.classList.add("applePayWrapper");
+ } else {
+ // Hide Apple Pay Wrapper
+ if (applePayWrapper) applePayWrapper.style.display = "none";
+ }
+ return applePayEnabled;
+ });
+ }
+ performValidation(url) {
+ return new Promise(function (resolve, reject) {
+ var merchantSession = {};
+ merchantSession.merchantIdentifier = apple_pay_merchantIdentifier;
+ merchantSession.merchantSessionIdentifier = apple_pay_merchantSessionIdentifier;
+ merchantSession.nonce = apple_pay_merchantNonce;
+ merchantSession.domainName = apple_pay_merchantDomainName;
+ merchantSession.epochTimestamp = apple_pay_merchantEpochTimestamp;
+ merchantSession.signature = apple_pay_merchantSignature;
+ var validationData = "&merchantIdentifier=" + apple_pay_merchantIdentifier + "&merchantDomain=" + apple_pay_merchantDomainName + "&displayName=" + apple_pay_merchantDisplayName;
+ var validationUrl = "/ea-dataservice/rest/applepay/validateurl?url=" + url + validationData;
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function () {
+ var data = JSON.parse(this.responseText);
+ if (dist_engrid_ENGrid.debug) console.log("Apple Pay Validation", data);
+ resolve(data);
+ };
+ xhr.onerror = reject;
+ xhr.open("GET", validationUrl);
+ xhr.send();
+ });
+ }
+ log(name, msg) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "/ea-dataservice/rest/applepay/log?name=" + name + "&msg=" + msg);
+ xhr.send();
+ }
+ sendPaymentToken(token) {
+ return new Promise(function (resolve, reject) {
+ resolve(true);
+ });
+ }
+ onPayClicked() {
+ if (!this._form.submit) return;
+ const enFieldPaymentType = document.querySelector("#en__field_transaction_paymenttype");
+ const applePayToken = document.getElementById("applePayToken");
+ const formClass = this._form;
+ // Only work if Payment Type is Apple Pay
+ if (enFieldPaymentType.value == "applepay" && applePayToken.value == "") {
+ try {
+ let donationAmount = this._amount.amount + this._fees.fee;
+ var request = {
+ supportedNetworks: apple_pay_merchantSupportedNetworks,
+ merchantCapabilities: apple_pay_merchantCapabilities,
+ countryCode: apple_pay_merchantCountryCode,
+ currencyCode: apple_pay_merchantCurrencyCode,
+ total: {
+ label: apple_pay_merchantTotalLabel,
+ amount: donationAmount
+ }
+ };
+ var session = new apple_pay_ApplePaySession(1, request);
+ var thisClass = this;
+ session.onvalidatemerchant = function (event) {
+ thisClass.performValidation(event.validationURL).then(function (merchantSession) {
+ if (dist_engrid_ENGrid.debug) console.log("Apple Pay merchantSession", merchantSession);
+ session.completeMerchantValidation(merchantSession);
+ });
+ };
+ session.onpaymentauthorized = function (event) {
+ thisClass.sendPaymentToken(event.payment.token).then(function (success) {
+ if (dist_engrid_ENGrid.debug) console.log("Apple Pay Token", event.payment.token);
+ document.getElementById("applePayToken").value = JSON.stringify(event.payment.token);
+ formClass.submitForm();
+ });
+ };
+ session.oncancel = function (event) {
+ if (dist_engrid_ENGrid.debug) console.log("Cancelled", event);
+ alert("You cancelled. Sorry it didn't work out.");
+ formClass.dispatchError();
+ };
+ session.begin();
+ this._form.submit = false;
+ return false;
+ } catch (e) {
+ alert("Developer mistake: '" + e.message + "'");
+ formClass.dispatchError();
+ }
+ }
+ this._form.submit = true;
+ return true;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/a11y.js
+// a11y means accessibility
+// This Component is supposed to be used as a helper for Aria Attributes & Other Accessibility Features
+class a11y_A11y {
+ constructor() {
+ this.addRequired();
+ this.addLabel();
+ this.addGroupRole();
+ this.updateFrequencyLabel();
+ const ecardImages = document.querySelectorAll('.en__ecarditems__list img');
+ this.setAutoGeneratedAltTags(ecardImages);
+ this.manageErrorListAlertRole();
+ }
+ addGroupRole() {
+ // Add role="group" to all EN Radio fields
+ const radioFields = document.querySelectorAll(".en__field--radio");
+ radioFields.forEach(field => {
+ field.setAttribute("role", "group");
+ // Add random ID to the label
+ const label = field.querySelector("label");
+ if (label) {
+ label.setAttribute("id", `en__field__label--${Math.random().toString(36).slice(2, 7)}`);
+ field.setAttribute("aria-labelledby", label.id);
+ }
+ });
+ }
+ addRequired() {
+ const mandatoryFields = document.querySelectorAll(".en__mandatory .en__field__input");
+ mandatoryFields.forEach(field => {
+ field.setAttribute("aria-required", "true");
+ });
+ }
+ addLabel() {
+ const otherAmount = document.querySelector(".en__field__input--otheramount");
+ if (otherAmount) {
+ otherAmount.setAttribute("aria-label", "Enter your custom donation amount");
+ }
+ // Split selects usually don't have a label, so let's make the first option the label
+ const splitSelects = document.querySelectorAll(".en__field__input--splitselect");
+ splitSelects.forEach(select => {
+ var _a, _b, _c, _d;
+ const firstOption = select.querySelector("option");
+ if (firstOption && firstOption.value === "" && !((_b = (_a = firstOption.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.includes("select")) && !((_d = (_c = firstOption.textContent) === null || _c === void 0 ? void 0 : _c.toLowerCase()) === null || _d === void 0 ? void 0 : _d.includes("choose"))) {
+ select.setAttribute("aria-label", firstOption.textContent || "");
+ }
+ });
+ }
+ // Update the label for the frequency field based on the selected radio button
+ updateFrequencyLabel() {
+ const frequencyLabels = document.querySelectorAll('div.en__field__item input[id^="en__field_transaction_recurrfreq"]');
+ const frequencyMainLabel = document.querySelector('label[for="en__field_transaction_recurrfreq"]');
+ frequencyLabels.forEach(item => {
+ if (item) {
+ // Set the label for the checked item on load
+ if (item.checked) {
+ frequencyMainLabel === null || frequencyMainLabel === void 0 ? void 0 : frequencyMainLabel.setAttribute('for', item.id);
+ }
+ // Then, detect if it changes with the click event
+ item.addEventListener('click', () => {
+ let frequencyId = item.id;
+ frequencyMainLabel === null || frequencyMainLabel === void 0 ? void 0 : frequencyMainLabel.setAttribute('for', frequencyId);
+ });
+ }
+ });
+ }
+ setAutoGeneratedAltTags(images) {
+ images.forEach(img => {
+ var _a;
+ // Skip if the alt tag is already set
+ if (img.alt) return;
+ try {
+ // Extract the filename from the `src` attribute
+ const src = img.src;
+ if (!src) throw new Error("Image src is null or undefined");
+ const url = new URL(src);
+ const fileNameWithExtension = url.pathname.split('/').pop();
+ if (!fileNameWithExtension) throw new Error("No filename found in src");
+ // Remove the file extension and replace `-` and `_` with spaces
+ let altText = ((_a = fileNameWithExtension.split('.').shift()) === null || _a === void 0 ? void 0 : _a.replace(/[-_]/g, ' ')) || '';
+ // Remove dimensions (#x#) and anything that follows
+ altText = altText.replace(/\d+x\d+.*$/, '').trim();
+ // Wrap in the disclaimer
+ altText = `This is an auto-generated alt tag from the filename: ${altText}`;
+ // Set the generated alt text on the image
+ img.alt = altText;
+ } catch (error) {
+ console.error(`Error processing image: ${img.src}`, error);
+ }
+ });
+ }
+ manageErrorListAlertRole() {
+ const errorList = document.querySelector('ul.en__errorList');
+ if (!errorList) return;
+ const hasErrorItems = () => Boolean(errorList.querySelector('li'));
+ const enableAlert = () => {
+ if (!errorList.hasAttribute('role')) {
+ errorList.setAttribute('role', 'alert');
+ }
+ };
+ const disableAlert = () => {
+ if (errorList.hasAttribute('role')) {
+ errorList.removeAttribute('role');
+ }
+ };
+ hasErrorItems() ? enableAlert() : disableAlert();
+ new MutationObserver(records => {
+ for (const record of records) {
+ if (record.type === 'childList') {
+ hasErrorItems() ? enableAlert() : disableAlert();
+ break;
}
- // Show the current header and form block, while removing the rest
- optInHeaders.forEach((header) => {
- if (header !== currentHeader) {
- header.remove();
- }
- else {
- header.style.display = "block";
- }
- });
- optInFormBlocks.forEach((formBlock) => {
- if (formBlock !== currentFormBlock) {
- formBlock.remove();
- }
- else {
- formBlock.style.display = "block";
- }
+ }
+ }).observe(errorList, {
+ childList: true
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/capitalize-fields.js
+// CapitalizeFields is a class that capitalizes the first letter of the fields passed to it.
+// It subscribes to the onSubmit event of the EnForm class and capitalizes the fields on submit.
+
+
+class capitalize_fields_CapitalizeFields {
+ constructor() {
+ this._form = events_en_form_EnForm.getInstance();
+ this._form.onSubmit.subscribe(() => this.capitalizeFields("en__field_supporter_firstName", "en__field_supporter_lastName", "en__field_supporter_address1", "en__field_supporter_city"));
+ }
+ capitalizeFields(...fields) {
+ fields.forEach(f => this.capitalize(f));
+ }
+ capitalize(f) {
+ let field = document.getElementById(f);
+ if (field) {
+ field.value = field.value.replace(/\w\S*/g, w => w.replace(/^\w/, c => c.toUpperCase()));
+ if (dist_engrid_ENGrid.debug) console.log("Capitalized", field.value);
+ }
+ return true;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/auto-year.js
+// This class changes the Credit Card Expiration Year Field Options to
+// include the current year and the next 19 years.
+class auto_year_AutoYear {
+ constructor() {
+ this.yearField = document.querySelector("select[name='transaction.ccexpire']:not(#en__field_transaction_ccexpire)");
+ this.years = 20;
+ this.yearLength = 2;
+ if (this.yearField) {
+ this.clearFieldOptions();
+ for (let i = 0; i < this.years; i++) {
+ const year = new Date().getFullYear() + i;
+ const newOption = document.createElement("option");
+ const optionText = document.createTextNode(year.toString());
+ newOption.appendChild(optionText);
+ newOption.value = this.yearLength == 2 ? year.toString().substr(-2) : year.toString();
+ this.yearField.appendChild(newOption);
+ }
+ }
+ }
+ clearFieldOptions() {
+ if (this.yearField) {
+ this.yearLength = this.yearField.options[this.yearField.options.length - 1].value.length;
+ [...this.yearField.options].forEach(option => {
+ var _a;
+ if (option.value !== "" && !isNaN(Number(option.value))) {
+ // @ts-ignore
+ const index = [...this.yearField.options].findIndex(i => i.value === option.value);
+ (_a = this.yearField) === null || _a === void 0 ? void 0 : _a.remove(index);
+ }
+ });
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/autocomplete.js
+// This class adds the autocomplete attribute to
+// the most common input elements
+
+class autocomplete_Autocomplete {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Autocomplete", "#330033", "#f0f0f0", "π");
+ this.autoCompleteField('[name="supporter.firstName"]', "given-name");
+ this.autoCompleteField('[name="supporter.lastName"]', "family-name");
+ this.autoCompleteField("#en__field_transaction_ccexpire", "cc-exp-month");
+ this.autoCompleteField('[name="transaction.ccexpire"]:not(#en__field_transaction_ccexpire)', "cc-exp-year");
+ this.autoCompleteField('[name="supporter.emailAddress"]', "email");
+ this.autoCompleteField('[name="supporter.phoneNumber"]', "tel");
+ this.autoCompleteField('[name="supporter.country"]', "country");
+ this.autoCompleteField('[name="supporter.address1"]', "address-line1");
+ this.autoCompleteField('[name="supporter.address2"]', "address-line2");
+ this.autoCompleteField('[name="supporter.city"]', "address-level2");
+ this.autoCompleteField('[name="supporter.region"]', "address-level1");
+ this.autoCompleteField('[name="supporter.postcode"]', "postal-code");
+ // Ignore Autocomplete on the Recipient Email Field & Address ("none" is intentional because "off" doesn't work)
+ this.autoCompleteField('[name="transaction.honname"]', "none");
+ this.autoCompleteField('[name="transaction.infemail"]', "none");
+ this.autoCompleteField('[name="transaction.infname"]', "none");
+ this.autoCompleteField('[name="transaction.infadd1"]', "none");
+ this.autoCompleteField('[name="transaction.infadd2"]', "none");
+ this.autoCompleteField('[name="transaction.infcity"]', "none");
+ this.autoCompleteField('[name="transaction.infpostcd"]', "none");
+ }
+ autoCompleteField(querySelector, autoCompleteValue) {
+ let field = document.querySelector(querySelector);
+ if (field) {
+ field.autocomplete = autoCompleteValue;
+ return true;
+ }
+ if (autoCompleteValue !== "none") this.logger.log("Field Not Found", querySelector);
+ return false;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/ecard.js
+
+class ecard_Ecard {
+ constructor() {
+ this._form = events_en_form_EnForm.getInstance();
+ this.logger = new dist_logger_EngridLogger("Ecard", "red", "#f5f5f5", "πͺͺ");
+ if (!this.shouldRun()) return;
+ this._form.onValidate.subscribe(() => this.checkRecipientFields());
+ const schedule = dist_engrid_ENGrid.getUrlParameter("engrid_ecard.schedule");
+ const scheduleField = dist_engrid_ENGrid.getField("ecard.schedule");
+ const name = dist_engrid_ENGrid.getUrlParameter("engrid_ecard.name");
+ const nameField = document.querySelector(".en__ecardrecipients__name input");
+ const email = dist_engrid_ENGrid.getUrlParameter("engrid_ecard.email");
+ const emailField = document.querySelector(".en__ecardrecipients__email input");
+ if (schedule && scheduleField) {
+ // Check if chedule date is in the past
+ const scheduleDate = new Date(schedule.toString());
+ const today = new Date();
+ if (scheduleDate.setHours(0, 0, 0, 0) < today.setHours(0, 0, 0, 0)) {
+ // If it is, set the schedule to today
+ scheduleField.value = dist_engrid_ENGrid.formatDate(today, "YYYY-MM-DD");
+ } else {
+ // Otherwise, set the schedule to the date provided
+ scheduleField.value = schedule.toString();
+ }
+ this.logger.log("Schedule set to " + scheduleField.value);
+ }
+ if (name && nameField) {
+ nameField.value = name.toString();
+ this.logger.log("Name set to " + nameField.value);
+ }
+ if (email && emailField) {
+ emailField.value = email.toString();
+ this.logger.log("Email set to " + emailField.value);
+ }
+ // Replace the Future Delivery Label with a H2
+ const futureDeliveryLabel = document.querySelector(".en__ecardrecipients__futureDelivery label");
+ if (futureDeliveryLabel) {
+ const futureDeliveryH2 = document.createElement("h2");
+ futureDeliveryH2.innerText = futureDeliveryLabel.innerText;
+ futureDeliveryLabel.replaceWith(futureDeliveryH2);
+ }
+ if (emailField) {
+ emailField.setAttribute("type", "email");
+ emailField.setAttribute("autocomplete", "off");
+ }
+ }
+ shouldRun() {
+ return dist_engrid_ENGrid.getPageType() === "ECARD";
+ }
+ checkRecipientFields() {
+ const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
+ // If we find the "+" button and there's no hidden recipient field, click on the button
+ if (addRecipientButton && !document.querySelector(".ecardrecipient__email")) {
+ addRecipientButton.click();
+ }
+ return true;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/click-to-expand.js
+// This class is used to expand content when a user clicks on a div with the class "click-to-expand".
+// The content is shortened by default and will expand when clicked.
+
+// Works when the user has adds ".click-to-expand" as a class to any field
+class click_to_expand_ClickToExpand {
+ constructor() {
+ this.clickToExpandWrapper = document.querySelectorAll("div.click-to-expand");
+ if (this.clickToExpandWrapper.length) {
+ this.clickToExpandWrapper.forEach(element => {
+ const content = element.innerHTML;
+ const wrapper_html = '
' + content + "
";
+ element.innerHTML = wrapper_html;
+ element.addEventListener("click", event => {
+ if (event) {
+ if (dist_engrid_ENGrid.debug) console.log("A click-to-expand div was clicked");
+ element.classList.add("expanded");
+ }
});
- // Save the current step to sessionStorage
- this.saveStepToSessionStorage(currentStep, totalSteps);
- // On form submit, save the checkbox values to sessionStorage
- this._form.onSubmit.subscribe(() => {
- this.saveOptInsToSessionStorage("child");
- // Save the current step to sessionStorage
- currentStep++;
- this.saveStepToSessionStorage(currentStep, totalSteps);
+ element.addEventListener("keydown", event => {
+ if (event.key === "Enter") {
+ if (dist_engrid_ENGrid.debug) console.log("A click-to-expand div had the 'Enter' key pressed on it");
+ element.classList.add("expanded");
+ } else if (event.key === " ") {
+ if (dist_engrid_ENGrid.debug) console.log("A click-to-expand div had the 'Spacebar' key pressed on it");
+ element.classList.add("expanded");
+ event.preventDefault(); // Prevents the page from scrolling
+ event.stopPropagation(); // Prevent a console error generated by LastPass https://github.com/KillerCodeMonkey/ngx-quill/issues/351#issuecomment-476017960
+ }
});
+ });
}
- runAsChildThankYou() {
- if (!this.isEmbeddedThankYouPage()) {
- this.logger.log("Not Embedded on a Thank You Page");
- return;
- }
- const hasOptInLadderStop = sessionStorage.getItem("engrid.optin-ladder-stop");
- const hasOptInLadderPersistStop = sessionStorage.getItem("engrid.optin-ladder-persist-stop");
- if (hasOptInLadderPersistStop) {
- this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page");
- sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
- return;
- }
- if (hasOptInLadderStop) {
- this.logger.log("OptInLadder has been stopped");
- return;
- }
- const sessionStorageOptInLadder = JSON.parse(sessionStorage.getItem("engrid.optin-ladder") || "{}");
- const currentStep = sessionStorageOptInLadder.step || 0;
- const totalSteps = sessionStorageOptInLadder.totalSteps || 0;
- if (totalSteps === 0) {
- this.logger.log("No total steps found in sessionStorage");
- this.hidePage();
- return;
- }
- else if (currentStep <= totalSteps) {
- this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`);
- this.hidePage(true);
- // Redirect to the first page
- window.location.href = this.getFirstPageUrl();
- return;
- }
- else {
- this.logger.log(`Current step ${currentStep} is greater than total steps ${totalSteps}`);
- // Remove the session storage
- this.clearSessionStorage();
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/advocacy.js
+// Component to handle advocacy features
+// 1 - Adds EN Polyfill to support "label" clicking on Advocacy Recipient "labels"
+
+class advocacy_Advocacy {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Advocacy", "#232323", "#f7b500", "π¨ββοΈ");
+ if (!this.shoudRun()) return;
+ this.setClickableLabels();
+ }
+ shoudRun() {
+ return ["ADVOCACY", "EMAILTOTARGET"].includes(dist_engrid_ENGrid.getPageType());
+ }
+ setClickableLabels() {
+ const contactItems = document.querySelectorAll(".en__contactDetails__rows");
+ if (!contactItems) return;
+ contactItems.forEach(contact => {
+ contact.addEventListener("click", e => {
+ this.toggleCheckbox(contact);
+ });
+ });
+ }
+ toggleCheckbox(contact) {
+ const wrapper = contact.closest(".en__contactDetails");
+ if (!wrapper) return;
+ const checkbox = wrapper.querySelector("input[type='checkbox']");
+ if (!checkbox) return;
+ this.logger.log("toggleCheckbox", checkbox.checked);
+ checkbox.checked = !checkbox.checked;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/data-attributes.js
+// Component that adds data attributes to the Body
+
+class data_attributes_DataAttributes {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Data Attribute Changed", "#FFFFFF", "#4d9068", "π οΈ");
+ this._country = country_Country.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this.setDataAttributes();
+ }
+ setDataAttributes() {
+ // Apple Pay Availability
+ if (window.hasOwnProperty("ApplePaySession")) {
+ dist_engrid_ENGrid.setBodyData("apple-pay-available", "true");
+ } else {
+ dist_engrid_ENGrid.setBodyData("apple-pay-available", "false");
+ }
+ // Add the Page Type as a Data Attribute on the Body Tag
+ if (dist_engrid_ENGrid.checkNested(window, "pageJson", "pageType")) {
+ dist_engrid_ENGrid.setBodyData("page-type", window.pageJson.pageType);
+ }
+ // Add the currency code as a Data Attribute on the Body Tag
+ dist_engrid_ENGrid.setBodyData("currency-code", dist_engrid_ENGrid.getCurrencyCode());
+ // Add a body banner data attribute if the banner contains no image or video
+ if (!document.querySelector(".body-banner img, .body-banner video")) {
+ dist_engrid_ENGrid.setBodyData("body-banner", "empty");
+ }
+ // Add a page-alert data attribute if it is empty
+ if (!document.querySelector(".page-alert *")) {
+ dist_engrid_ENGrid.setBodyData("no-page-alert", "");
+ }
+ // Add a content-header data attribute if it is empty
+ if (!document.querySelector(".content-header *")) {
+ dist_engrid_ENGrid.setBodyData("no-content-header", "");
+ }
+ // Add a body-headerOutside data attribute if it is empty
+ if (!document.querySelector(".body-headerOutside *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-headerOutside", "");
+ }
+ // Add a body-header data attribute if it is empty
+ if (!document.querySelector(".body-header *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-header", "");
+ }
+ // Add a body-title data attribute if it is empty
+ if (!document.querySelector(".body-title *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-title", "");
+ }
+ // Add a body-banner data attribute if it is empty
+ if (!document.querySelector(".body-banner *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-banner", "");
+ }
+ // Add a body-bannerOverlay data attribute if it is empty
+ if (!document.querySelector(".body-bannerOverlay *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-bannerOverlay", "");
+ }
+ // Add a body-top data attribute if it is empty
+ if (!document.querySelector(".body-top *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-top", "");
+ }
+ // Add a body-main data attribute if it is empty
+ if (!document.querySelector(".body-main *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-main", "");
+ }
+ // Add a body-bottom data attribute if it is empty
+ if (!document.querySelector(".body-bottom *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-bottom", "");
+ }
+ // Add a body-footer data attribute if it is empty
+ if (!document.querySelector(".body-footer *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-footer", "");
+ }
+ // Add a body-footerOutside data attribute if it is empty
+ if (!document.querySelector(".body-footerOutside *")) {
+ dist_engrid_ENGrid.setBodyData("no-body-footerOutside", "");
+ }
+ // Add a content-footerSpacer data attribute if it is empty
+ if (!document.querySelector(".content-footerSpacer *")) {
+ dist_engrid_ENGrid.setBodyData("no-content-footerSpacer", "");
+ }
+ // Add a content-preFooter data attribute if it is empty
+ if (!document.querySelector(".content-preFooter *")) {
+ dist_engrid_ENGrid.setBodyData("no-content-preFooter", "");
+ }
+ // Add a content-footer data attribute if it is empty
+ if (!document.querySelector(".content-footer *")) {
+ dist_engrid_ENGrid.setBodyData("no-content-footer", "");
+ }
+ // Add a page-backgroundImage banner data attribute if the page background image contains no image or video
+ if (!document.querySelector(".page-backgroundImage img, .page-backgroundImage video")) {
+ dist_engrid_ENGrid.setBodyData("no-page-backgroundImage", "");
+ }
+ // Add a page-backgroundImageOverlay data attribute if it is empty
+ if (!document.querySelector(".page-backgroundImageOverlay *")) {
+ dist_engrid_ENGrid.setBodyData("no-page-backgroundImageOverlay", "");
+ }
+ // Add a page-customCode data attribute if it is empty
+ if (!document.querySelector(".page-customCode *")) {
+ dist_engrid_ENGrid.setBodyData("no-page-customCode", "");
+ }
+ // Add a country data attribute
+ if (this._country.country) {
+ dist_engrid_ENGrid.setBodyData("country", this._country.country);
+ this._country.onCountryChange.subscribe(country => {
+ dist_engrid_ENGrid.setBodyData("country", country);
+ });
+ }
+ const otherAmountDiv = document.querySelector(".en__field--donationAmt .en__field__item--other");
+ if (otherAmountDiv) {
+ otherAmountDiv.setAttribute("data-currency-symbol", dist_engrid_ENGrid.getCurrencySymbol());
+ }
+ // Add a payment type data attribute
+ const paymentTypeSelect = dist_engrid_ENGrid.getField("transaction.paymenttype");
+ if (paymentTypeSelect) {
+ dist_engrid_ENGrid.setBodyData("payment-type", paymentTypeSelect.value);
+ paymentTypeSelect.addEventListener("change", () => {
+ dist_engrid_ENGrid.setBodyData("payment-type", paymentTypeSelect.value);
+ });
+ }
+ // Footer in Viewport Check
+ const contentFooter = document.querySelector(".content-footer");
+ if (contentFooter && dist_engrid_ENGrid.isInViewport(contentFooter)) {
+ dist_engrid_ENGrid.setBodyData("footer-above-fold", "");
+ } else {
+ dist_engrid_ENGrid.setBodyData("footer-below-fold", "");
+ }
+ // Add demo data attribute
+ if (dist_engrid_ENGrid.demo) dist_engrid_ENGrid.setBodyData("demo", "");
+ // Add data-first-page and data-last-page
+ if (dist_engrid_ENGrid.getPageNumber() === 1) {
+ dist_engrid_ENGrid.setBodyData("first-page", "");
+ }
+ if (dist_engrid_ENGrid.getPageNumber() === dist_engrid_ENGrid.getPageCount()) {
+ dist_engrid_ENGrid.setBodyData("last-page", "");
+ }
+ // "Temporary solutions are forever, you know..."
+ // - Fernando Santos
+ // "I know, but what if we just..."
+ // - Bryan Casler
+ // Add data attribute if browser does not support :has selector
+ if (!CSS.supports("selector(:has(*))")) {
+ dist_engrid_ENGrid.setBodyData("css-has-selector", "false");
+ }
+ if (dist_engrid_ENGrid.getPageType() === "DONATION") {
+ this.addFrequencyDataAttribute();
+ this.addGiftAmountDataAttribute();
+ }
+ }
+ // Add a data attribute to the body tag with how many visible frequency options there are
+ addFrequencyDataAttribute() {
+ const frequencyOptions = document.querySelectorAll(".en__field--recurrfreq .en__field__item label.en__field__label");
+ let visibleFrequencyOptions = 0;
+ frequencyOptions.forEach(option => {
+ if (dist_engrid_ENGrid.isVisible(option)) {
+ visibleFrequencyOptions++;
+ }
+ });
+ dist_engrid_ENGrid.setBodyData("visible-frequency", visibleFrequencyOptions.toString());
+ }
+ // Add a data attribute to the body tag with how many visible gift amount options there are
+ addGiftAmountDataAttribute() {
+ const updateGiftAmountData = () => {
+ const giftAmountOptions = document.querySelectorAll(".en__field--donationAmt .en__field__element .en__field__item");
+ let visibleGiftAmountOptions = 0;
+ giftAmountOptions.forEach(option => {
+ if (dist_engrid_ENGrid.isVisible(option)) {
+ visibleGiftAmountOptions++;
}
+ });
+ dist_engrid_ENGrid.setBodyData("visible-gift-amount", visibleGiftAmountOptions.toString());
+ this.logger.log("Visible Gift Amount Changed to: " + visibleGiftAmountOptions.toString());
+ };
+ // Initial update
+ updateGiftAmountData();
+ // Observe changes in the donation amount section
+ const observer = new MutationObserver(updateGiftAmountData);
+ const targetNode = document.querySelector(".en__field--donationAmt");
+ if (targetNode) {
+ observer.observe(targetNode, {
+ childList: true,
+ subtree: true,
+ attributes: true
+ });
}
- inIframe() {
+ // Run update updateGiftAmountData when frequency changes
+ this._frequency.onFrequencyChange.subscribe(() => {
+ setTimeout(() => {
+ updateGiftAmountData();
+ }, 10);
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/iframe.js
+
+
+class iframe_iFrame {
+ constructor() {
+ this._form = events_en_form_EnForm.getInstance();
+ this.logger = new dist_logger_EngridLogger("iFrame", "brown", "gray", "π‘");
+ if (this.inIframe()) {
+ // Add the data-engrid-embedded attribute when inside an iFrame if it wasn't already added by a script in the Page Template
+ dist_engrid_ENGrid.setBodyData("embedded", "");
+ // Check if the parent page URL matches the criteria for a thank you page donation
+ const getParentUrl = () => {
try {
- return window.self !== window.top;
+ return window.parent.location.href;
+ } catch (e) {
+ // If we can't access parent location due to same-origin policy, fall back to referrer
+ return document.referrer;
}
- catch (e) {
- return true;
+ };
+ const parentUrl = getParentUrl();
+ const thankYouPageRegex = /\/page\/\d+\/[^\/]+\/(\d+)(\?|$)/;
+ const match = parentUrl.match(thankYouPageRegex);
+ if (match) {
+ const pageNumber = parseInt(match[1], 10);
+ if (pageNumber > 1) {
+ dist_engrid_ENGrid.setBodyData("embedded", "thank-you-page-donation");
+ this.hideFormComponents();
+ this.logger.log("iFrame Event - Set embedded attribute to thank-you-page-donation");
}
- }
- saveStepToSessionStorage(step, totalSteps) {
- sessionStorage.setItem("engrid.optin-ladder", JSON.stringify({ step, totalSteps }));
- this.logger.log(`Saved step ${step} of ${totalSteps} to sessionStorage`);
- }
- saveOptInsToSessionStorage(type = "parent") {
- // Grab all the checkboxes with the name starting with "supporter.questions"
- const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
- if (checkboxes.length === 0) {
- this.logger.log("No checkboxes found");
- return;
+ }
+ // Fire the resize event
+ this.logger.log("iFrame Event - Begin Resizing");
+ // Run onLoaded function
+ console.log("document.readyState", document.readyState);
+ // Document Load
+ if (document.readyState !== "loading") {
+ this.onLoaded();
+ } else {
+ document.addEventListener("DOMContentLoaded", () => {
+ this.onLoaded();
+ });
+ }
+ window.setTimeout(() => {
+ this.sendIframeHeight();
+ }, 300);
+ window.addEventListener("resize", this.debounceWithImmediate(() => {
+ this.logger.log("iFrame Event - window resized");
+ this.sendIframeHeight();
+ }));
+ // Listen for the form submit event
+ this._form.onSubmit.subscribe(e => {
+ this.logger.log("iFrame Event - onSubmit");
+ this.sendIframeFormStatus("submit");
+ });
+ // If the iFrame is Chained, check if the form has data
+ if (this.isChained() && dist_engrid_ENGrid.getPaymentType()) {
+ this.logger.log("iFrame Event - Chained iFrame");
+ this.sendIframeFormStatus("chained");
+ // this.addChainedBanner();
+ }
+ // Remove the skip link markup when inside an iFrame
+ const skipLink = document.querySelector(".skip-link");
+ if (skipLink) {
+ skipLink.remove();
+ }
+ this._form.onError.subscribe(() => {
+ // Get the first .en__field--validationFailed element
+ const firstError = document.querySelector(".en__field--validationFailed");
+ // Send scrollTo message
+ // Parent pages listens for this message and scrolls to the correct position
+ const scrollTo = firstError ? firstError.getBoundingClientRect().top : 0;
+ this.logger.log(`iFrame Event 'scrollTo' - Position of top of first error ${scrollTo} px`); // check the message is being sent correctly
+ window.parent.postMessage({
+ scrollTo
+ }, "*");
+ // Send the height of the iFrame
+ window.setTimeout(() => {
+ this.sendIframeHeight();
+ }, 100);
+ });
+ } else {
+ // When not in iframe, default behaviour, smooth scroll to first error
+ this._form.onError.subscribe(() => {
+ // Smooth Scroll to the first .en__field--validationFailed element
+ const firstError = document.querySelector(".en__field--validationFailed");
+ if (firstError) {
+ firstError.scrollIntoView({
+ behavior: "smooth"
+ });
}
- const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
- let hasDeny = false;
- // Loop through all the checkboxes and store the value in sessionStorage
- checkboxes.forEach((checkbox) => {
- if (checkbox.checked) {
- const index = checkbox.name.split(".")[2];
- sessionStorageCheckboxValues[index] = "Y";
- }
- else {
- hasDeny = true;
+ });
+ // Parent Page Logic (when an ENgrid form is embedded in an ENgrid page)
+ window.addEventListener("message", event => {
+ const iframe = this.getIFrameByEvent(event);
+ if (iframe) {
+ if (event.data.hasOwnProperty("frameHeight")) {
+ iframe.style.height = event.data.frameHeight + "px";
+ if (event.data.frameHeight > 0) {
+ iframe.classList.add("loaded");
+ } else {
+ iframe.classList.remove("loaded");
}
- });
- sessionStorage.setItem("engrid.supporter.questions", JSON.stringify(sessionStorageCheckboxValues));
- this.logger.log(`Saved checkbox values to sessionStorage: ${JSON.stringify(sessionStorageCheckboxValues)}`);
- if (type === "child" && hasDeny) {
- // Add a deny value to the sessionStorage to stop the ladder
- sessionStorage.setItem("engrid.optin-ladder-stop", "Y");
+ }
+ // Old scroll event logic "scroll", scrolls to correct iframe?
+ else if (event.data.hasOwnProperty("scroll") && event.data.scroll > 0) {
+ const elDistanceToTop = window.pageYOffset + iframe.getBoundingClientRect().top;
+ let scrollTo = elDistanceToTop + event.data.scroll;
+ window.scrollTo({
+ top: scrollTo,
+ left: 0,
+ behavior: "smooth"
+ });
+ this.logger.log("iFrame Event - Scrolling Window to " + scrollTo);
+ }
+ // New scroll event logic "scrollTo", scrolls to the first error
+ else if (event.data.hasOwnProperty("scrollTo")) {
+ const scrollToPosition = event.data.scrollTo + window.scrollY + iframe.getBoundingClientRect().top;
+ window.scrollTo({
+ top: scrollToPosition,
+ left: 0,
+ behavior: "smooth"
+ });
+ this.logger.log("iFrame Event - Scrolling Window to " + scrollToPosition);
+ }
}
+ });
}
- isEmbeddedThankYouPage() {
- return ENGrid.getBodyData("embedded") === "thank-you-page-donation";
+ }
+ onLoaded() {
+ // Scroll to top of iFrame
+ this.logger.log("iFrame Event - window.onload");
+ this.sendIframeHeight();
+ window.parent.postMessage({
+ scroll: this.shouldScroll()
+ }, "*");
+ // Iframe Queue: signal Thank-You-page completion to the parent window.
+ // The IframeQueue component (in parent mode) listens for this ping and
+ // matches it by Page ID to advance to the next queued iframe. Fires
+ // exactly once per Thank-You-page load. See iframe-queue.ts.
+ this.sendIframeQueueThankYouPing();
+ // On click fire the resize event
+ document.addEventListener("click", e => {
+ this.logger.log("iFrame Event - click");
+ setTimeout(() => {
+ this.sendIframeHeight();
+ }, 100);
+ });
+ // Watch for errors and send the height
+ dist_engrid_ENGrid.watchForError(this.sendIframeHeight.bind(this));
+ }
+ /**
+ * Posts a `engrid-iframe-queue:thank-you` message to the parent window
+ * when the embedded EN page reaches its Thank You page (the last page
+ * in the page sequence). Carries the Page ID of the submitting form so
+ * the IframeQueue parent can match the ping against the queued item it
+ * is waiting on, ignoring pings from unrelated EN iframes that may exist
+ * on the same parent page (e.g. an Embedded Ecard iframe).
+ *
+ * Only fires when:
+ * - the script is running inside an iframe (already guaranteed by the
+ * code path that calls onLoaded()), AND
+ * - the embedded page is a Thank You page (ENGrid.isThankYouPage()).
+ *
+ * Consumed by: IframeQueue (engrid/packages/scripts/src/iframe-queue.ts).
+ */
+ sendIframeQueueThankYouPing() {
+ if (!dist_engrid_ENGrid.isThankYouPage()) return;
+ const pageId = dist_engrid_ENGrid.getPageID();
+ const message = {
+ type: "engrid-iframe-queue:thank-you",
+ pageId,
+ pageNumber: dist_engrid_ENGrid.getPageNumber(),
+ pageCount: dist_engrid_ENGrid.getPageCount(),
+ url: window.location.href
+ };
+ this.logger.log(`iFrame Event - Iframe Queue thank-you ping (pageId=${pageId})`);
+ window.parent.postMessage(message, "*");
+ }
+ sendIframeHeight() {
+ let height = document.body.offsetHeight;
+ this.logger.log("iFrame Event - Sending iFrame height of: " + height + "px"); // check the message is being sent correctly
+ window.parent.postMessage({
+ frameHeight: height,
+ pageNumber: dist_engrid_ENGrid.getPageNumber(),
+ pageCount: dist_engrid_ENGrid.getPageCount(),
+ giftProcess: dist_engrid_ENGrid.getGiftProcess()
+ }, "*");
+ }
+ sendIframeFormStatus(status) {
+ window.parent.postMessage({
+ status: status,
+ pageNumber: dist_engrid_ENGrid.getPageNumber(),
+ pageCount: dist_engrid_ENGrid.getPageCount(),
+ giftProcess: dist_engrid_ENGrid.getGiftProcess()
+ }, "*");
+ }
+ getIFrameByEvent(event) {
+ return [].slice.call(document.getElementsByTagName("iframe")).filter(iframe => {
+ return iframe.contentWindow === event.source;
+ })[0];
+ }
+ shouldScroll() {
+ // If you find a error, scroll
+ if (document.querySelector(".en__errorHeader")) {
+ return true;
}
- getPageUrl(page, chain = false) {
- const url = new URL(window.location.href);
- const path = url.pathname.split("/");
- path[path.length - 1] = String(page);
- return url.origin + path.join("/") + (chain ? "?chain" : "");
+ // If it's a chained iFrame, don't scroll
+ if (this.isChained()) {
+ return false;
}
- getFirstPageUrl() {
- return this.getPageUrl(1, true);
+ // Try to match the iframe referrer URL by testing valid EN Page URLs
+ let referrer = document.referrer;
+ let enURLPattern = new RegExp(/^(.*)\/(page)\/(\d+.*)/);
+ // Scroll if the Regex matches, don't scroll otherwise
+ return enURLPattern.test(referrer);
+ }
+ inIframe() {
+ try {
+ return window.self !== window.top;
+ } catch (e) {
+ return true;
}
- hidePage(forceHide = false) {
- if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) {
- this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page");
- sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y");
- window.location.href = this.getPageUrl(2);
- }
- else {
- const engridPage = document.querySelector("#engrid");
- if (engridPage) {
- engridPage.classList.add("hide");
- }
- }
+ }
+ // This method checks if the URL has a parameter named "chain" and returns true if it exists, otherwise false.
+ isChained() {
+ return !!dist_engrid_ENGrid.getUrlParameter("chain");
+ }
+ hideFormComponents() {
+ this.logger.log("iFrame Event - Hiding Form Components");
+ const excludeClasses = ["giveBySelect-Card", "en__field--ccnumber", "en__field--survey", "en__component--ecardblock", "give-by-select", "give-by-select-header", "en__submit", "en__captcha", "force-visibility", "hide", "hide-iframe", "radio-to-buttons_donationAmt"];
+ const excludeIds = ["en__digitalWallet"];
+ const components = Array.from(document.querySelectorAll(".body-main:not(.force-visibility) > div:not(:last-child)"));
+ components.forEach(component => {
+ const shouldExclude = excludeClasses.some(cls => component.classList.contains(cls) || component.querySelector(`:scope > .${cls}`)) || excludeIds.some(id => component.querySelector(`#${id}`));
+ if (!shouldExclude) {
+ component.classList.add("hide-iframe", "hide-chained");
+ }
+ });
+ this.sendIframeHeight();
+ }
+ showFormComponents() {
+ this.logger.log("iFrame Event - Showing Form Components");
+ const en__component = document.querySelectorAll(".body-main > div.hide-chained");
+ en__component.forEach(component => {
+ component.classList.remove("hide-iframe");
+ component.classList.remove("hide-chained");
+ });
+ this.sendIframeHeight();
+ }
+ // private addChainedBanner() {
+ // this.logger.log("iFrame Event - Adding Chained Banner");
+ // const banner = document.createElement("div");
+ // const lastComponent = document.querySelector(
+ // ".body-main > div:last-of-type"
+ // ) as HTMLDivElement;
+ // banner.classList.add("en__component");
+ // banner.classList.add("en__component--banner");
+ // banner.classList.add("en__component--banner--chained");
+ // banner.innerHTML = `
+ // ${ENGrid.getFieldValue("supporter.firstName") ? `Giving as ${ENGrid.getFieldValue("supporter.firstName")} ${ENGrid.getFieldValue("supporter.lastName")} ` : "Testing as "}
+ // with ${ENGrid.getFieldValue(
+ // "transaction.paymenttype"
+ // ).toUpperCase()}
+ // (change )
`;
+ // lastComponent?.parentNode?.insertBefore(banner, lastComponent);
+ // banner
+ // .querySelector(".en__component__content__link")
+ // ?.addEventListener("click", (e) => {
+ // e.preventDefault();
+ // this.showFormComponents();
+ // banner.remove();
+ // });
+ // }
+ debounceWithImmediate(func, timeout = 1000) {
+ let timer;
+ let firstEvent = true;
+ return (...args) => {
+ clearTimeout(timer);
+ if (firstEvent) {
+ func.apply(this, args);
+ firstEvent = false;
+ }
+ timer = setTimeout(() => {
+ func.apply(this, args);
+ firstEvent = true;
+ }, timeout);
+ };
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/iframe-queue.js
+/**
+ * Iframe Queue β load embedded EN pages sequentially.
+ *
+ * **This component is opt-in.** Like `OptInLadder`, it is exported from
+ * `@4site/engrid-scripts` but is **not** auto-constructed by ENgrid's
+ * core bootstrap (`app.ts`). To use it, instantiate it once in your
+ * theme's bootstrap:
+ *
+ * ```ts
+ * import { IframeQueue } from "@4site/engrid-scripts";
+ * new IframeQueue();
+ * ```
+ *
+ * On client themes that don't use this component, **nothing in this
+ * file runs**: no `message` listener is registered, no singleton is
+ * allocated, no bundle code beyond the unused class definition.
+ *
+ * **Why this exists.** Engaging Networks' platform handles concurrent
+ * iframe submissions inconsistently β when several embedded EN forms
+ * are submitted in parallel (e.g. QCB opt-ins for postal mail, mobile
+ * phone, and double opt-in email), roughly 40% of records are lost.
+ * Loading the iframes sequentially (without `?chain`) resolves the
+ * issue. This component generalises that pattern.
+ *
+ * **What it does.** In _parent_ mode (top-level page) it holds an
+ * ordered queue of {@link IframeQueueItem} configs and processes them
+ * one at a time: create iframe β wait for `load` β post a populate
+ * message with field values β wait for the embedded page to reach a
+ * Thank You page β advance. In _embedded_ mode (running inside an
+ * iframe owned by an IframeQueue parent) it listens for the populate
+ * message, fills the form fields via {@link ENGrid.setFieldValue}, and
+ * submits via {@link EnForm.submitForm} when `autoSubmit` is true.
+ *
+ * **Why not `?chain`?** Engaging Networks' `?chain` URL parameter is
+ * unreliable for sequential iframe submission; the agreed solution is
+ * to pass field data via `postMessage` instead. The queue defensively
+ * strips any `chain` query parameter from queued URLs.
+ *
+ * **Page ID matching.** The Thank-You-page ping (sent by the iFrame
+ * component, see iframe.ts) carries the Page ID of the submitting
+ * form. The queue compares it against the Page ID parsed from the
+ * queued URL so that pings from unrelated EN iframes on the same
+ * parent page (such as an Embedded Ecard iframe) are ignored.
+ *
+ * **Events.** Lifecycle events are dispatched via the
+ * {@link IframeQueueEvents} singleton. External code subscribes there
+ * rather than holding a reference to the queue itself.
+ *
+ * @example Programmatic API
+ * const queue = IframeQueue.getInstance();
+ * queue.enqueue({
+ * url: "https://example.org/page/123/data/1",
+ * fields: { "supporter.emailAddress": "donor@example.org" },
+ * autoSubmit: true,
+ * });
+ * queue.process().then(() => console.log("done"));
+ *
+ * @example Declarative API (set on the EN page before the bundle loads)
+ * window.EngridIframeQueue = {
+ * items: [
+ * { url: "https://example.org/page/123/data/1",
+ * fields: { "supporter.emailAddress": "donor@example.org" } },
+ * ],
+ * autoStart: true,
+ * };
+ */
+var dist_iframe_queue_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function (resolve) {
+ resolve(value);
+ });
+ }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
+ }
}
- clearSessionStorage() {
- sessionStorage.removeItem("engrid.supporter.questions");
- sessionStorage.removeItem("engrid.optin-ladder");
- sessionStorage.removeItem("engrid.optin-ladder-stop");
- sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
+ }
}
-}
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/post-donation-embed.js
-// This component only works on Thank You pages and the current page IS NOT embedded as an iframe.
-// It searches for a post-donation tag (engrid-post-donation)
-// and if it exists, it will replace it with an iframe of the chained `src` attribute (or the current donation page, replacing the
-// "/donate/2" with "/donate/1").
-// The engrid-post-donation tag has 3 attributes:
-// 1. src: the URL of the iframe to load (optional)
-// 2. params: the URL parameters to pass to the iframe
-// 3. amounts: comma separated list of amounts to pass to the iframe
-class PostDonationEmbed {
- constructor() {
- this.logger = new logger_EngridLogger("PostDonationEmbed", "red", "white", "πΌοΈ");
- if (!this.shouldRun())
- return;
- this.logger.log("Post Donation Tag found");
- const postDonationTag = document.querySelector("engrid-post-donation");
- // Get `src` attribute from the tag if it exists
- // If not, use the current page URL as the base URL
- let iFrameSRC;
- if (!postDonationTag.getAttribute("src")) {
- iFrameSRC = new URL(window.location.href);
- // Modify the path: replace "/donate/2" with "/donate/1"
- iFrameSRC.pathname = iFrameSRC.pathname.replace("/donate/2", "/donate/1");
+
+/** Wire-format type for the populate message sent parent β iframe. */
+const iframe_queue_MSG_POPULATE = "engrid-iframe-queue:populate";
+/** Wire-format type for the Thank-You-page ping sent iframe β parent. */
+const iframe_queue_MSG_THANK_YOU = "engrid-iframe-queue:thank-you";
+/** Wire-format type for an error message sent iframe β parent. */
+const iframe_queue_MSG_ERROR = "engrid-iframe-queue:error";
+/** Default per-item timeout in milliseconds. */
+const iframe_queue_DEFAULT_TIMEOUT_MS = 30000;
+/**
+ * Parameters that are automatically inherited from the parent page
+ * onto each queued iframe URL. These are all ENgrid loader / dev-mode
+ * flags β adding them to the parent is meant to affect "the ENgrid
+ * bundle running on this browser tab," which conceptually includes
+ * the embedded forms loaded by the queue.
+ *
+ * For each key, the value is resolved with the same precedence used by
+ * `loader.ts#getOption`:
+ * 1. The item's own URL β if the consumer hard-coded the param on
+ * the iframe URL, that wins.
+ * 2. The parent page's URL parameter (`?assets=local`).
+ * 3. `window.EngridLoader[key]` on the parent page β useful when EN
+ * strips URL params on the Thank You page, so themes set
+ * ``
+ * to pin the bundle source.
+ *
+ * Notable use case: any of the three works for forcing local-asset
+ * loading on every queued QCB iframe during testing.
+ */
+const iframe_queue_PROPAGATED_PARENT_PARAMS = (/* unused pure expression or super */ null && (["assets", "engridjs", "engridcss", "repo-name", "repo-owner", "debug", "mode"]));
+/** Default visually-hidden style for queue iframes. */
+const iframe_queue_DEFAULT_HIDDEN_STYLE = {
+ position: "absolute",
+ width: "1px",
+ height: "1px",
+ left: "-9999px",
+ top: "0",
+ opacity: "0",
+ border: "0"
+};
+class iframe_queue_IframeQueue {
+ /**
+ * Returns the shared IframeQueue singleton. The bootstrap in app.ts
+ * instantiates this once via `new IframeQueue()`, but consumers that
+ * need to enqueue items programmatically should always go through
+ * `getInstance()` so they share the same queue state.
+ */
+ static getInstance() {
+ if (!iframe_queue_IframeQueue.instance) {
+ iframe_queue_IframeQueue.instance = new iframe_queue_IframeQueue();
+ }
+ return iframe_queue_IframeQueue.instance;
+ }
+ constructor() {
+ this.logger = new EngridLogger("IframeQueue", "white", "#1f6feb", "π");
+ this.events = IframeQueueEvents.getInstance();
+ this._form = EnForm.getInstance();
+ this.queue = [];
+ this._isProcessing = false;
+ this._aborted = false;
+ this.inFlightPromise = null;
+ // Singleton guard: if called via `new IframeQueue()` after an
+ // instance already exists (e.g. by app.ts), return the existing
+ // instance so behaviour stays consistent with `getInstance()`.
+ if (iframe_queue_IframeQueue.instance) {
+ return iframe_queue_IframeQueue.instance;
+ }
+ iframe_queue_IframeQueue.instance = this;
+ if (this.inIframe()) {
+ this.setupEmbeddedMode();
+ } else {
+ this.setupParentMode();
+ }
+ }
+ // ---------------------------------------------------------------------------
+ // Public API (parent mode)
+ // ---------------------------------------------------------------------------
+ /** Whether the queue is currently processing. */
+ get isProcessing() {
+ return this._isProcessing;
+ }
+ /** Number of items currently in the queue (not counting the in-flight item). */
+ get size() {
+ return this.queue.length;
+ }
+ /**
+ * Add an item to the back of the queue. Items are processed in
+ * insertion order. Calling `enqueue` while the queue is processing is
+ * supported β the new item joins the chain and will be picked up
+ * after the current item completes.
+ */
+ enqueue(item) {
+ if (!item || typeof item.url !== "string" || !item.url) {
+ this.logger.danger("enqueue() called with invalid item; ignoring");
+ return;
+ }
+ this.queue.push(item);
+ this.logger.log(`enqueue: ${item.url} (queue size = ${this.queue.length})`);
+ }
+ /**
+ * Add many items at once, preserving order. Equivalent to calling
+ * {@link enqueue} repeatedly.
+ */
+ enqueueAll(items) {
+ if (!Array.isArray(items)) return;
+ for (const item of items) this.enqueue(item);
+ }
+ /**
+ * Begin processing the queue. Resolves when the queue drains
+ * successfully and rejects on the first error. If already processing,
+ * returns the in-flight promise so callers don't start a second drain.
+ */
+ process() {
+ if (this._isProcessing && this.inFlightPromise) {
+ this.logger.log("process: already processing; returning in-flight promise");
+ return this.inFlightPromise;
+ }
+ if (this.queue.length === 0) {
+ this.logger.log("process: queue empty; nothing to do");
+ return Promise.resolve();
+ }
+ this._aborted = false;
+ this._isProcessing = true;
+ this.inFlightPromise = this.drain().then(() => {
+ this.events.dispatchChainComplete();
+ }).finally(() => {
+ this._isProcessing = false;
+ this.inFlightPromise = null;
+ });
+ return this.inFlightPromise;
+ }
+ /**
+ * Empty the queue without processing. Stops the in-flight item if
+ * any (the in-flight item rejects with an abort error which is
+ * surfaced via `onChainError`).
+ */
+ clear() {
+ this.logger.log(`clear: dropping ${this.queue.length} queued item(s)`);
+ this.queue = [];
+ this._aborted = true;
+ }
+ // ---------------------------------------------------------------------------
+ // Parent-mode internals
+ // ---------------------------------------------------------------------------
+ /**
+ * In parent mode the constructor checks `window.EngridIframeQueue`
+ * for declarative startup config, enqueues those items, and (if
+ * `autoStart` is true) calls `process()` after DOMContentLoaded.
+ */
+ setupParentMode() {
+ this.logger.log("setupParentMode");
+ const config = this.readWindowConfig();
+ if (!config) return;
+ if (Array.isArray(config.items) && config.items.length > 0) {
+ this.enqueueAll(config.items);
+ }
+ const shouldAutoStart = typeof config.autoStart === "boolean" ? config.autoStart : this.queue.length > 0;
+ if (!shouldAutoStart || this.queue.length === 0) return;
+ const start = () => {
+ this.process().catch(err => {
+ this.logger.danger(`Auto-started queue rejected: ${err}`);
+ });
+ };
+ if (document.readyState !== "loading") {
+ start();
+ } else {
+ document.addEventListener("DOMContentLoaded", start);
+ }
+ }
+ /**
+ * Reads `window.EngridIframeQueue` and returns merged options, or
+ * null if no valid config is present.
+ */
+ readWindowConfig() {
+ const raw = window.EngridIframeQueue;
+ if (!raw || typeof raw !== "object") return null;
+ return Object.assign(Object.assign({}, IframeQueueOptionsDefaults), raw);
+ }
+ /** Process queued items strictly one at a time. */
+ drain() {
+ var _a;
+ return dist_iframe_queue_awaiter(this, void 0, void 0, function* () {
+ while (this.queue.length > 0) {
+ if (this._aborted) {
+ this.logger.log("drain: aborted; stopping");
+ return;
}
- else {
- iFrameSRC = new URL(postDonationTag.getAttribute("src") || "");
+ const item = this.queue.shift();
+ try {
+ yield this.processItem(item);
+ } catch (err) {
+ const error = err instanceof Error ? err : new Error(String(err));
+ this.events.dispatchItemError(item, error);
+ try {
+ (_a = item.onError) === null || _a === void 0 ? void 0 : _a.call(item, error);
+ } catch (cbErr) {
+ this.logger.danger(`onError callback threw: ${cbErr}`);
+ }
+ this.events.dispatchChainError({
+ message: error.message,
+ failedItem: item,
+ cause: error
+ });
+ // Abort the rest of the chain.
+ this.queue = [];
+ throw error;
}
- // Extract parameters from the tag
- let params = postDonationTag.getAttribute("params") || "";
- let amounts = postDonationTag.getAttribute("amounts");
- // Format parameters correctly
- let searchParams = new URLSearchParams(params.replace(/&/g, "&"));
- let paramString = searchParams
- .toString()
- .replace(/%5B/g, "[")
- .replace(/%5D/g, "]");
- // Construct new URL with "chain" parameter
- let newUrl = `${iFrameSRC.origin}${iFrameSRC.pathname}?chain&${paramString}`;
- if (amounts) {
- newUrl += `&engrid-amounts=${amounts}`;
+ }
+ });
+ }
+ /**
+ * Process a single item: create the iframe, post populate, wait for
+ * the matching Thank-You ping (or error/timeout). Resolves on success
+ * and rejects on error/timeout.
+ */
+ processItem(item) {
+ return new Promise((resolve, reject) => {
+ var _a, _b;
+ const url = this.prepareIframeUrl(item.url);
+ const expectedPageId = ENGrid.getPageIdFromUrl(url);
+ if (!expectedPageId) {
+ reject(new Error(`IframeQueue: could not parse Page ID from URL "${item.url}".`));
+ return;
+ }
+ this.events.dispatchItemStart(item);
+ const container = (_a = item.container) !== null && _a !== void 0 ? _a : document.body;
+ const iframe = this.createIframe(url, item.iframeStyle);
+ const timeoutMs = (_b = item.timeout) !== null && _b !== void 0 ? _b : iframe_queue_DEFAULT_TIMEOUT_MS;
+ let settled = false;
+ let timeoutId = null;
+ const detachListeners = () => {
+ if (timeoutId !== null) {
+ window.clearTimeout(timeoutId);
+ timeoutId = null;
+ }
+ window.removeEventListener("message", onMessage);
+ iframe.removeEventListener("load", onIframeLoad);
+ iframe.removeEventListener("error", onIframeError);
+ };
+ const removeIframe = () => {
+ if (iframe.parentNode) {
+ iframe.parentNode.removeChild(iframe);
}
- // Create the iframe element
- let iframe = document.createElement("iframe");
- iframe.setAttribute("loading", "lazy");
- iframe.setAttribute("width", "100%");
- iframe.setAttribute("scrolling", "no");
- iframe.setAttribute("class", "engrid-iframe thank-you-page-donation");
- iframe.setAttribute("src", newUrl);
- iframe.setAttribute("frameborder", "0");
- iframe.setAttribute("allowfullscreen", "");
- iframe.setAttribute("allowpaymentrequest", "true");
- iframe.setAttribute("allow", "payment");
- iframe.setAttribute("title", "Post Donation iframe");
- // Replace with the iframe
- postDonationTag.replaceWith(iframe);
- }
- shouldRun() {
- return (engrid_ENGrid.isThankYouPage() &&
- this.hasPostDonationTag() &&
- engrid_ENGrid.getBodyData("embedded") === null);
+ };
+ const succeed = () => {
+ var _a;
+ if (settled) return;
+ settled = true;
+ detachListeners();
+ removeIframe();
+ this.events.dispatchItemComplete(item);
+ try {
+ (_a = item.onComplete) === null || _a === void 0 ? void 0 : _a.call(item);
+ } catch (cbErr) {
+ this.logger.danger(`onComplete callback threw: ${cbErr}`);
+ }
+ resolve();
+ };
+ const fail = error => {
+ if (settled) return;
+ settled = true;
+ detachListeners();
+ if (this.shouldKeepIframeOnError(item)) {
+ this.markIframeFailed(iframe, error);
+ this.logger.danger(`Item failed β iframe kept in DOM for inspection: ${error.message}`);
+ } else {
+ removeIframe();
+ }
+ reject(error);
+ };
+ const onMessage = event => {
+ var _a;
+ // Only accept messages from this specific iframe β origin
+ // string matching is unreliable because EN may serve embedded
+ // pages from different subdomains. `event.source` identity is
+ // what matters here.
+ if (event.source !== iframe.contentWindow) return;
+ const data = event.data;
+ if (!data || typeof data !== "object" || !data.type) return;
+ if (data.type === iframe_queue_MSG_THANK_YOU) {
+ if (data.pageId !== expectedPageId) {
+ this.logger.log(`Ignoring thank-you ping with mismatched pageId ` + `(expected ${expectedPageId}, got ${data.pageId})`);
+ return;
+ }
+ this.logger.log(`Item complete: ${url} (pageId ${expectedPageId})`);
+ succeed();
+ } else if (data.type === iframe_queue_MSG_ERROR) {
+ if (data.pageId !== expectedPageId) return;
+ fail(new Error(`IframeQueue: embedded page reported error: ${(_a = data.message) !== null && _a !== void 0 ? _a : "unknown error"}`));
+ }
+ };
+ const onIframeLoad = () => {
+ var _a, _b;
+ if (settled) return;
+ const populate = {
+ type: iframe_queue_MSG_POPULATE,
+ pageId: expectedPageId,
+ fields: (_a = item.fields) !== null && _a !== void 0 ? _a : {},
+ autoSubmit: item.autoSubmit !== false // default true
+ };
+ this.logger.log(`Posting populate to iframe (pageId=${expectedPageId}, ` + `fieldCount=${Object.keys(populate.fields).length}, ` + `autoSubmit=${populate.autoSubmit})`);
+ // Use "*" for the same reason origin matching is skipped on
+ // inbound messages β EN may serve embedded pages from a
+ // different subdomain than the host page.
+ (_b = iframe.contentWindow) === null || _b === void 0 ? void 0 : _b.postMessage(populate, "*");
+ };
+ const onIframeError = () => {
+ fail(new Error(`IframeQueue: iframe failed to load: ${url}`));
+ };
+ window.addEventListener("message", onMessage);
+ iframe.addEventListener("load", onIframeLoad);
+ iframe.addEventListener("error", onIframeError);
+ timeoutId = window.setTimeout(() => {
+ fail(new Error(`IframeQueue: timed out after ${timeoutMs}ms waiting for ` + `Thank-You-page ping from ${url}`));
+ }, timeoutMs);
+ this.logger.log(`Item start: ${url} (pageId ${expectedPageId}, timeout ${timeoutMs}ms)`);
+ container.appendChild(iframe);
+ });
+ }
+ /**
+ * Normalise the URL for a queued iframe:
+ * 1. Strip any `chain` query parameter defensively β the queue
+ * replaces `?chain` with sequential processing.
+ * 2. Inherit a small allowlist of loader / dev-mode params (see
+ * {@link PROPAGATED_PARENT_PARAMS}) when they're not already set
+ * on the item URL. Each key is resolved with the same precedence
+ * `loader.ts#getOption` uses: parent URL param first, then
+ * `window.EngridLoader[key]`.
+ *
+ * Item-specified params always take precedence over inherited ones.
+ * Returns the original string unchanged if URL parsing fails.
+ */
+ prepareIframeUrl(rawUrl) {
+ let url;
+ try {
+ url = new URL(rawUrl, window.location.href);
+ } catch (_a) {
+ return rawUrl;
+ }
+ url.searchParams.delete("chain");
+ const parentUrlParams = this.getParentSearchParams();
+ const parentLoader = this.getParentEngridLoader();
+ const inherited = [];
+ for (const key of iframe_queue_PROPAGATED_PARENT_PARAMS) {
+ if (url.searchParams.has(key)) continue;
+ let value = null;
+ let source = "";
+ if (parentUrlParams) {
+ const v = parentUrlParams.get(key);
+ if (v !== null) {
+ value = v;
+ source = "url";
+ }
+ }
+ if (value === null && parentLoader) {
+ const v = parentLoader[key];
+ if (typeof v === "string" && v !== "") {
+ value = v;
+ source = "EngridLoader";
+ }
+ }
+ if (value !== null) {
+ url.searchParams.set(key, value);
+ inherited.push(`${key}=${value} (from parent ${source})`);
+ }
}
- hasPostDonationTag() {
- return !!document.querySelector("engrid-post-donation");
+ if (inherited.length > 0) {
+ this.logger.log(`Inherited parent params on iframe URL: ${inherited.join(", ")}`);
}
-}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/frequency-upsell-modal.js
-/*
- * FrequencyUpsellModal - this is class that creates the modal for the frequency upsell.
- * This component is intentionally "dumb" and only creates the modal renders its content.
- * Logic for showing the modal and handling the upsell is in the FrequencyUpsell class.
- */
-
-class FrequencyUpsellModal extends Modal {
- constructor(upsellOptions) {
- super({
- onClickOutside: "bounce",
- customClass: `engrid--frequency-upsell-modal ${upsellOptions.customClass}`,
- showCloseX: false,
- });
- this._amountWithFees = 0;
- this._upsellAmountWithFees = 0;
- this.upsellOptions = upsellOptions;
- this.updateModalContent();
+ return url.href;
+ }
+ /** Returns the parent page's URLSearchParams, or null on failure. */
+ getParentSearchParams() {
+ try {
+ return new URL(window.location.href).searchParams;
+ } catch (_a) {
+ return null;
}
- set amountWithFees(value) {
- this._amountWithFees = value;
+ }
+ /**
+ * Returns the parent page's `window.EngridLoader` object if set, or
+ * null. Used by {@link prepareIframeUrl} as a fallback source for
+ * loader/dev-mode param values when EN has stripped URL parameters
+ * from the Thank You page.
+ */
+ getParentEngridLoader() {
+ const w = window;
+ if (!w.EngridLoader || typeof w.EngridLoader !== "object") return null;
+ return w.EngridLoader;
+ }
+ /**
+ * Decide whether to leave a failed iframe in the DOM (for
+ * inspection) instead of removing it. True when the item explicitly
+ * asks for it via `keepIframeOnError`, OR whenever ENgrid debug
+ * mode is on (since debugging is when this is useful and we don't
+ * want to make consumers opt in just to inspect failures).
+ */
+ shouldKeepIframeOnError(item) {
+ if (item.keepIframeOnError) return true;
+ try {
+ return ENGrid.debug === true;
+ } catch (_a) {
+ return false;
}
- set upsellAmountWithFees(value) {
- this._upsellAmountWithFees = value;
+ }
+ /**
+ * Reposition and style a failed iframe so it's visible in the
+ * viewport (overriding the visually-hidden default), and tag it
+ * with a class + tooltip so the developer knows why it's there.
+ * Right-click the iframe β Inspect frame to dive in.
+ */
+ markIframeFailed(iframe, error) {
+ Object.assign(iframe.style, {
+ position: "fixed",
+ top: "10px",
+ right: "10px",
+ bottom: "auto",
+ left: "auto",
+ width: "min(600px, 90vw)",
+ height: "min(500px, 80vh)",
+ opacity: "1",
+ zIndex: "99999",
+ border: "3px solid #d33",
+ background: "white",
+ boxShadow: "0 4px 24px rgba(0, 0, 0, 0.25)"
+ });
+ iframe.classList.add("engrid-iframe--queue-failed");
+ iframe.title = `Iframe Queue: failed item β ${error.message}`;
+ }
+ /** Create a hidden iframe element for a queue item. */
+ createIframe(url, styleOverride) {
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("src", url);
+ iframe.setAttribute("frameborder", "0");
+ iframe.setAttribute("scrolling", "no");
+ iframe.setAttribute("aria-hidden", "true");
+ iframe.setAttribute("title", "ENgrid Iframe Queue");
+ iframe.classList.add("engrid-iframe", "engrid-iframe--queue");
+ const style = Object.assign(Object.assign({}, iframe_queue_DEFAULT_HIDDEN_STYLE), styleOverride !== null && styleOverride !== void 0 ? styleOverride : {});
+ Object.assign(iframe.style, style);
+ return iframe;
+ }
+ // ---------------------------------------------------------------------------
+ // Embedded-mode internals
+ // ---------------------------------------------------------------------------
+ /**
+ * In embedded mode we register a `message` listener that accepts
+ * populate messages from `window.parent`, fills form fields, and
+ * (optionally) submits. The Thank-You-page ping is sent by the iFrame
+ * component (iframe.ts) β not here β so this method does not need to
+ * concern itself with completion signalling.
+ */
+ setupEmbeddedMode() {
+ this.logger.log("setupEmbeddedMode");
+ window.addEventListener("message", event => {
+ if (event.source !== window.parent) return;
+ const data = event.data;
+ if (!data || typeof data !== "object" || data.type !== iframe_queue_MSG_POPULATE) {
+ return;
+ }
+ this.handlePopulate(data);
+ });
+ }
+ /** Handle a populate message sent by an IframeQueue parent. */
+ handlePopulate(data) {
+ var _a, _b;
+ const fields = (_a = data.fields) !== null && _a !== void 0 ? _a : {};
+ const autoSubmit = data.autoSubmit !== false;
+ this.logger.log(`Received populate (pageId=${data.pageId}, ` + `fieldCount=${Object.keys(fields).length}, autoSubmit=${autoSubmit})`);
+ try {
+ for (const [name, value] of Object.entries(fields)) {
+ // Pass `dispatchEvents = true` so each field fires
+ // `change` + `blur` after the value is set. Without that,
+ // EN's form-validation state machine doesn't see the new
+ // values and leaves `en__submit--disabled` on the submit
+ // button, causing the auto-click below to no-op.
+ ENGrid.setFieldValue(name, value, true, true);
+ }
+ if (autoSubmit) {
+ // Defer slightly so any synchronous EN dependency parsing in
+ // setFieldValue settles before the form is submitted.
+ window.setTimeout(() => {
+ // Belt-and-braces: clear EN's "submit disabled" state in
+ // case its validators didn't re-evaluate (e.g. async
+ // validators that hadn't completed when the events fired).
+ this.forceEnableSubmitButton();
+ this._form.submitForm();
+ }, 0);
+ }
+ } catch (err) {
+ const error = err instanceof Error ? err : new Error(String(err));
+ this.logger.danger(`handlePopulate failed: ${error.message}`);
+ window.parent.postMessage({
+ type: iframe_queue_MSG_ERROR,
+ pageId: (_b = data.pageId) !== null && _b !== void 0 ? _b : ENGrid.getPageID(),
+ message: error.message
+ }, "*");
}
- updateModalContent() {
- var _a;
- this.modalContent = this.getModalContent();
- const modalBody = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector(".engrid-modal__body");
- if (modalBody) {
- modalBody.innerHTML = "";
- modalBody.insertAdjacentHTML("beforeend", this.modalContent);
- }
+ }
+ /**
+ * Strip every "disabled" marker from the EN submit button so the
+ * programmatic `submitForm()` click is honoured. Removes:
+ * - the `disabled` DOM property/attribute on the button,
+ * - the `en__submit--disabled` BEM modifier (EN's own class),
+ * - the `en__submit--disabled` modifier on the `.en__submit`
+ * wrapper (some templates style the wrapper instead),
+ * - ENgrid's own loader markup if a previous `disableSubmit()`
+ * call left it in place.
+ *
+ * Used only by embedded-mode populate flow when `autoSubmit` is on.
+ */
+ forceEnableSubmitButton() {
+ const button = document.querySelector("form .en__submit button");
+ if (button) {
+ if (button.disabled) button.disabled = false;
+ button.removeAttribute("disabled");
+ button.classList.remove("en__submit--disabled");
+ }
+ const wrapper = document.querySelector(".en__submit");
+ if (wrapper) {
+ wrapper.classList.remove("en__submit--disabled");
+ }
+ }
+ // ---------------------------------------------------------------------------
+ // Helpers
+ // ---------------------------------------------------------------------------
+ /** True when this script is executing inside an iframe. */
+ inIframe() {
+ try {
+ return window.self !== window.top;
+ } catch (_a) {
+ return true;
}
- getModalContent() {
- if (!this.upsellOptions)
- return "";
- return `
-
-
-
-
${this.replaceAmountTokens(this.upsellOptions.title)}
-
${this.replaceAmountTokens(this.upsellOptions.paragraph)}
-
-
-
- ${this.replaceAmountTokens(this.upsellOptions.yesButton)}
-
-
- ${this.replaceAmountTokens(this.upsellOptions.noButton)}
-
-
-
- `;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/input-has-value-and-focus.js
+// Component that adds has-value and has-focus classes to form inputs
+
+class input_has_value_and_focus_InputHasValueAndFocus {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("InputHasValueAndFocus", "yellow", "#333", "π");
+ this.formInputs = document.querySelectorAll(".en__field--text, .en__field--email:not(.en__field--checkbox), .en__field--telephone, .en__field--number, .en__field--textarea, .en__field--select, .en__field--checkbox");
+ if (this.shouldRun()) {
+ this.run();
}
- replaceAmountTokens(string) {
- const amount = engrid_ENGrid.formatNumber(this._amountWithFees, this._amountWithFees % 1 == 0 ? 0 : 2, ".", "");
- const upsellAmount = engrid_ENGrid.formatNumber(this._upsellAmountWithFees, this._upsellAmountWithFees % 1 == 0 ? 0 : 2, ".", "");
- return string
- .replace(/{current_amount}/g, amount)
- .replace(/{upsell_amount}/g, upsellAmount);
+ }
+ shouldRun() {
+ return this.formInputs.length > 0;
+ }
+ run() {
+ this.formInputs.forEach(el => {
+ const input = el.querySelector("input, textarea, select");
+ if (input && input.value) {
+ el.classList.add("has-value");
+ }
+ this.bindEvents(el);
+ });
+ }
+ bindEvents(el) {
+ const input = el.querySelector("input, textarea, select");
+ if (!input) {
+ return;
}
+ input.addEventListener("focus", () => {
+ this.log("Focus added", input);
+ el.classList.add("has-focus");
+ });
+ input.addEventListener("blur", () => {
+ this.log("Focus removed", input);
+ el.classList.remove("has-focus");
+ });
+ input.addEventListener("input", () => {
+ if (input.value) {
+ this.log("Value added", input);
+ el.classList.add("has-value");
+ } else {
+ this.log("Value removed", input);
+ el.classList.remove("has-value");
+ }
+ });
+ }
+ log(message, input) {
+ this.logger.log(`${message} on ${input.name}: ${input.value}`);
+ }
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/input-placeholders.js
+// Component that adds input placeholders
+// You can override the default placeholders by adding a Placeholders option to the EngridOptions on the client theme.
+// You can also add an EngridPageOptions override to the page, if you want to override the placeholders on a specific page. Example:
+//
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/frequency-upsell.js
+class input_placeholders_InputPlaceholders {
+ constructor() {
+ this.defaultPlaceholders = {
+ "input#en__field_supporter_firstName": "First Name",
+ "input#en__field_supporter_lastName": "Last Name",
+ "input#en__field_supporter_emailAddress": "Email Address",
+ "input#en__field_supporter_phoneNumber": "Phone Number (Optional)",
+ ".en__mandatory input#en__field_supporter_phoneNumber": "Phone Number",
+ ".i-required input#en__field_supporter_phoneNumber": "Phone Number",
+ "input#en__field_supporter_phoneNumber2": "000-000-0000 (Optional)",
+ ".en__mandatory input#en__field_supporter_phoneNumber2": "000-000-0000",
+ ".i-required input#en__field_supporter_phoneNumber2": "000-000-0000",
+ "input#en__field_supporter_country": "Country",
+ "input#en__field_supporter_address1": "Street Address",
+ "input#en__field_supporter_address2": "Apt., Ste., Bldg.",
+ "input#en__field_supporter_city": "City",
+ "input#en__field_supporter_region": "Region",
+ "input#en__field_supporter_postcode": "ZIP Code",
+ ".en__field--donationAmt.en__field--withOther .en__field__input--other": "Other",
+ "input#en__field_transaction_ccexpire": "MM / YY",
+ "input#en__field_supporter_bankAccountNumber": "Bank Account Number",
+ "input#en__field_supporter_bankRoutingNumber": "Bank Routing Number",
+ "input#en__field_transaction_honname": "Honoree Name",
+ "input#en__field_transaction_infname": "Recipient Name",
+ "input#en__field_transaction_infemail": "Recipient Email Address",
+ "input#en__field_transaction_infcountry": "Country",
+ "input#en__field_transaction_infadd1": "Recipient Street Address",
+ "input#en__field_transaction_infadd2": "Recipient Apt., Ste., Bldg.",
+ "input#en__field_transaction_infcity": "Recipient City",
+ "input#en__field_transaction_infpostcd": "Recipient Postal Code",
+ "input#en__field_transaction_gftrsn": "Reason for your gift",
+ "input#en__field_transaction_shipfname": "Shipping First Name",
+ "input#en__field_transaction_shiplname": "Shipping Last Name",
+ "input#en__field_transaction_shipemail": "Shipping Email Address",
+ "input#en__field_transaction_shipcountry": "Shipping Country",
+ "input#en__field_transaction_shipadd1": "Shipping Street Address",
+ "input#en__field_transaction_shipadd2": "Shipping Apt., Ste., Bldg.",
+ "input#en__field_transaction_shipcity": "Shipping City",
+ "input#en__field_transaction_shipregion": "Shipping Region",
+ "input#en__field_transaction_shippostcode": "Shipping Postal Code",
+ "input#en__field_supporter_billingCountry": "Billing Country",
+ "input#en__field_supporter_billingAddress1": "Billing Street Address",
+ "input#en__field_supporter_billingAddress2": "Billing Apt., Ste., Bldg.",
+ "input#en__field_supporter_billingCity": "Billing City",
+ "input#en__field_supporter_billingRegion": "Billing Region",
+ "input#en__field_supporter_billingPostcode": "Billing Postal Code"
+ };
+ if (this.shouldRun()) {
+ // If there's a Placeholders option, merge it with the default placeholders
+ const placeholders = dist_engrid_ENGrid.getOption("Placeholders");
+ if (placeholders) {
+ this.defaultPlaceholders = Object.assign(Object.assign({}, this.defaultPlaceholders), placeholders);
+ }
+ this.run();
+ }
+ }
+ shouldRun() {
+ return dist_engrid_ENGrid.hasBodyData("add-input-placeholders");
+ }
+ run() {
+ Object.keys(this.defaultPlaceholders).forEach(selector => {
+ if (selector in this.defaultPlaceholders) this.addPlaceholder(selector, this.defaultPlaceholders[selector]);
+ });
+ }
+ addPlaceholder(selector, placeholder) {
+ const fieldEl = document.querySelector(selector);
+ if (fieldEl) {
+ fieldEl.placeholder = placeholder;
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/media-attribution.js
/*
- * FrequencyUpsell component which creates a modal to upsell the frequency of the donation
- * This is typically used to upsell a single donation into an annual donation, but the component
- * options can be configured to upsell any frequency to any other frequency. The upsell amount can also be configured
- * See FrequencyUpsellOptions for more details.
- */
+ Looks for specially crafted links and will transform its markup to display an attribution overlay on top of the image
+ Depends on "_engrid-media-attribution.scss" for styling
+ Example Image Input
+
+
+
-class FrequencyUpsell {
- constructor() {
- this.logger = new logger_EngridLogger("FrequencyUpsell", "lightgray", "darkblue", "π¦");
- this.upsellModal = null;
- this.options = null;
- this._frequency = DonationFrequency.getInstance();
- this._amount = DonationAmount.getInstance();
- this._fee = ProcessingFees.getInstance();
- this._form = en_form_EnForm.getInstance();
- this.modalSeen = false;
- if (!this.shouldRun()) {
- this.logger.log("FrequencyUpsell not running");
- return;
- }
- this.options = this.selectOptions(window.EngridFrequencyUpsell);
- this.logger.log("FrequencyUpsell initialized", this.options);
- this.upsellModal = new FrequencyUpsellModal(this.options);
- this.createFrequencyField();
- this.addEventListeners();
- }
- /**
- * Select the proper options (single config or A/B variant) and return a concrete FrequencyUpsellOptions object.
- * If an A/B test config is provided (abTest: true, options: [...]) a random variant is chosen and stored
- * in a 1-day cookie so subsequent visits get the same variant.
- */
- selectOptions(config) {
- // Simple (non AB) case
- if (!config.abTest) {
- return Object.assign(Object.assign({}, FrequencyUpsellOptionsDefaults), config);
- }
- const abConfig = config;
- const cookieName = abConfig.cookieName || "engrid_frequency_upsell_variant";
- const existing = get(cookieName);
- let index;
- if (existing !== undefined) {
- const parsed = parseInt(existing, 10);
- if (!isNaN(parsed) && parsed >= 0 && parsed < abConfig.options.length) {
- index = parsed;
- }
- else {
- index = this.randomIndex(abConfig.options.length);
- }
- }
- else {
- index = this.randomIndex(abConfig.options.length);
- }
- // Persist for configured duration
- const duration = abConfig.cookieDurationDays || 1;
- set(cookieName, index.toString(), { expires: duration });
- const chosen = abConfig.options[index];
- // Push variant info to dataLayer if available
- if (window.dataLayer) {
- window.dataLayer.push({
- event: "frequency_upsell_ab_variant",
- frequencyUpsellVariantIndex: index,
- frequencyUpsellVariantTitle: chosen.title,
+ Example Video Input (Doesn't currently visually display)
+ @TODO Video tags are processed but their is not visually displayed. Need to update "_engrid-media-attribution.scss"
+
+
+ Example Image Output
+ Jane Doe 1
+*/
+
+const media_attribution_tippy = (__webpack_require__(716)/* ["default"] */ .Ay);
+class media_attribution_MediaAttribution {
+ constructor() {
+ // Find all images with attribution but not with the "data-attribution-hide-overlay" attribute
+ this.mediaWithAttribution = document.querySelectorAll("img[data-attribution-source]:not([data-attribution-hide-overlay]), video[data-attribution-source]:not([data-attribution-hide-overlay])");
+ this.mediaWithAttribution.forEach(element => {
+ if (dist_engrid_ENGrid.debug) console.log("The following image was found with data attribution fields on it. It's markup will be changed to add caption support.", element);
+ // Creates the wapping element
+ let figure = document.createElement("figure");
+ figure.classList.add("media-with-attribution");
+ // Moves the inside its element
+ let mediaWithAttributionParent = element.parentNode;
+ if (mediaWithAttributionParent) {
+ mediaWithAttributionParent.insertBefore(figure, element);
+ figure.appendChild(element);
+ let mediaWithAttributionElement = element;
+ // Append the element after the and conditionally add the Source's Link to it
+ let attributionSource = mediaWithAttributionElement.dataset.attributionSource;
+ if (attributionSource) {
+ let attributionSourceLink = mediaWithAttributionElement.dataset.attributionSourceLink;
+ if (attributionSourceLink) {
+ mediaWithAttributionElement.insertAdjacentHTML("afterend", '' + attributionSource + " ");
+ } else {
+ mediaWithAttributionElement.insertAdjacentHTML("afterend", "" + attributionSource + " ");
+ }
+ const attributionSourceTooltip = "attributionSourceTooltip" in mediaWithAttributionElement.dataset ? mediaWithAttributionElement.dataset.attributionSourceTooltip : false;
+ if (attributionSourceTooltip) {
+ media_attribution_tippy(mediaWithAttributionElement.nextSibling, {
+ content: attributionSourceTooltip,
+ arrow: true,
+ arrowType: "default",
+ placement: "left",
+ trigger: "click mouseenter focus",
+ interactive: true
});
+ }
}
- return Object.assign(Object.assign({}, FrequencyUpsellOptionsDefaults), chosen);
- }
- randomIndex(length) {
- return Math.floor(Math.random() * length);
- }
- /**
- * Check if the FrequencyUpsell should run:
- * - Check if the FrequencyUpsell is enabled in the window object
- * - Check that we don't have an EngridUpsell active on this page
- * - Check that we don't have an EngagingNetworks upsell active on this page
- * @returns {boolean} - true if the FrequencyUpsell should run, false otherwise
- */
- shouldRun() {
- return (window.EngridFrequencyUpsell &&
- !window.EngridUpsell &&
- (!window.EngagingNetworks.upsell ||
- window.EngagingNetworks.upsell.length === 0));
- }
- /**
- * Get the upsell amount with/without fees
- * We want to display to the user the amount with fees, but we need to set the donation amount to the value without fees
- * @param {boolean} withFee - true if we want to include the fees in the upsell amount
- * @returns {number} - The upsell amount with fees
- */
- getUpsellAmount(withFee) {
- if (withFee) {
- const upsellAmount = this.options.upsellAmount(this._amount.amount);
- return upsellAmount + this._fee.calculateFees(upsellAmount);
+ }
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/live-variables.js
+
+
+class live_variables_LiveVariables {
+ constructor(options) {
+ var _a;
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._fees = processing_fees_ProcessingFees.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._form = events_en_form_EnForm.getInstance();
+ this.multiplier = 1 / 12;
+ this.options = Object.assign(Object.assign({}, options_OptionsDefaults), options);
+ this.submitLabel = ((_a = document.querySelector(".en__submit button")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "Donate";
+ this._amount.onAmountChange.subscribe(() => this.changeSubmitButton());
+ this._amount.onAmountChange.subscribe(() => this.changeLiveAmount());
+ this._amount.onAmountChange.subscribe(() => this.changeLiveUpsellAmount());
+ this._fees.onFeeChange.subscribe(() => this.changeLiveAmount());
+ this._fees.onFeeChange.subscribe(() => this.changeLiveUpsellAmount());
+ this._fees.onFeeChange.subscribe(() => this.changeSubmitButton());
+ this._frequency.onFrequencyChange.subscribe(() => this.changeLiveFrequency());
+ this._frequency.onFrequencyChange.subscribe(() => this.changeRecurrency());
+ this._frequency.onFrequencyChange.subscribe(() => this.changeSubmitButton());
+ this._form.onSubmit.subscribe(() => {
+ if (dist_engrid_ENGrid.getPageType() !== "SUPPORTERHUB") dist_engrid_ENGrid.disableSubmit("Processing...");
+ });
+ this._form.onError.subscribe(() => dist_engrid_ENGrid.enableSubmit());
+ // Watch the monthly-upsell links
+ document.addEventListener("click", e => {
+ const element = e.target;
+ if (element) {
+ if (element.classList.contains("monthly-upsell")) {
+ this.upsold(e);
+ } else if (element.classList.contains("form-submit")) {
+ e.preventDefault();
+ this._form.submitForm();
}
- return this.options.upsellAmount(this._amount.amount);
+ }
+ });
+ }
+ getAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = dist_engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = this.options.DecimalSeparator) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = this.options.ThousandsSeparator) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = this.options.DecimalPlaces) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = dist_engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? `${symbol} ${amountTxt} ` : "";
+ }
+ getUpsellAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = dist_engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = this.options.DecimalSeparator) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = this.options.ThousandsSeparator) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = this.options.DecimalPlaces) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = dist_engrid_ENGrid.formatNumber(Math.ceil(amount / 5) * 5, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? symbol + amountTxt : "";
+ }
+ getUpsellAmountRaw(amount = 0) {
+ const amountRaw = Math.ceil(amount / 5) * 5;
+ return amount > 0 ? amountRaw.toString() : "";
+ }
+ changeSubmitButton() {
+ const submit = document.querySelector(".en__submit button");
+ const amount = this.getAmountTxt(this._amount.amount + this._fees.fee);
+ const frequency = this._frequency.frequency == "onetime" ? "" : this._frequency.frequency == "annual" ? "annually" : this._frequency.frequency;
+ let label = this.submitLabel;
+ if (amount) {
+ label = label.replace("$AMOUNT", amount);
+ label = label.replace("$FREQUENCY", `${frequency} `);
+ } else {
+ label = label.replace("$AMOUNT", "");
+ label = label.replace("$FREQUENCY", "");
}
- addEventListeners() {
- var _a, _b;
- // When the Modal buttons are clicked
- (_b = (_a = this.upsellModal) === null || _a === void 0 ? void 0 : _a.modal) === null || _b === void 0 ? void 0 : _b.addEventListener("click", (e) => {
- const target = e.target;
- // Upsell is accepted
- if (target.id === "frequency-upsell-yes") {
- this.logger.log("Frequency upsell accepted");
- this._frequency.setFrequency(this.options.upsellFrequency);
- this._amount.setAmount(this.getUpsellAmount(false));
- this.options.onAccept();
- this._form.submitForm();
- this.upsellModal.close();
- return;
- }
- // Upsell is declined
- if (target.id === "frequency-upsell-no") {
- this.logger.log("Frequency upsell declined");
- this.options.onDecline();
- this._form.submitForm();
- this.upsellModal.close();
- return;
- }
- });
- // When the form is submitted
- this._form.onSubmit.subscribe(() => {
- var _a;
- // If we have a frequency we want to upsell on & the modal isn't already open
- // Since frequency in the event class doesn't have a specific type, I need to cast our options array to a general string array
- if (this.options.upsellFromFrequency.includes(this._frequency.frequency) &&
- !this.modalSeen) {
- // Open the modal and prevent form submission
- this.upsellModal.amountWithFees =
- this._amount.amount + this._fee.calculateFees(this._amount.amount);
- this.upsellModal.upsellAmountWithFees = this.getUpsellAmount(true);
- this.upsellModal.updateModalContent();
- this.logger.log("Frequency upsell modal opened");
- (_a = this.upsellModal) === null || _a === void 0 ? void 0 : _a.open();
- this.options.onOpen();
- this.modalSeen = true;
- this._form.submit = false;
- return false;
- }
- // If not opening, continue with the form submission
- this._form.submit = true;
- return true;
- });
+ if (submit && label) {
+ submit.innerHTML = label;
+ }
+ }
+ changeLiveAmount() {
+ const value = this._amount.amount + this._fees.fee;
+ const live_amount = document.querySelectorAll(".live-giving-amount");
+ live_amount.forEach(elem => elem.innerHTML = this.getAmountTxt(value));
+ }
+ changeLiveUpsellAmount() {
+ const value = (this._amount.amount + this._fees.fee) * this.multiplier;
+ const live_upsell_amount = document.querySelectorAll(".live-giving-upsell-amount");
+ live_upsell_amount.forEach(elem => elem.innerHTML = this.getUpsellAmountTxt(value));
+ const live_upsell_amount_raw = document.querySelectorAll(".live-giving-upsell-amount-raw");
+ live_upsell_amount_raw.forEach(elem => elem.innerHTML = this.getUpsellAmountRaw(value));
+ }
+ changeLiveFrequency() {
+ const live_frequency = document.querySelectorAll(".live-giving-frequency");
+ live_frequency.forEach(elem => elem.innerHTML = this._frequency.frequency == "onetime" ? "" : this._frequency.frequency);
+ }
+ changeRecurrency() {
+ const recurrpay = document.querySelector("[name='transaction.recurrpay']");
+ if (recurrpay && recurrpay.type != "radio") {
+ recurrpay.value = this._frequency.frequency == "onetime" ? "N" : "Y";
+ this._frequency.recurring = recurrpay.value;
+ if (dist_engrid_ENGrid.getOption("Debug")) console.log("Recurpay Changed!");
+ // Trigger the onChange event for the field
+ const event = new Event("change", {
+ bubbles: true
+ });
+ recurrpay.dispatchEvent(event);
+ }
+ }
+ // Watch for a clicks on monthly-upsell link
+ upsold(e) {
+ // Find and select monthly giving
+ const enFieldRecurrpay = document.querySelector(".en__field--recurrpay input[value='Y']");
+ if (enFieldRecurrpay) {
+ enFieldRecurrpay.checked = true;
+ }
+ // Find the hidden radio select that needs to be selected when entering an "Other" amount
+ const enFieldOtherAmountRadio = document.querySelector(".en__field--donationAmt input[value='other']");
+ if (enFieldOtherAmountRadio) {
+ enFieldOtherAmountRadio.checked = true;
+ }
+ // Enter the other amount and remove the "en__field__item--hidden" class from the input's parent
+ const enFieldOtherAmount = document.querySelector("input[name='transaction.donationAmt.other']");
+ if (enFieldOtherAmount) {
+ enFieldOtherAmount.value = this.getUpsellAmountRaw(this._amount.amount * this.multiplier);
+ this._amount.load();
+ this._frequency.load();
+ if (enFieldOtherAmount.parentElement) {
+ enFieldOtherAmount.parentElement.classList.remove("en__field__item--hidden");
+ }
}
- /**
- * Create the frequency field for the upsell, if it does not exist on the page already
- * This is required by DonationFrequency to set the frequency
- */
- createFrequencyField() {
- const frequencyField = document.querySelector(`input[name="transaction.recurrfreq"][value="${this.options.upsellFrequency.toUpperCase()}"]`);
- if (frequencyField)
- return;
- const frequencyFieldContainer = document.querySelector(".en__field--recurrfreq .en__field__element");
- frequencyFieldContainer === null || frequencyFieldContainer === void 0 ? void 0 : frequencyFieldContainer.insertAdjacentHTML("beforeend", `
-
-
-
- `);
+ const target = e.target;
+ if (target && target.classList.contains("form-submit")) {
+ e.preventDefault();
+ // Form submit
+ this._form.submitForm();
}
+ }
}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/sticky-nsg.js
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/upsell-lightbox.js
+class upsell_lightbox_UpsellLightbox {
+ constructor() {
+ this.overlay = document.createElement("div");
+ this._form = events_en_form_EnForm.getInstance();
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._fees = processing_fees_ProcessingFees.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._dataLayer = data_layer_DataLayer.getInstance();
+ this._suggestAmount = 0;
+ this.logger = new dist_logger_EngridLogger("UpsellLightbox", "black", "pink", "πͺ");
+ let options = "EngridUpsell" in window ? window.EngridUpsell : {};
+ this.options = Object.assign(Object.assign({}, upsell_options_UpsellOptionsDefaults), options);
+ //Disable for "applepay" via Vantiv payment method. Adding it to the array like this so it persists
+ //even if the client provides custom options.
+ this.options.disablePaymentMethods.push("applepay");
+ if (!this.shouldRun()) {
+ this.logger.log("Upsell script should NOT run");
+ // If we're not on a Donation Page, get out
+ return;
+ }
+ this.overlay.id = "enModal";
+ this.overlay.classList.add("is-hidden");
+ this.overlay.classList.add("image-" + this.options.imagePosition);
+ this.renderLightbox();
+ this._form.onSubmit.subscribe(() => this.open());
+ }
+ renderLightbox() {
+ const title = this.options.title.replace("{new-amount}", " ").replace("{old-amount}", " ").replace("{old-frequency}", " ");
+ const paragraph = this.options.paragraph.replace("{new-amount}", " ").replace("{old-amount}", " ").replace("{old-frequency}", " ");
+ const yes = this.options.yesLabel.replace("{new-amount}", " ").replace("{old-amount}", " ").replace("{old-frequency}", " ");
+ const no = this.options.noLabel.replace("{new-amount}", " ").replace("{old-amount}", " ").replace("{old-frequency}", " ");
+ const markup = `
+
+
+
+
+ ${this.options.canClose ? `
` : ``}
+
+ ${title}
+
+ ${this.options.otherAmount ? `
+
+
+
+ ${this.options.otherLabel}
+
+
+
+
+ Minimum ${this.getAmountTxt(this.options.minAmount)}
+
+
+ ` : ``}
-class StickyNSG {
- constructor() {
- this.logger = new logger_EngridLogger("StickyNSG", "teal", "white", "π");
- this.cookieName = "engrid-sticky-nsg";
- if (!this.shouldRun())
- return;
- this.logger.log("Sticky NSG is enabled");
- this.deleteCookieIfGiftProcessComplete();
- this.createStickyNSGCookie();
- this.applyStickyNSGCookie();
+
+ ${paragraph}
+
+
+
+
+
+
+
+ `;
+ this.overlay.innerHTML = markup;
+ const closeButton = this.overlay.querySelector("#goMonthlyClose");
+ const yesButton = this.overlay.querySelector("#upsellYesButton a");
+ const noButton = this.overlay.querySelector("#upsellNoButton button");
+ yesButton.addEventListener("click", this.continue.bind(this));
+ noButton.addEventListener("click", this.continue.bind(this));
+ if (closeButton) closeButton.addEventListener("click", this.close.bind(this));
+ this.overlay.addEventListener("click", e => {
+ if (e.target instanceof Element && e.target.id == this.overlay.id && this.options.canClose) {
+ this.close(e);
+ }
+ });
+ document.addEventListener("keyup", e => {
+ if (e.key === "Escape" && closeButton) {
+ closeButton.click();
+ }
+ });
+ document.body.appendChild(this.overlay);
+ const otherField = document.querySelector("#secondOtherField");
+ if (otherField) {
+ otherField.addEventListener("keyup", this.popupOtherField.bind(this));
}
- shouldRun() {
- return engrid_ENGrid.getOption("StickyNSG") === true;
+ this.logger.log("Upsell script rendered");
+ }
+ // Should we run the script?
+ shouldRun() {
+ // if it's a first page of a Donation page
+ return (
+ // !hideModal &&
+ !this.shouldSkip() && "EngridUpsell" in window && !!window.pageJson && window.pageJson.pageNumber == 1 && ["donation", "premiumgift"].includes(window.pageJson.pageType)
+ );
+ }
+ shouldSkip() {
+ if ("EngridUpsell" in window && window.EngridUpsell.skipUpsell) {
+ return true;
}
- /*
- * Determine if NSG provided by EN is active on the page
- */
- nsgActiveOnPage() {
- return (window.EngagingNetworks &&
- window.EngagingNetworks.suggestedGift &&
- typeof window.EngagingNetworks.suggestedGift === "object" &&
- Object.keys(window.EngagingNetworks.suggestedGift).length > 0);
+ return this.options.skipUpsell;
+ }
+ popupOtherField() {
+ var _a, _b;
+ const value = parseFloat((_b = (_a = this.overlay.querySelector("#secondOtherField")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
+ const live_upsell_amount = document.querySelectorAll("#upsellYesButton .upsell_suggestion");
+ const upsellAmount = this.getUpsellAmount();
+ if (!isNaN(value) && value > 0) {
+ this.checkOtherAmount(value);
+ } else {
+ this.checkOtherAmount(upsellAmount);
}
- /*
- * Delete the cookie if the gift process is complete
- */
- deleteCookieIfGiftProcessComplete() {
- if (engrid_ENGrid.getGiftProcess()) {
- this.logger.log("Gift process complete, removing sticky NSG cookie if it exists");
- remove(this.cookieName);
- }
+ live_upsell_amount.forEach(elem => elem.innerHTML = this.getAmountTxt(upsellAmount + this._fees.calculateFees(upsellAmount)));
+ }
+ liveAmounts() {
+ const live_upsell_amount = document.querySelectorAll(".upsell_suggestion");
+ const live_amount = document.querySelectorAll(".upsell_amount");
+ const upsellAmount = this.getUpsellAmount();
+ const suggestedAmount = upsellAmount + this._fees.calculateFees(upsellAmount);
+ live_upsell_amount.forEach(elem => elem.innerHTML = this.getAmountTxt(suggestedAmount));
+ live_amount.forEach(elem => elem.innerHTML = this.getAmountTxt(this._amount.amount + this._fees.fee));
+ }
+ liveFrequency() {
+ const live_upsell_frequency = document.querySelectorAll(".upsell_frequency");
+ live_upsell_frequency.forEach(elem => elem.innerHTML = this.getFrequencyTxt());
+ }
+ // Return the Suggested Upsell Amount
+ getUpsellAmount() {
+ var _a, _b;
+ const amount = this._amount.amount;
+ const otherAmount = parseFloat((_b = (_a = this.overlay.querySelector("#secondOtherField")) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
+ if (otherAmount > 0) {
+ return otherAmount > this.options.minAmount ? otherAmount : this.options.minAmount;
}
- /*
- * Create the sticky NSG cookie if NSG is active on the page
- */
- createStickyNSGCookie() {
- var _a, _b, _c, _d, _e, _f;
- if (!this.nsgActiveOnPage()) {
- this.logger.log("No NSG active on page, not creating sticky NSG cookie");
- return;
- }
- const url = new URL(window.location.href);
- if (url.searchParams.get("skipstickynsg") === "true") {
- this.logger.log("'skipstickynsg' param present, not creating sticky NSG cookie");
- return;
- }
- // We do some reformating to match the EngridAmounts format
- // We also add "Other" to the amounts list
- const nsg = window.EngagingNetworks.suggestedGift;
- this.logger.log("Creating sticky NSG cookie", nsg);
- const oneTimeNsg = (_a = nsg.single) === null || _a === void 0 ? void 0 : _a.reduce((acc, curr) => {
- acc[curr.value] = curr.value;
- return acc;
- }, {});
- const oneTimeDefault = (_c = (_b = nsg.single) === null || _b === void 0 ? void 0 : _b.find((gift) => gift.nextSuggestedGift)) === null || _c === void 0 ? void 0 : _c.value;
- const recurringNsg = (_d = nsg.recurring) === null || _d === void 0 ? void 0 : _d.reduce((acc, curr) => {
- acc[curr.value] = curr.value;
- return acc;
- }, {});
- const recurringDefault = (_f = (_e = nsg.recurring) === null || _e === void 0 ? void 0 : _e.find((gift) => gift.nextSuggestedGift)) === null || _f === void 0 ? void 0 : _f.value;
- const nsgCookieData = {};
- if (oneTimeNsg && oneTimeDefault) {
- nsgCookieData.onetime = {
- amounts: oneTimeNsg,
- default: oneTimeDefault,
- stickyDefault: false,
- };
- }
- if (recurringNsg && recurringDefault) {
- nsgCookieData.monthly = {
- amounts: recurringNsg,
- default: recurringDefault,
- stickyDefault: false,
- };
- }
- if (Object.keys(nsgCookieData).length === 0) {
- this.logger.log("No valid NSG data found to create sticky NSG cookie");
- return;
+ let upsellAmount = 0;
+ for (let i = 0; i < this.options.amountRange.length; i++) {
+ let val = this.options.amountRange[i];
+ if (upsellAmount == 0 && amount <= val.max) {
+ upsellAmount = val.suggestion;
+ if (upsellAmount === 0) return 0;
+ if (typeof upsellAmount !== "number") {
+ const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
+ upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
}
- const cookieValue = JSON.stringify(nsgCookieData);
- set(this.cookieName, cookieValue, { path: "/", expires: 30 });
- this.logger.log("Sticky NSG cookie created", cookieValue);
+ break;
+ }
}
- /*
- * Apply the sticky NSG cookie values to window.EngridAmounts if NSG is not active on the page
- */
- applyStickyNSGCookie() {
- if (this.nsgActiveOnPage()) {
- this.logger.log("NSG active on page, not applying sticky NSG cookie, leaving the EN NSG values.");
- return;
- }
- const cookieValue = get(this.cookieName);
- if (!cookieValue) {
- this.logger.log("No sticky NSG cookie found, nothing to apply");
- return;
- }
- try {
- const nsg = JSON.parse(cookieValue);
- this.logger.log("Applying sticky NSG cookie values", nsg);
- window.EngridAmounts = nsg;
- }
- catch (e) {
- this.logger.error("Error parsing sticky NSG cookie, not applying", e);
+ return upsellAmount > this.options.minAmount ? upsellAmount : this.options.minAmount;
+ }
+ shouldOpen() {
+ const upsellAmount = this.getUpsellAmount();
+ const paymenttype = dist_engrid_ENGrid.getFieldValue("transaction.paymenttype") || "";
+ this._suggestAmount = upsellAmount;
+ // If frequency is not onetime or
+ // the modal is already opened or
+ // there's no suggestion for this donation amount,
+ // we should not open
+ if (this.freqAllowed() && !this.shouldSkip() && !this.options.disablePaymentMethods.includes(paymenttype.toLowerCase()) && !this.overlay.classList.contains("is-submitting") && upsellAmount > 0) {
+ this.logger.log("Upsell Frequency " + this._frequency.frequency);
+ this.logger.log("Upsell Amount " + this._amount.amount);
+ this.logger.log("Upsell Suggested Amount " + upsellAmount);
+ return true;
+ }
+ return false;
+ }
+ // Return true if the current frequency is allowed by the options
+ freqAllowed() {
+ const freq = this._frequency.frequency;
+ const allowed = [];
+ if (this.options.oneTime) allowed.push("onetime");
+ if (this.options.annual) allowed.push("annual");
+ return allowed.includes(freq);
+ }
+ open() {
+ this.logger.log("Upsell script opened");
+ if (!this.shouldOpen()) {
+ // In the circumstance when the form fails to validate via server-side validation, the page will reload
+ // When that happens, we should place the original amount saved in sessionStorage into the upsell original amount field
+ let original = window.sessionStorage.getItem("original");
+ if (original && document.querySelectorAll(".en__errorList .en__error").length > 0) {
+ this.setOriginalAmount(original);
+ }
+ // Returning true will give the "go ahead" to submit the form
+ this._form.submit = true;
+ return true;
+ }
+ this.liveAmounts();
+ this.liveFrequency();
+ this.overlay.classList.remove("is-hidden");
+ this._form.submit = false;
+ dist_engrid_ENGrid.setBodyData("has-lightbox", "");
+ return false;
+ }
+ // Set the original amount into a hidden field using the upsellOriginalGiftAmountFieldName, if provided
+ setOriginalAmount(original) {
+ if (this.options.upsellOriginalGiftAmountFieldName) {
+ let enFieldUpsellOriginalAmount = document.querySelector(".en__field__input.en__field__input--hidden[name='" + this.options.upsellOriginalGiftAmountFieldName + "']");
+ if (!enFieldUpsellOriginalAmount) {
+ let pageform = document.querySelector("form.en__component--page");
+ if (pageform) {
+ let input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("name", this.options.upsellOriginalGiftAmountFieldName);
+ input.classList.add("en__field__input", "en__field__input--hidden");
+ pageform.appendChild(input);
+ enFieldUpsellOriginalAmount = document.querySelector('.en__field__input.en__field__input--hidden[name="' + this.options.upsellOriginalGiftAmountFieldName + '"]');
}
+ }
+ if (enFieldUpsellOriginalAmount) {
+ // save it to a session variable just in case this page reloaded due to server-side validation error
+ window.sessionStorage.setItem("original", original);
+ enFieldUpsellOriginalAmount.setAttribute("value", original);
+ }
+ }
+ }
+ // Proceed to the next page (upsold or not)
+ continue(e) {
+ var _a;
+ e.preventDefault();
+ if (e.target instanceof Element && ((_a = document.querySelector("#upsellYesButton")) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
+ this.logger.success("Upsold");
+ this.setOriginalAmount(this._amount.amount.toString());
+ const upsoldAmount = this.getUpsellAmount();
+ const originalAmount = this._amount.amount;
+ this._frequency.setFrequency("monthly");
+ this._amount.setAmount(upsoldAmount);
+ this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL", {
+ eventValue: true,
+ originalAmount: originalAmount,
+ upsoldAmount: upsoldAmount,
+ frequency: "monthly"
+ });
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL", true);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT", originalAmount);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "MONTHLY");
+ this.renderConversionField("upsellSuccess", "onetime", originalAmount, "monthly", this._suggestAmount, "monthly", upsoldAmount);
+ } else {
+ this.setOriginalAmount("");
+ window.sessionStorage.removeItem("original");
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL", false);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "ONE-TIME");
+ this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._suggestAmount, this._frequency.frequency, this._amount.amount);
+ }
+ this._form.submitForm();
+ }
+ // Close the lightbox
+ close(e) {
+ e.preventDefault();
+ this.overlay.classList.add("is-hidden");
+ dist_engrid_ENGrid.setBodyData("has-lightbox", false);
+ if (this.options.submitOnClose) {
+ this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._suggestAmount, this._frequency.frequency, this._amount.amount);
+ this._form.submitForm();
+ } else {
+ this._form.dispatchError();
+ }
+ }
+ getAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = dist_engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = dist_engrid_ENGrid.getOption("DecimalSeparator")) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = dist_engrid_ENGrid.getOption("ThousandsSeparator")) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = dist_engrid_ENGrid.getOption("DecimalPlaces")) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = dist_engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? symbol + amountTxt : "";
+ }
+ getFrequencyTxt() {
+ const freqTxt = {
+ onetime: "one-time",
+ monthly: "monthly",
+ annual: "annual"
+ };
+ const frequency = this._frequency.frequency;
+ return frequency in freqTxt ? freqTxt[frequency] : frequency;
+ }
+ checkOtherAmount(value) {
+ const otherInput = document.querySelector(".upsellOtherAmountInput");
+ if (otherInput) {
+ if (value >= this.options.minAmount) {
+ otherInput.classList.remove("is-invalid");
+ } else {
+ otherInput.classList.add("is-invalid");
+ }
+ }
+ }
+ renderConversionField(event,
+ // The event that triggered the conversion
+ freq,
+ // The frequency of the donation (onetime, monthly, annual)
+ amt,
+ // The original amount of the donation (before the upsell)
+ sugFreq,
+ // The suggested frequency of the upsell (monthly)
+ sugAmt,
+ // The suggested amount of the upsell
+ subFreq,
+ // The submitted frequency of the upsell (onetime, monthly, annual)
+ subAmt // The submitted amount of the upsell
+ ) {
+ if (this.options.conversionField === "") return;
+ const conversionField = document.querySelector("input[name='" + this.options.conversionField + "']") || dist_engrid_ENGrid.createHiddenInput(this.options.conversionField);
+ if (!conversionField) {
+ this.logger.error("Could not find or create the conversion field");
+ return;
}
+ const conversionValue = `event:${event},freq:${freq},amt:${amt},sugFreq:${sugFreq},sugAmt:${sugAmt},subFreq:${subFreq},subAmt:${subAmt}`;
+ conversionField.value = conversionValue;
+ this.logger.log(`Conversion Field ${event}`, conversionValue);
+ }
}
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/sticky-prepopulation.js
-var sticky_prepopulation_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/upsell-checkbox.js
+// This component will add a checkbox to the donation form that will allow the user to upgrade their donation to a monthly donation.
-class StickyPrepopulation {
- constructor() {
- this.logger = new logger_EngridLogger("StickyPrepopulation", "teal", "white", "π");
- this.options = { fields: [] };
- this.cookieName = "engrid-sticky-prepop";
- if (!this.shouldRun()) {
- return;
- }
- this.logger.log("StickyPrepopulation initialized");
- if (engrid_ENGrid.getGiftProcess()) {
- this.deleteCookie();
- return;
- }
- if (engrid_ENGrid.getPageNumber() !== 1 || !engrid_ENGrid.getField("supporter.emailAddress")) {
- this.logger.log("Not on page 1 or email field not present, not creating cookie or applying pre-population.");
- return;
- }
- this.createCookie();
- this.applyPrepopulation();
+class upsell_checkbox_UpsellCheckbox {
+ constructor() {
+ this.checkboxOptions = false;
+ this.checkboxOptionsDefaults = {
+ label: "Make my gift a monthly gift of {new-amount}/mo ",
+ location: "before .en__component .en__submit",
+ cssClass: ""
+ };
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._fees = processing_fees_ProcessingFees.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._dataLayer = data_layer_DataLayer.getInstance();
+ this.checkboxContainer = null;
+ this.oldAmount = 0;
+ this.oldFrequency = "one-time";
+ this.resetCheckbox = false;
+ this.logger = new dist_logger_EngridLogger("UpsellCheckbox", "black", "LemonChiffon", "β
");
+ let options = "EngridUpsell" in window ? window.EngridUpsell : {};
+ this.options = Object.assign(Object.assign({}, upsell_options_UpsellOptionsDefaults), options);
+ if (this.options.upsellCheckbox === false) {
+ this.logger.log("Skipped");
+ return;
}
- /*
- * Determine if we should run the script
- * Do not run if RememberMe is active
- * Do not run if on a chain link
- * Only run if StickyPrepopulation option is set with fields
- */
- shouldRun() {
- if (engrid_ENGrid.getOption("RememberMe")) {
- return false;
- }
- const url = new URL(window.location.href);
- const options = engrid_ENGrid.getOption("StickyPrepopulation");
- if (options && (options === null || options === void 0 ? void 0 : options.fields.length) > 0 && !url.searchParams.has("chain")) {
- this.options = options;
- return true;
- }
- else {
- return false;
+ // To avoid using both UpsellLightbox and UpsellCheckbox at the same time, set window.EngridUpsell.skipUpsell to true if there's an upsellCheckbox
+ if ("upsellCheckbox" in options && options.upsellCheckbox !== false) {
+ window.EngridUpsell.skipUpsell = true; // Skip the upsell lightbox
+ }
+ this.checkboxOptions = Object.assign(Object.assign({}, this.checkboxOptionsDefaults), this.options.upsellCheckbox);
+ if (!this.shouldRun()) {
+ this.logger.log("should NOT run");
+ // If we're not on a Donation Page, get out
+ return;
+ }
+ this.renderCheckbox();
+ this.updateLiveData();
+ this._frequency.onFrequencyChange.subscribe(() => this.updateLiveData());
+ this._frequency.onFrequencyChange.subscribe(() => this.resetUpsellCheckbox());
+ this._amount.onAmountChange.subscribe(() => this.updateLiveData());
+ this._amount.onAmountChange.subscribe(() => this.resetUpsellCheckbox());
+ this._fees.onFeeChange.subscribe(() => this.updateLiveData());
+ }
+ updateLiveData() {
+ this.liveAmounts();
+ this.liveFrequency();
+ }
+ resetUpsellCheckbox() {
+ var _a, _b;
+ // Only reset the upsell checkbox if it has been checked
+ if (!this.resetCheckbox) return;
+ this.logger.log("Reset");
+ // Uncheck the upsell checkbox
+ const checkbox = (_a = this.checkboxContainer) === null || _a === void 0 ? void 0 : _a.querySelector("#upsellCheckbox");
+ if (checkbox) {
+ checkbox.checked = false;
+ }
+ // Hide the upsell checkbox
+ (_b = this.checkboxContainer) === null || _b === void 0 ? void 0 : _b.classList.add("recurring-frequency-y-hide");
+ this.oldAmount = 0;
+ this.oldFrequency = "one-time";
+ this.resetCheckbox = false;
+ }
+ renderCheckbox() {
+ if (this.checkboxOptions === false) return;
+ const label = this.checkboxOptions.label.replace("{new-amount}", " ").replace("{old-amount}", " ").replace("{old-frequency}", " ");
+ const formBlock = document.createElement("div");
+ formBlock.classList.add("en__component", "en__component--formblock", "recurring-frequency-y-hide", "engrid-upsell-checkbox");
+ if (this.checkboxOptions.cssClass) formBlock.classList.add(this.checkboxOptions.cssClass);
+ formBlock.innerHTML = `
+ `;
+ const checkbox = formBlock.querySelector("#upsellCheckbox");
+ if (checkbox) checkbox.addEventListener("change", this.toggleCheck.bind(this));
+ const position = this.checkboxOptions.location.split(" ")[0];
+ // Location is everything after the first space
+ const location = this.checkboxOptions.location.split(" ").slice(1).join(" ").trim();
+ const target = document.querySelector(location);
+ this.checkboxContainer = formBlock;
+ if (target) {
+ if (position === "before") {
+ this.logger.log("rendered before");
+ target.before(formBlock);
+ } else {
+ this.logger.log("rendered after");
+ target.after(formBlock);
+ }
+ } else {
+ this.logger.error("could not render - target not found");
+ }
+ }
+ // Should we run the script?
+ shouldRun() {
+ // if it's a first page of a Donation page
+ return dist_engrid_ENGrid.getPageNumber() === 1 && dist_engrid_ENGrid.getPageType() === "DONATION";
+ }
+ showCheckbox() {
+ if (this.checkboxContainer) this.checkboxContainer.classList.remove("hide");
+ }
+ hideCheckbox() {
+ if (this.checkboxContainer) this.checkboxContainer.classList.add("hide");
+ }
+ liveAmounts() {
+ // Only update live data if the current frequency is one-time
+ if (this._frequency.frequency !== "onetime") return;
+ const live_upsell_amount = document.querySelectorAll(".upsell_suggestion");
+ const live_amount = document.querySelectorAll(".upsell_amount");
+ const upsellAmount = this.getUpsellAmount();
+ const suggestedAmount = upsellAmount + this._fees.calculateFees(upsellAmount);
+ if (suggestedAmount > 0) {
+ this.showCheckbox();
+ } else {
+ this.hideCheckbox();
+ }
+ live_upsell_amount.forEach(elem => elem.innerHTML = this.getAmountTxt(suggestedAmount));
+ live_amount.forEach(elem => elem.innerHTML = this.getAmountTxt(this._amount.amount + this._fees.fee));
+ }
+ liveFrequency() {
+ const live_upsell_frequency = document.querySelectorAll(".upsell_frequency");
+ live_upsell_frequency.forEach(elem => elem.innerHTML = this.getFrequencyTxt());
+ }
+ // Return the Suggested Upsell Amount
+ getUpsellAmount() {
+ const amount = this._amount.amount;
+ let upsellAmount = 0;
+ for (let i = 0; i < this.options.amountRange.length; i++) {
+ let val = this.options.amountRange[i];
+ if (upsellAmount == 0 && amount <= val.max) {
+ upsellAmount = val.suggestion;
+ if (upsellAmount === 0) return 0;
+ if (typeof upsellAmount !== "number") {
+ const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
+ upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
}
+ break;
+ }
}
- /*
- * Delete the cookie if the gift process is complete
- */
- deleteCookie() {
- this.logger.log("Gift process complete, removing sticky prepopulation cookie if it exists");
- remove(this.cookieName);
+ return upsellAmount > this.options.minAmount ? upsellAmount : this.options.minAmount;
+ }
+ // Proceed to the next page (upsold or not)
+ toggleCheck(e) {
+ var _a, _b;
+ e.preventDefault();
+ if (e.target.checked) {
+ this.logger.success("Upsold");
+ const upsoldAmount = this.getUpsellAmount();
+ const originalAmount = this._amount.amount;
+ this.oldAmount = originalAmount;
+ this.oldFrequency = this._frequency.frequency;
+ // If we're checking the upsell checkbox, remove the class that hides it on different frequencies
+ (_a = this.checkboxContainer) === null || _a === void 0 ? void 0 : _a.classList.remove("recurring-frequency-y-hide");
+ this._frequency.setFrequency("monthly");
+ this._amount.setAmount(upsoldAmount);
+ this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL_CHECKBOX", {
+ eventValue: true,
+ originalAmount: originalAmount,
+ upsoldAmount: upsoldAmount,
+ frequency: "monthly"
+ });
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX", true);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT", originalAmount);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "MONTHLY");
+ this.renderConversionField("upsellSuccess", "onetime", originalAmount, "monthly", upsoldAmount, "monthly", upsoldAmount);
+ // Set the resetCheckbox flag to true so it will reset if the user changes the amount or frequency
+ window.setTimeout(() => {
+ this.resetCheckbox = true;
+ }, 500);
+ } else {
+ this.resetCheckbox = false;
+ this.logger.success("Not Upsold");
+ this._amount.setAmount(this.oldAmount);
+ this._frequency.setFrequency(this.oldFrequency);
+ (_b = this.checkboxContainer) === null || _b === void 0 ? void 0 : _b.classList.add("recurring-frequency-y-hide");
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX", false);
+ this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY", "ONE-TIME");
+ this.renderConversionField("upsellFail", this._frequency.frequency, this._amount.amount, "monthly", this._amount.amount, this._frequency.frequency, this._amount.amount);
+ }
+ }
+ getAmountTxt(amount = 0) {
+ var _a, _b, _c, _d;
+ const symbol = (_a = dist_engrid_ENGrid.getCurrencySymbol()) !== null && _a !== void 0 ? _a : "$";
+ const dec_separator = (_b = dist_engrid_ENGrid.getOption("DecimalSeparator")) !== null && _b !== void 0 ? _b : ".";
+ const thousands_separator = (_c = dist_engrid_ENGrid.getOption("ThousandsSeparator")) !== null && _c !== void 0 ? _c : "";
+ const dec_places = amount % 1 == 0 ? 0 : (_d = dist_engrid_ENGrid.getOption("DecimalPlaces")) !== null && _d !== void 0 ? _d : 2;
+ const amountTxt = dist_engrid_ENGrid.formatNumber(amount, dec_places, dec_separator, thousands_separator);
+ return amount > 0 ? symbol + amountTxt : "";
+ }
+ getFrequencyTxt() {
+ const freqTxt = {
+ onetime: "one-time",
+ monthly: "monthly",
+ annual: "annual"
+ };
+ const frequency = this._frequency.frequency;
+ return frequency in freqTxt ? freqTxt[frequency] : frequency;
+ }
+ renderConversionField(event,
+ // The event that triggered the conversion
+ freq,
+ // The frequency of the donation (onetime, monthly, annual)
+ amt,
+ // The original amount of the donation (before the upsell)
+ sugFreq,
+ // The suggested frequency of the upsell (monthly)
+ sugAmt,
+ // The suggested amount of the upsell
+ subFreq,
+ // The submitted frequency of the upsell (onetime, monthly, annual)
+ subAmt // The submitted amount of the upsell
+ ) {
+ if (this.options.conversionField === "") return;
+ const conversionField = document.querySelector("input[name='" + this.options.conversionField + "']") || dist_engrid_ENGrid.createHiddenInput(this.options.conversionField);
+ if (!conversionField) {
+ this.logger.error("Could not find or create the conversion field");
+ return;
}
- /*
- * Create the cookie if we're coming from a campaign link and supporterId is present
- */
- createCookie() {
- var _a;
- return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
- // If we're not coming from a campaign link, don't create the cookie
- if (!((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId)) {
- this.logger.log("No supporterId present, not creating sticky prepopulation cookie");
- return;
- }
- try {
- const encryptedSupporterDetails = yield this.encryptSupporterDetails(this.getSupporterDetailsFromFields());
- set(this.cookieName, window.btoa(JSON.stringify({
- encryptedData: encryptedSupporterDetails.encryptedData,
- iv: encryptedSupporterDetails.iv,
- pageId: engrid_ENGrid.getPageID()
- })), { path: "/", expires: 7 });
- }
- catch (e) {
- this.logger.log("Error creating sticky prepopulation cookie");
- return;
+ const conversionValue = `event:${event},freq:${freq},amt:${amt},sugFreq:${sugFreq},sugAmt:${sugAmt},subFreq:${subFreq},subAmt:${subAmt}`;
+ conversionField.value = conversionValue;
+ this.logger.log(`Conversion Field ${event}`, conversionValue);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/show-hide-radio-checkboxes.js
+
+class show_hide_radio_checkboxes_ShowHideRadioCheckboxes {
+ // Create default data attributes on all fields
+ createDataAttributes() {
+ this.elements.forEach(item => {
+ if (item instanceof HTMLInputElement) {
+ let inputValue = item.value.replace(/\W/g, "");
+ document.querySelectorAll("." + this.classes + inputValue).forEach(el => {
+ // Consider toggling "hide" class so these fields can be displayed when in a debug state
+ if (el instanceof HTMLElement) {
+ const fields = el.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");
+ if (fields.length > 0) {
+ fields.forEach(field => {
+ if (field instanceof HTMLInputElement || field instanceof HTMLSelectElement) {
+ if (!field.hasAttribute("data-original-value")) {
+ field.setAttribute("data-original-value", field.value);
+ }
+ if (!field.hasAttribute("data-value")) {
+ field.setAttribute("data-value", field.value);
+ }
+ }
+ });
}
- this.logger.log("Sticky prepopulation cookie created");
+ }
});
+ }
+ });
+ }
+ // Hide All Divs
+ hideAll() {
+ this.elements.forEach((item, index) => {
+ if (item instanceof HTMLInputElement) this.hide(item);
+ });
+ }
+ // Hide Single Element Div
+ hide(item) {
+ let inputValue = item.value.replace(/\W/g, "");
+ document.querySelectorAll("." + this.classes + inputValue).forEach(el => {
+ // Consider toggling "hide" class so these fields can be displayed when in a debug state
+ if (el instanceof HTMLElement) {
+ this.toggleValue(el, "hide");
+ el.style.display = "none";
+ this.logger.log("Hiding", el);
+ const input = el.querySelector("input");
+ if (input instanceof HTMLInputElement) {
+ input.setAttribute("aria-required", "false");
+ this.logger.log("aria-required set to FALSE", input);
+ }
+ }
+ });
+ }
+ // Show Single Element Div
+ show(item) {
+ let inputValue = item.value.replace(/\W/g, "");
+ document.querySelectorAll("." + this.classes + inputValue).forEach(el => {
+ // Consider toggling "hide" class so these fields can be displayed when in a debug state
+ if (el instanceof HTMLElement) {
+ this.toggleValue(el, "show");
+ el.style.display = "";
+ this.logger.log("Showing", el);
+ const input = el.querySelector("input");
+ if (input instanceof HTMLInputElement) {
+ input.setAttribute("aria-required", "true");
+ this.logger.log("aria-required set to TRUE", input);
+ }
+ }
+ });
+ if (item.type == "checkbox" && !item.checked) {
+ this.hide(item);
}
- /*
- * If the cookie is present and supporterId is not (it's not a campaign link prefilled by EN),
- * then apply the prepopulation
- */
- applyPrepopulation() {
+ }
+ // Take the field values and add to a data attribute on the field
+ toggleValue(item, type) {
+ if (type == "hide" && !dist_engrid_ENGrid.isVisible(item)) return;
+ this.logger.log(`toggleValue: ${type}`);
+ const fields = item.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");
+ if (fields.length > 0) {
+ fields.forEach(field => {
var _a;
- return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
- const cookieData = get(this.cookieName);
- if (!cookieData) {
- this.logger.log("No sticky prepopulation cookie found, not prepopulating fields");
- return;
- }
- if ((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId) {
- this.logger.log("SupporterId present, not applying sticky prepopulation");
- return;
- }
- let supporterDetails = {};
- try {
- const encryptedSupporterDetails = JSON.parse(window.atob(cookieData));
- if (!encryptedSupporterDetails || (encryptedSupporterDetails === null || encryptedSupporterDetails === void 0 ? void 0 : encryptedSupporterDetails.pageId) !== engrid_ENGrid.getPageID()) {
- this.logger.log("No encrypted supporter details found in cookie, or page ID does not match");
- return;
- }
- supporterDetails = JSON.parse(yield this.decryptSupporterDetails(this.base64ToArrayBuffer(encryptedSupporterDetails.encryptedData), new Uint8Array(this.base64ToArrayBuffer(encryptedSupporterDetails.iv))));
- }
- catch (e) {
- this.logger.log("Error decrypting supporter details from cookie");
- return;
+ if (field instanceof HTMLInputElement || field instanceof HTMLSelectElement) {
+ if (field.name) {
+ const fieldValue = dist_engrid_ENGrid.getFieldValue(field.name);
+ const originalValue = field.getAttribute("data-original-value");
+ const dataValue = (_a = field.getAttribute("data-value")) !== null && _a !== void 0 ? _a : "";
+ if (type === "hide") {
+ field.setAttribute("data-value", fieldValue);
+ dist_engrid_ENGrid.setFieldValue(field.name, originalValue);
+ } else {
+ dist_engrid_ENGrid.setFieldValue(field.name, dataValue);
}
- this.options.fields.forEach((fieldName) => {
- if (!supporterDetails[fieldName])
- return;
- engrid_ENGrid.setFieldValue(fieldName, decodeURIComponent(supporterDetails[fieldName]));
- this.logger.log(`Setting "${fieldName}" to "${decodeURIComponent(supporterDetails[fieldName])}"`);
- });
- });
+ }
+ }
+ });
}
- /*
- * Get the supporter details from the form fields
- */
- getSupporterDetailsFromFields() {
- const supporterDetails = {};
- this.options.fields.forEach((fieldName) => {
- let field = document.querySelector(`[name="${fieldName}"]`);
- // If it is a radio or checkbox, get the checked value
- if (field) {
- if (field.type === "radio" || field.type === "checkbox") {
- field = document.querySelector(`[name="${fieldName}"]:checked`);
- }
- supporterDetails[fieldName] = encodeURIComponent(field.value);
- }
+ }
+ getSessionState() {
+ var _a;
+ try {
+ const plainState = (_a = window.sessionStorage.getItem(`engrid_ShowHideRadioCheckboxesState`)) !== null && _a !== void 0 ? _a : "";
+ return JSON.parse(plainState);
+ } catch (err) {
+ return [];
+ }
+ }
+ storeSessionState() {
+ const state = this.getSessionState();
+ [...this.elements].forEach(element => {
+ var _a, _b;
+ if (!(element instanceof HTMLInputElement)) return;
+ if (element.type == "radio" && element.checked) {
+ //remove other items that have the same "class" property
+ state.forEach((item, index) => {
+ if (item.class == this.classes) {
+ state.splice(index, 1);
+ }
});
- return supporterDetails;
- }
- /*
- * Encrypt the supporter details
- */
- encryptSupporterDetails(supporterDetails) {
- return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
- const encryptionKey = yield this.createEncryptionKey(this.getSeed());
- const iv = window.crypto.getRandomValues(new Uint8Array(12));
- const supporterDetailsString = JSON.stringify(supporterDetails);
- const encryptedData = yield window.crypto.subtle.encrypt({
- name: "AES-GCM",
- iv: iv,
- }, encryptionKey, new TextEncoder().encode(supporterDetailsString));
- return {
- encryptedData: this.arrayBufferToBase64(encryptedData),
- iv: this.arrayBufferToBase64(iv),
- };
+ //add the current item, with the currently active value
+ state.push({
+ page: dist_engrid_ENGrid.getPageID(),
+ class: this.classes,
+ value: element.value
});
- }
- /*
- * Decrypt the supporter details
- */
- decryptSupporterDetails(encryptedSupporterDetails, iv) {
- return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
- const encryptionKey = yield this.createEncryptionKey(this.getSeed());
- const decryptedData = yield window.crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, encryptionKey, encryptedSupporterDetails);
- return new TextDecoder().decode(decryptedData);
+ this.logger.log("storing radio state", state[state.length - 1]);
+ }
+ if (element.type == "checkbox") {
+ //remove other items that have the same "class" property
+ state.forEach((item, index) => {
+ if (item.class == this.classes) {
+ state.splice(index, 1);
+ }
});
- }
- /*
- * Create the encryption key
- */
- createEncryptionKey(seed) {
- return sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
- const encoder = new TextEncoder();
- const keyMaterial = yield window.crypto.subtle.importKey("raw", encoder.encode(seed), { name: "PBKDF2" }, false, ["deriveKey"]);
- return yield window.crypto.subtle.deriveKey({
- name: "PBKDF2",
- salt: encoder.encode(seed),
- iterations: 100000,
- hash: "SHA-256",
- }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
+ //add the current item, with the first checked value or "N" if none are checked
+ state.push({
+ page: dist_engrid_ENGrid.getPageID(),
+ class: this.classes,
+ value: (_b = (_a = [...this.elements].find(el => el.checked)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "N" // First checked value or "N" if none
});
+ this.logger.log("storing checkbox state", state[state.length - 1]);
+ }
+ });
+ window.sessionStorage.setItem(`engrid_ShowHideRadioCheckboxesState`, JSON.stringify(state));
+ }
+ constructor(elements, classes) {
+ this.logger = new dist_logger_EngridLogger("ShowHideRadioCheckboxes", "black", "lightblue", "π");
+ this.elements = document.getElementsByName(elements);
+ this.classes = classes;
+ this.createDataAttributes();
+ this.hideAll();
+ this.storeSessionState();
+ for (let i = 0; i < this.elements.length; i++) {
+ let element = this.elements[i];
+ if (element.checked) {
+ this.show(element);
+ }
+ element.addEventListener("change", e => {
+ this.hideAll();
+ this.show(element);
+ this.storeSessionState();
+ });
}
- /*
- * Convert an ArrayBuffer to a base64 string
- */
- arrayBufferToBase64(buffer) {
- let binary = "";
- const bytes = new Uint8Array(buffer);
- const len = bytes.byteLength;
- for (let i = 0; i < len; i++) {
- binary += String.fromCharCode(bytes[i]);
- }
- return window.btoa(binary);
- }
- /*
- * Create an Array Buffer from a base64 string
- */
- base64ToArrayBuffer(base64) {
- const binary_string = window.atob(base64);
- const len = binary_string.length;
- const bytes = new Uint8Array(len);
- for (let i = 0; i < len; i++) {
- bytes[i] = binary_string.charCodeAt(i);
- }
- return bytes.buffer;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/cookie.js
+/**
+Example:
+import * as cookie from "./cookie";
+
+cookie.set('name', 'value');
+cookie.get('name'); // => 'value'
+cookie.remove('name');
+cookie.set('name', 'value', { expires: 7 }); // 7 Days cookie
+cookie.set('name', 'value', { expires: 7, path: '' }); // Set Path
+cookie.remove('name', { path: '' });
+ */
+function cookie_stringifyAttribute(name, value) {
+ if (!value) {
+ return "";
+ }
+ let stringified = "; " + name;
+ if (value === true) {
+ return stringified; // boolean attributes shouldn't have a value
+ }
+ return stringified + "=" + value;
+}
+function cookie_stringifyAttributes(attributes) {
+ if (typeof attributes.expires === "number") {
+ let expires = new Date();
+ expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e5);
+ attributes.expires = expires;
+ }
+ return cookie_stringifyAttribute("Expires", attributes.expires ? attributes.expires.toUTCString() : "") + cookie_stringifyAttribute("Domain", attributes.domain) + cookie_stringifyAttribute("Path", attributes.path) + cookie_stringifyAttribute("Secure", attributes.secure) + cookie_stringifyAttribute("SameSite", attributes.sameSite);
+}
+function cookie_encode(name, value, attributes) {
+ return encodeURIComponent(name).replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent) // allowed special characters
+ .replace(/\(/g, "%28").replace(/\)/g, "%29") +
+ // replace opening and closing parens
+ "=" + encodeURIComponent(value)
+ // allowed special characters
+ .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent) + cookie_stringifyAttributes(attributes);
+}
+function cookie_parse(cookieString) {
+ let result = {};
+ let cookies = cookieString ? cookieString.split("; ") : [];
+ let rdecode = /(%[\dA-F]{2})+/gi;
+ for (let i = 0; i < cookies.length; i++) {
+ let parts = cookies[i].split("=");
+ let cookie = parts.slice(1).join("=");
+ if (cookie.charAt(0) === '"') {
+ cookie = cookie.slice(1, -1);
}
- /*
- * Derive a seed from the page URL
- */
- getSeed() {
- const url = new URL(window.location.href);
- return url.origin + url.pathname + (url.searchParams.get("ea.tracking.id") ? `?ea.tracking.id=${url.searchParams.get("ea.tracking.id")}` : '');
+ try {
+ let name = parts[0].replace(rdecode, decodeURIComponent);
+ result[name] = cookie.replace(rdecode, decodeURIComponent);
+ } catch (e) {
+ // ignore cookies with invalid name/value encoding
}
+ }
+ return result;
+}
+function cookie_getAll() {
+ return cookie_parse(document.cookie);
+}
+function cookie_get(name) {
+ return cookie_getAll()[name];
+}
+function cookie_set(name, value, attributes) {
+ document.cookie = cookie_encode(name, value, Object.assign({
+ path: "/"
+ }, attributes));
}
+function cookie_remove(name, attributes) {
+ cookie_set(name, "", Object.assign(Object.assign({}, attributes), {
+ expires: -1
+ }));
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/translate-fields.js
+// Component to translate fields based on the country selected
+// It will also adapt the state field to the country selected
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/preferred-payment-method.js
-class PreferredPaymentMethod {
- constructor() {
- var _a;
- this.logger = new logger_EngridLogger("PreferredPaymentMethod", "#ffffff", "#1f2933", "βοΈ");
- this.availabilityTimeoutMs = 4000;
- this.cleanupHandlers = [];
- this.selectionFinalized = false;
- this.listenersAttached = false;
- this.config = this.resolveConfig();
- this.preferredFieldName = ((_a = this.config.preferredPaymentMethodField) === null || _a === void 0 ? void 0 : _a.trim()) || "";
- if (!this.shouldRun()) {
- return;
+class translate_fields_TranslateFields {
+ constructor() {
+ this.countryToStateFields = {
+ "supporter.country": "supporter.region",
+ "transaction.shipcountry": "transaction.shipregion",
+ "supporter.billingCountry": "supporter.billingRegion",
+ "transaction.infcountry": "transaction.infreg"
+ };
+ this.countriesSelect = document.querySelectorAll('select[name="supporter.country"], select[name="transaction.shipcountry"], select[name="supporter.billingCountry"], select[name="transaction.infcountry"]');
+ let options = "EngridTranslate" in window ? window.EngridTranslate : {};
+ this.options = translate_options_TranslateOptionsDefaults;
+ // Don't run this for US-only forms.
+ if (document.querySelector(".en__component--formblock.us-only-form .en__field--country")) {
+ return;
+ }
+ if (options) {
+ for (let key in options) {
+ this.options[key] = this.options[key] ? [...this.options[key], ...options[key]] : options[key];
+ }
+ }
+ //Storing these values on load so we can set them back after the translation/swap.
+ let countryAndStateValuesOnLoad = {};
+ if (this.countriesSelect && this.countriesSelect.length > 0) {
+ this.countriesSelect.forEach(select => {
+ select.addEventListener("change", this.translateFields.bind(this, select.name));
+ if (select.value) {
+ countryAndStateValuesOnLoad[select.name] = select.value;
}
- this.attachGiveBySelectListeners();
- const candidates = this.buildCandidateList();
- if (candidates.length === 0) {
- this.logger.log("No payment methods to evaluate. Skipping.");
- return;
+ const stateField = document.querySelector(`select[name="${this.countryToStateFields[select.name]}"]`);
+ if (stateField) {
+ stateField.addEventListener("change", this.rememberState.bind(this, select.name));
+ if (stateField.value) {
+ countryAndStateValuesOnLoad[stateField.name] = stateField.value;
+ }
}
- this.logger.log(`Evaluating preferred payment methods in order: ${candidates.join(", ")}`);
- this.tryCandidateAtIndex(0, candidates);
+ });
+ this.translateFields("supporter.country");
+ //dont set these back if submission failed. EN / cookie will handle it.
+ const submissionFailed = !!(dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
+ if (!submissionFailed) {
+ for (let field in countryAndStateValuesOnLoad) {
+ dist_engrid_ENGrid.setFieldValue(field, countryAndStateValuesOnLoad[field], false);
+ }
+ }
}
- shouldRun() {
- if (engrid_ENGrid.getPageType() !== "DONATION") {
- this.logger.log("Not a donation page. Skipping preferred payment selection.");
- return false;
+ }
+ translateFields(countryName = "supporter.country") {
+ this.resetTranslatedFields();
+ const countryValue = dist_engrid_ENGrid.getFieldValue(countryName);
+ // Translate the State Field
+ this.setStateField(countryValue, this.countryToStateFields[countryName]);
+ if (countryName === "supporter.country") {
+ if (countryValue in this.options) {
+ this.options[countryValue].forEach(field => {
+ // console.log(field);
+ this.translateField(field.field, field.translation);
+ });
+ }
+ // Translate the "To:"
+ const recipient_block = document.querySelectorAll(".recipient-block");
+ if (!!recipient_block.length) {
+ switch (countryValue) {
+ case "FR":
+ case "FRA":
+ case "France":
+ recipient_block.forEach(elem => elem.innerHTML = "Γ:");
+ break;
+ case "DE":
+ case "DEU":
+ case "Germany":
+ recipient_block.forEach(elem => elem.innerHTML = "Zu:");
+ break;
+ case "NL":
+ case "NLD":
+ case "Netherlands":
+ recipient_block.forEach(elem => elem.innerHTML = "Aan:");
+ break;
}
- // If there's a "payment" URL parameter, we can proceed
- if (engrid_ENGrid.getUrlParameter("payment")) {
- return true;
+ }
+ }
+ }
+ translateField(name, translation) {
+ const field = document.querySelector(`[name="${name}"]`);
+ if (field) {
+ const fieldWrapper = field.closest(".en__field");
+ if (fieldWrapper) {
+ const fieldLabel = fieldWrapper.querySelector(".en__field__label");
+ // Check if there's the simple country select class
+ const simplecountriesSelect = fieldLabel.querySelector(".engrid-simple-country");
+ let simplecountriesSelectClone = simplecountriesSelect ? simplecountriesSelect.cloneNode(true) : null;
+ if (field instanceof HTMLInputElement && field.placeholder != "") {
+ if (!fieldLabel || fieldLabel.innerHTML == field.placeholder) {
+ field.dataset.original = field.placeholder;
+ field.placeholder = translation;
+ }
}
- if (!this.getGiveBySelectInputs().length) {
- this.logger.log("No give-by-select inputs found. Skipping.");
- return false;
+ if (fieldLabel) {
+ fieldLabel.dataset.original = fieldLabel.innerHTML;
+ fieldLabel.innerHTML = translation;
+ if (simplecountriesSelectClone) {
+ fieldLabel.appendChild(simplecountriesSelectClone);
+ }
}
- const config = engrid_ENGrid.getOption("PreferredPaymentMethod") || false;
- if (config === false) {
- this.logger.log("PreferredPaymentMethod option disabled.");
- return false;
+ }
+ }
+ }
+ resetTranslatedFields() {
+ const fields = document.querySelectorAll("[data-original]");
+ fields.forEach(field => {
+ if (field instanceof HTMLInputElement && field.dataset.original) {
+ field.placeholder = field.dataset.original;
+ } else {
+ // Check if there's the simple country select class
+ const simplecountriesSelect = field.querySelector(".engrid-simple-country");
+ let simplecountriesSelectClone = simplecountriesSelect ? simplecountriesSelect.cloneNode(true) : null;
+ field.innerHTML = field.dataset.original;
+ if (simplecountriesSelectClone) {
+ field.appendChild(simplecountriesSelectClone);
}
- return true;
+ }
+ field.removeAttribute("data-original");
+ });
+ }
+ setStateField(country, state) {
+ switch (country) {
+ case "ES":
+ case "ESP":
+ case "Spain":
+ this.setStateValues(state, "Provincia", null);
+ break;
+ case "BR":
+ case "BRA":
+ case "Brazil":
+ this.setStateValues(state, "Estado", null);
+ break;
+ case "FR":
+ case "FRA":
+ case "France":
+ this.setStateValues(state, "RΓ©gion", null);
+ break;
+ case "GB":
+ case "GBR":
+ case "United Kingdom":
+ this.setStateValues(state, "State/Region", null);
+ break;
+ case "DE":
+ case "DEU":
+ case "Germany":
+ this.setStateValues(state, "Bundesland", null);
+ break;
+ case "NL":
+ case "NLD":
+ case "Netherlands":
+ this.setStateValues(state, "Provincie", null);
+ break;
+ case "AU":
+ case "AUS":
+ this.setStateValues(state, "Province / State", [{
+ label: "Select",
+ value: ""
+ }, {
+ label: "New South Wales",
+ value: "NSW"
+ }, {
+ label: "Victoria",
+ value: "VIC"
+ }, {
+ label: "Queensland",
+ value: "QLD"
+ }, {
+ label: "South Australia",
+ value: "SA"
+ }, {
+ label: "Western Australia",
+ value: "WA"
+ }, {
+ label: "Tasmania",
+ value: "TAS"
+ }, {
+ label: "Northern Territory",
+ value: "NT"
+ }, {
+ label: "Australian Capital Territory",
+ value: "ACT"
+ }]);
+ break;
+ case "Australia":
+ this.setStateValues(state, "Province / State", [{
+ label: "Select",
+ value: ""
+ }, {
+ label: "New South Wales",
+ value: "New South Wales"
+ }, {
+ label: "Victoria",
+ value: "Victoria"
+ }, {
+ label: "Queensland",
+ value: "Queensland"
+ }, {
+ label: "South Australia",
+ value: "South Australia"
+ }, {
+ label: "Western Australia",
+ value: "Western Australia"
+ }, {
+ label: "Tasmania",
+ value: "Tasmania"
+ }, {
+ label: "Northern Territory",
+ value: "Northern Territory"
+ }, {
+ label: "Australian Capital Territory",
+ value: "Australian Capital Territory"
+ }]);
+ break;
+ case "US":
+ case "USA":
+ this.setStateValues(state, "State", [{
+ label: "Select State",
+ value: ""
+ }, {
+ label: "Alabama",
+ value: "AL"
+ }, {
+ label: "Alaska",
+ value: "AK"
+ }, {
+ label: "Arizona",
+ value: "AZ"
+ }, {
+ label: "Arkansas",
+ value: "AR"
+ }, {
+ label: "California",
+ value: "CA"
+ }, {
+ label: "Colorado",
+ value: "CO"
+ }, {
+ label: "Connecticut",
+ value: "CT"
+ }, {
+ label: "Delaware",
+ value: "DE"
+ }, {
+ label: "District of Columbia",
+ value: "DC"
+ }, {
+ label: "Florida",
+ value: "FL"
+ }, {
+ label: "Georgia",
+ value: "GA"
+ }, {
+ label: "Hawaii",
+ value: "HI"
+ }, {
+ label: "Idaho",
+ value: "ID"
+ }, {
+ label: "Illinois",
+ value: "IL"
+ }, {
+ label: "Indiana",
+ value: "IN"
+ }, {
+ label: "Iowa",
+ value: "IA"
+ }, {
+ label: "Kansas",
+ value: "KS"
+ }, {
+ label: "Kentucky",
+ value: "KY"
+ }, {
+ label: "Louisiana",
+ value: "LA"
+ }, {
+ label: "Maine",
+ value: "ME"
+ }, {
+ label: "Maryland",
+ value: "MD"
+ }, {
+ label: "Massachusetts",
+ value: "MA"
+ }, {
+ label: "Michigan",
+ value: "MI"
+ }, {
+ label: "Minnesota",
+ value: "MN"
+ }, {
+ label: "Mississippi",
+ value: "MS"
+ }, {
+ label: "Missouri",
+ value: "MO"
+ }, {
+ label: "Montana",
+ value: "MT"
+ }, {
+ label: "Nebraska",
+ value: "NE"
+ }, {
+ label: "Nevada",
+ value: "NV"
+ }, {
+ label: "New Hampshire",
+ value: "NH"
+ }, {
+ label: "New Jersey",
+ value: "NJ"
+ }, {
+ label: "New Mexico",
+ value: "NM"
+ }, {
+ label: "New York",
+ value: "NY"
+ }, {
+ label: "North Carolina",
+ value: "NC"
+ }, {
+ label: "North Dakota",
+ value: "ND"
+ }, {
+ label: "Ohio",
+ value: "OH"
+ }, {
+ label: "Oklahoma",
+ value: "OK"
+ }, {
+ label: "Oregon",
+ value: "OR"
+ }, {
+ label: "Pennsylvania",
+ value: "PA"
+ }, {
+ label: "Rhode Island",
+ value: "RI"
+ }, {
+ label: "South Carolina",
+ value: "SC"
+ }, {
+ label: "South Dakota",
+ value: "SD"
+ }, {
+ label: "Tennessee",
+ value: "TN"
+ }, {
+ label: "Texas",
+ value: "TX"
+ }, {
+ label: "Utah",
+ value: "UT"
+ }, {
+ label: "Vermont",
+ value: "VT"
+ }, {
+ label: "Virginia",
+ value: "VA"
+ }, {
+ label: "Washington",
+ value: "WA"
+ }, {
+ label: "West Virginia",
+ value: "WV"
+ }, {
+ label: "Wisconsin",
+ value: "WI"
+ }, {
+ label: "Wyoming",
+ value: "WY"
+ }, {
+ label: "── US Territories ──",
+ value: "",
+ disabled: true
+ }, {
+ label: "American Samoa",
+ value: "AS"
+ }, {
+ label: "Guam",
+ value: "GU"
+ }, {
+ label: "Northern Mariana Islands",
+ value: "MP"
+ }, {
+ label: "Puerto Rico",
+ value: "PR"
+ }, {
+ label: "US Minor Outlying Islands",
+ value: "UM"
+ }, {
+ label: "Virgin Islands",
+ value: "VI"
+ }, {
+ label: "── Armed Forces ──",
+ value: "",
+ disabled: true
+ }, {
+ label: "Armed Forces Americas",
+ value: "AA"
+ }, {
+ label: "Armed Forces Africa",
+ value: "AE"
+ }, {
+ label: "Armed Forces Canada",
+ value: "AE"
+ }, {
+ label: "Armed Forces Europe",
+ value: "AE"
+ }, {
+ label: "Armed Forces Middle East",
+ value: "AE"
+ }, {
+ label: "Armed Forces Pacific",
+ value: "AP"
+ }]);
+ break;
+ case "United States":
+ this.setStateValues(state, "State", [{
+ label: "Select State",
+ value: ""
+ }, {
+ label: "Alabama",
+ value: "Alabama"
+ }, {
+ label: "Alaska",
+ value: "Alaska"
+ }, {
+ label: "Arizona",
+ value: "Arizona"
+ }, {
+ label: "Arkansas",
+ value: "Arkansas"
+ }, {
+ label: "California",
+ value: "California"
+ }, {
+ label: "Colorado",
+ value: "Colorado"
+ }, {
+ label: "Connecticut",
+ value: "Connecticut"
+ }, {
+ label: "Delaware",
+ value: "Delaware"
+ }, {
+ label: "District of Columbia",
+ value: "District of Columbia"
+ }, {
+ label: "Florida",
+ value: "Florida"
+ }, {
+ label: "Georgia",
+ value: "Georgia"
+ }, {
+ label: "Hawaii",
+ value: "Hawaii"
+ }, {
+ label: "Idaho",
+ value: "Idaho"
+ }, {
+ label: "Illinois",
+ value: "Illinois"
+ }, {
+ label: "Indiana",
+ value: "Indiana"
+ }, {
+ label: "Iowa",
+ value: "Iowa"
+ }, {
+ label: "Kansas",
+ value: "Kansas"
+ }, {
+ label: "Kentucky",
+ value: "Kentucky"
+ }, {
+ label: "Louisiana",
+ value: "Louisiana"
+ }, {
+ label: "Maine",
+ value: "Maine"
+ }, {
+ label: "Maryland",
+ value: "Maryland"
+ }, {
+ label: "Massachusetts",
+ value: "Massachusetts"
+ }, {
+ label: "Michigan",
+ value: "Michigan"
+ }, {
+ label: "Minnesota",
+ value: "Minnesota"
+ }, {
+ label: "Mississippi",
+ value: "Mississippi"
+ }, {
+ label: "Missouri",
+ value: "Missouri"
+ }, {
+ label: "Montana",
+ value: "Montana"
+ }, {
+ label: "Nebraska",
+ value: "Nebraska"
+ }, {
+ label: "Nevada",
+ value: "Nevada"
+ }, {
+ label: "New Hampshire",
+ value: "New Hampshire"
+ }, {
+ label: "New Jersey",
+ value: "New Jersey"
+ }, {
+ label: "New Mexico",
+ value: "New Mexico"
+ }, {
+ label: "New York",
+ value: "New York"
+ }, {
+ label: "North Carolina",
+ value: "North Carolina"
+ }, {
+ label: "North Dakota",
+ value: "North Dakota"
+ }, {
+ label: "Ohio",
+ value: "Ohio"
+ }, {
+ label: "Oklahoma",
+ value: "Oklahoma"
+ }, {
+ label: "Oregon",
+ value: "Oregon"
+ }, {
+ label: "Pennsylvania",
+ value: "Pennsylvania"
+ }, {
+ label: "Rhode Island",
+ value: "Rhode Island"
+ }, {
+ label: "South Carolina",
+ value: "South Carolina"
+ }, {
+ label: "South Dakota",
+ value: "South Dakota"
+ }, {
+ label: "Tennessee",
+ value: "Tennessee"
+ }, {
+ label: "Texas",
+ value: "Texas"
+ }, {
+ label: "Utah",
+ value: "Utah"
+ }, {
+ label: "Vermont",
+ value: "Vermont"
+ }, {
+ label: "Virginia",
+ value: "Virginia"
+ }, {
+ label: "Washington",
+ value: "Washington"
+ }, {
+ label: "West Virginia",
+ value: "West Virginia"
+ }, {
+ label: "Wisconsin",
+ value: "Wisconsin"
+ }, {
+ label: "Wyoming",
+ value: "Wyoming"
+ }, {
+ label: "── US Territories ──",
+ value: "",
+ disabled: true
+ }, {
+ label: "American Samoa",
+ value: "American Samoa"
+ }, {
+ label: "Guam",
+ value: "Guam"
+ }, {
+ label: "Northern Mariana Islands",
+ value: "Northern Mariana Islands"
+ }, {
+ label: "Puerto Rico",
+ value: "Puerto Rico"
+ }, {
+ label: "US Minor Outlying Islands",
+ value: "US Minor Outlying Islands"
+ }, {
+ label: "Virgin Islands",
+ value: "Virgin Islands"
+ }, {
+ label: "── Armed Forces ──",
+ value: "",
+ disabled: true
+ }, {
+ label: "Armed Forces Americas",
+ value: "Armed Forces Americas"
+ }, {
+ label: "Armed Forces Africa",
+ value: "Armed Forces Africa"
+ }, {
+ label: "Armed Forces Canada",
+ value: "Armed Forces Canada"
+ }, {
+ label: "Armed Forces Europe",
+ value: "Armed Forces Europe"
+ }, {
+ label: "Armed Forces Middle East",
+ value: "Armed Forces Middle East"
+ }, {
+ label: "Armed Forces Pacific",
+ value: "Armed Forces Pacific"
+ }]);
+ break;
+ case "CA":
+ case "CAN":
+ this.setStateValues(state, "Province / Territory", [{
+ label: "Select",
+ value: ""
+ }, {
+ label: "Alberta",
+ value: "AB"
+ }, {
+ label: "British Columbia",
+ value: "BC"
+ }, {
+ label: "Manitoba",
+ value: "MB"
+ }, {
+ label: "New Brunswick",
+ value: "NB"
+ }, {
+ label: "Newfoundland and Labrador",
+ value: "NL"
+ }, {
+ label: "Northwest Territories",
+ value: "NT"
+ }, {
+ label: "Nova Scotia",
+ value: "NS"
+ }, {
+ label: "Nunavut",
+ value: "NU"
+ }, {
+ label: "Ontario",
+ value: "ON"
+ }, {
+ label: "Prince Edward Island",
+ value: "PE"
+ }, {
+ label: "Quebec",
+ value: "QC"
+ }, {
+ label: "Saskatchewan",
+ value: "SK"
+ }, {
+ label: "Yukon",
+ value: "YT"
+ }]);
+ break;
+ case "Canada":
+ this.setStateValues(state, "Province / Territory", [{
+ label: "Select",
+ value: ""
+ }, {
+ label: "Alberta",
+ value: "Alberta"
+ }, {
+ label: "British Columbia",
+ value: "British Columbia"
+ }, {
+ label: "Manitoba",
+ value: "Manitoba"
+ }, {
+ label: "New Brunswick",
+ value: "New Brunswick"
+ }, {
+ label: "Newfoundland and Labrador",
+ value: "Newfoundland and Labrador"
+ }, {
+ label: "Northwest Territories",
+ value: "Northwest Territories"
+ }, {
+ label: "Nova Scotia",
+ value: "Nova Scotia"
+ }, {
+ label: "Nunavut",
+ value: "Nunavut"
+ }, {
+ label: "Ontario",
+ value: "Ontario"
+ }, {
+ label: "Prince Edward Island",
+ value: "Prince Edward Island"
+ }, {
+ label: "Quebec",
+ value: "Quebec"
+ }, {
+ label: "Saskatchewan",
+ value: "Saskatchewan"
+ }, {
+ label: "Yukon",
+ value: "Yukon"
+ }]);
+ break;
+ case "MX":
+ case "MEX":
+ this.setStateValues(state, "Estado", [{
+ label: "Seleccione Estado",
+ value: ""
+ }, {
+ label: "Aguascalientes",
+ value: "AGU"
+ }, {
+ label: "Baja California",
+ value: "BCN"
+ }, {
+ label: "Baja California Sur",
+ value: "BCS"
+ }, {
+ label: "Campeche",
+ value: "CAM"
+ }, {
+ label: "Chiapas",
+ value: "CHP"
+ }, {
+ label: "Ciudad de Mexico",
+ value: "CMX"
+ }, {
+ label: "Chihuahua",
+ value: "CHH"
+ }, {
+ label: "Coahuila",
+ value: "COA"
+ }, {
+ label: "Colima",
+ value: "COL"
+ }, {
+ label: "Durango",
+ value: "DUR"
+ }, {
+ label: "Guanajuato",
+ value: "GUA"
+ }, {
+ label: "Guerrero",
+ value: "GRO"
+ }, {
+ label: "Hidalgo",
+ value: "HID"
+ }, {
+ label: "Jalisco",
+ value: "JAL"
+ }, {
+ label: "Michoacan",
+ value: "MIC"
+ }, {
+ label: "Morelos",
+ value: "MOR"
+ }, {
+ label: "Nayarit",
+ value: "NAY"
+ }, {
+ label: "Nuevo Leon",
+ value: "NLE"
+ }, {
+ label: "Oaxaca",
+ value: "OAX"
+ }, {
+ label: "Puebla",
+ value: "PUE"
+ }, {
+ label: "Queretaro",
+ value: "QUE"
+ }, {
+ label: "Quintana Roo",
+ value: "ROO"
+ }, {
+ label: "San Luis Potosi",
+ value: "SLP"
+ }, {
+ label: "Sinaloa",
+ value: "SIN"
+ }, {
+ label: "Sonora",
+ value: "SON"
+ }, {
+ label: "Tabasco",
+ value: "TAB"
+ }, {
+ label: "Tamaulipas",
+ value: "TAM"
+ }, {
+ label: "Tlaxcala",
+ value: "TLA"
+ }, {
+ label: "Veracruz",
+ value: "VER"
+ }, {
+ label: "Yucatan",
+ value: "YUC"
+ }, {
+ label: "Zacatecas",
+ value: "ZAC"
+ }]);
+ break;
+ case "Mexico":
+ this.setStateValues(state, "Estado", [{
+ label: "Seleccione Estado",
+ value: ""
+ }, {
+ label: "Aguascalientes",
+ value: "Aguascalientes"
+ }, {
+ label: "Baja California",
+ value: "Baja California"
+ }, {
+ label: "Baja California Sur",
+ value: "Baja California Sur"
+ }, {
+ label: "Campeche",
+ value: "Campeche"
+ }, {
+ label: "Chiapas",
+ value: "Chiapas"
+ }, {
+ label: "Ciudad de Mexico",
+ value: "Ciudad de Mexico"
+ }, {
+ label: "Chihuahua",
+ value: "Chihuahua"
+ }, {
+ label: "Coahuila",
+ value: "Coahuila"
+ }, {
+ label: "Colima",
+ value: "Colima"
+ }, {
+ label: "Durango",
+ value: "Durango"
+ }, {
+ label: "Guanajuato",
+ value: "Guanajuato"
+ }, {
+ label: "Guerrero",
+ value: "Guerrero"
+ }, {
+ label: "Hidalgo",
+ value: "Hidalgo"
+ }, {
+ label: "Jalisco",
+ value: "Jalisco"
+ }, {
+ label: "Michoacan",
+ value: "Michoacan"
+ }, {
+ label: "Morelos",
+ value: "Morelos"
+ }, {
+ label: "Nayarit",
+ value: "Nayarit"
+ }, {
+ label: "Nuevo Leon",
+ value: "Nuevo Leon"
+ }, {
+ label: "Oaxaca",
+ value: "Oaxaca"
+ }, {
+ label: "Puebla",
+ value: "Puebla"
+ }, {
+ label: "Queretaro",
+ value: "Queretaro"
+ }, {
+ label: "Quintana Roo",
+ value: "Quintana Roo"
+ }, {
+ label: "San Luis Potosi",
+ value: "San Luis Potosi"
+ }, {
+ label: "Sinaloa",
+ value: "Sinaloa"
+ }, {
+ label: "Sonora",
+ value: "Sonora"
+ }, {
+ label: "Tabasco",
+ value: "Tabasco"
+ }, {
+ label: "Tamaulipas",
+ value: "Tamaulipas"
+ }, {
+ label: "Tlaxcala",
+ value: "Tlaxcala"
+ }, {
+ label: "Veracruz",
+ value: "Veracruz"
+ }, {
+ label: "Yucatan",
+ value: "Yucatan"
+ }, {
+ label: "Zacatecas",
+ value: "Zacatecas"
+ }]);
+ break;
+ default:
+ this.setStateValues(state, "Province / State", null);
+ break;
}
- resolveConfig() {
- const option = engrid_ENGrid.getOption("PreferredPaymentMethod") || false;
- if (option && typeof option === "object") {
- const preferredPaymentMethodField = option.preferredPaymentMethodField || "";
- const defaultPaymentMethod = Array.isArray(option.defaultPaymentMethod)
- ? option.defaultPaymentMethod.filter((item) => !!item)
- : [];
- return {
- preferredPaymentMethodField,
- defaultPaymentMethod: defaultPaymentMethod.length > 0 ? defaultPaymentMethod : ["card"],
- };
+ }
+ setStateValues(state, label, values) {
+ const stateField = dist_engrid_ENGrid.getField(state);
+ const stateWrapper = stateField ? stateField.closest(".en__field") : null;
+ if (stateWrapper) {
+ const stateLabel = stateWrapper.querySelector(".en__field__label");
+ const elementWrapper = stateWrapper.querySelector(".en__field__element");
+ if (stateLabel) {
+ stateLabel.innerHTML = label;
+ }
+ if (elementWrapper) {
+ const selectedState = cookie_get(`engrid-state-${state}`);
+ if (values === null || values === void 0 ? void 0 : values.length) {
+ const select = document.createElement("select");
+ select.name = state;
+ select.id = "en__field_" + state.toLowerCase().replace(".", "_");
+ select.classList.add("en__field__input");
+ select.classList.add("en__field__input--select");
+ select.autocomplete = "address-level1";
+ let valueSelected = false;
+ values.forEach(value => {
+ const option = document.createElement("option");
+ option.value = value.value;
+ option.innerHTML = value.label;
+ if (selectedState === value.value && !valueSelected) {
+ option.selected = true;
+ valueSelected = true;
+ }
+ if (value.disabled) {
+ option.disabled = true;
+ }
+ select.appendChild(option);
+ });
+ elementWrapper.innerHTML = "";
+ elementWrapper.appendChild(select);
+ select.addEventListener("change", this.rememberState.bind(this, state));
+ select.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ } else {
+ elementWrapper.innerHTML = "";
+ const input = document.createElement("input");
+ input.type = "text";
+ input.name = state;
+ input.placeholder = label;
+ input.id = "en__field_" + state.toLowerCase().replace(".", "_");
+ input.classList.add("en__field__input");
+ input.classList.add("en__field__input--text");
+ input.autocomplete = "address-level1";
+ if (selectedState) {
+ input.value = selectedState;
+ }
+ elementWrapper.appendChild(input);
+ input.addEventListener("change", this.rememberState.bind(this, state));
}
- return {
- preferredPaymentMethodField: "",
- defaultPaymentMethod: ["card"],
- };
+ }
}
- buildCandidateList() {
- const candidates = [];
- const seen = new Set();
- const pushCandidate = (value) => {
- if (!value)
- return;
- const normalized = this.normalizePaymentValue(value);
- if (!normalized || seen.has(normalized))
- return;
- seen.add(normalized);
- candidates.push(normalized);
- };
- pushCandidate(this.getFieldPreference());
- pushCandidate(this.getUrlPreference());
- this.config.defaultPaymentMethod.forEach(pushCandidate);
- return candidates;
+ }
+ rememberState(state) {
+ const stateField = dist_engrid_ENGrid.getField(state);
+ if (stateField) {
+ cookie_set(`engrid-state-${stateField.name}`, stateField.value, {
+ expires: 1,
+ sameSite: "none",
+ secure: true
+ });
}
- hasPreferredField() {
- if (!this.preferredFieldName)
- return false;
- const field = engrid_ENGrid.getField(this.preferredFieldName);
- return !!field;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/auto-country-select.js
+// This class works when the user has added ".simple_country_select" as a class in page builder for the Country select
+
+
+class auto_country_select_AutoCountrySelect {
+ constructor() {
+ this._countryEvent = country_Country.getInstance();
+ this.countryWrapper = document.querySelector(".simple_country_select");
+ this.countrySelect = this._countryEvent.countryField;
+ this.country = null;
+ const engridAutofill = cookie_get("engrid-autofill");
+ const submissionFailed = !!(dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
+ const hasIntlSupport = !!dist_engrid_ENGrid.checkNested(window.Intl, "DisplayNames");
+ // Only run if there's no engrid-autofill cookie && if it has Intl support && no country data in url
+ const locationDataInUrl = dist_engrid_ENGrid.getUrlParameter("supporter.country") || dist_engrid_ENGrid.getUrlParameter("supporter.region") || dist_engrid_ENGrid.getUrlParameter("ea.url.id") && !dist_engrid_ENGrid.getUrlParameter("forwarded");
+ // If fast form is active, then personal details have already been filled somehow and we should not override the country selection
+ // The client is also likely using WelcomeBack.
+ const fastFormActive = dist_engrid_ENGrid.getBodyData("hide-fast-address-details") || dist_engrid_ENGrid.getBodyData("hide-fast-personal-details");
+ if (!engridAutofill && !submissionFailed && hasIntlSupport && !locationDataInUrl && !fastFormActive) {
+ fetch(`https://${window.location.hostname}/cdn-cgi/trace`).then(res => res.text()).then(t => {
+ let data = t.replace(/[\r\n]+/g, '","').replace(/\=+/g, '":"');
+ data = '{"' + data.slice(0, data.lastIndexOf('","')) + '"}';
+ const jsondata = JSON.parse(data);
+ this.country = jsondata.loc;
+ this.init();
+ // console.log("Country:", this.country);
+ });
+ } else {
+ this.init();
}
- attachGiveBySelectListeners() {
- if (this.listenersAttached)
- return;
- if (!this.preferredFieldName)
- return;
- if (!this.hasPreferredField()) {
- this.logger.log(`Preferred payment field "${this.preferredFieldName}" not found. Field sync disabled.`);
- return;
- }
- const inputs = this.getGiveBySelectInputs();
- inputs.forEach((input) => {
- input.addEventListener("change", () => {
- if (input.checked) {
- this.syncPreferredField(input.value);
- }
- });
+ }
+ init() {
+ if (this.countrySelect) {
+ if (this.country) {
+ const countriesNames = new Intl.DisplayNames(["en"], {
+ type: "region"
});
- this.listenersAttached = true;
+ // We are setting the country by Name because the ISO code is not always the same. They have 2 and 3 letter codes.
+ this.setCountryByName(countriesNames.of(this.country), this.country);
+ }
}
- syncPreferredField(value) {
- if (!this.preferredFieldName)
- return;
- if (!this.hasPreferredField())
- return;
- engrid_ENGrid.setFieldValue(this.preferredFieldName, value, false, true);
+ }
+ setCountryByName(countryName, countryCode) {
+ if (this.countrySelect) {
+ let countrySelectOptions = this.countrySelect.options;
+ for (let i = 0; i < countrySelectOptions.length; i++) {
+ if (countrySelectOptions[i].innerHTML.toLowerCase() == countryName.toLowerCase() || countrySelectOptions[i].value.toLowerCase() == countryCode.toLowerCase()) {
+ this.countrySelect.selectedIndex = i;
+ break;
+ }
+ }
+ const event = new Event("change", {
+ bubbles: true
+ });
+ this.countrySelect.dispatchEvent(event);
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/skip-link.js
+// Javascript that adds an accessible "Skip Link" button after the opening that jumps to
+// the first or field in a "body-" section, or the first if none are found
+// in those sections
+// Depends on _engrid-skip-link.scss
+
+class skip_link_SkipToMainContentLink {
+ constructor() {
+ const firstTitleInEngridBody = document.querySelector("div[class*='body-'] title");
+ const firstH1InEngridBody = document.querySelector("div[class*='body-'] h1");
+ const firstTitle = document.querySelector("title");
+ const firstH1 = document.querySelector("h1");
+ if (firstTitleInEngridBody && firstTitleInEngridBody.parentElement) {
+ firstTitleInEngridBody.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
+ } else if (firstH1InEngridBody && firstH1InEngridBody.parentElement) {
+ firstH1InEngridBody.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
+ } else if (firstTitle && firstTitle.parentElement) {
+ firstTitle.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
+ } else if (firstH1 && firstH1.parentElement) {
+ firstH1.parentElement.id = "skip-link";
+ this.insertSkipLinkSpan();
+ } else {
+ if (dist_engrid_ENGrid.debug) console.log("This page contains no or and a 'Skip to main content' link was not added");
+ }
+ }
+ insertSkipLinkSpan() {
+ document.body.insertAdjacentHTML("afterbegin", 'Skip to main content ');
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/src-defer.js
+// Build Notes: Add the vanilla Javascript version inline inside the page template right before
+// In the event the vanilla javascript is not inlined we should still process any assets with a data-src still defined on it. Plus we only process background video via this JS file as to not block the page with a large video file downloading.
+// // 4Site's simplified image lazy loader
+// var srcDefer = document.querySelectorAll("img[data-src]");
+// window.addEventListener('DOMContentLoaded', (event) => {
+// for (var i = 0; i < srcDefer.length; i++) {
+// let dataSrc = srcDefer[i].getAttribute("data-src");
+// if (dataSrc) {
+// srcDefer[i].setAttribute("decoding", "async"); // Gets image processing off the main working thread
+// srcDefer[i].setAttribute("loading", "lazy"); // Lets the browser determine when the asset should be downloaded
+// srcDefer[i].setAttribute("src", dataSrc); // Sets the src which will cause the browser to retrieve the asset
+// srcDefer[i].setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
+// srcDefer[i].removeAttribute("data-src"); // Removes the data-source
+// }
+// }
+// });
+class src_defer_SrcDefer {
+ constructor() {
+ // Find all images and videos with a data-src defined
+ this.imgSrcDefer = document.querySelectorAll("img[data-src]");
+ this.videoBackground = document.querySelectorAll("video");
+ this.videoBackgroundSource = document.querySelectorAll("video source");
+ // Process images
+ for (let i = 0; i < this.imgSrcDefer.length; i++) {
+ let img = this.imgSrcDefer[i];
+ if (img) {
+ img.setAttribute("decoding", "async"); // Gets image processing off the main working thread, and decodes the image asynchronously to reduce delay in presenting other content
+ img.setAttribute("loading", "lazy"); // Lets the browser determine when the asset should be downloaded using it's native lazy loading
+ let imgDataSrc = img.getAttribute("data-src");
+ if (imgDataSrc) {
+ img.setAttribute("src", imgDataSrc); // Sets the src which will cause the browser to retrieve the asset
+ }
+ img.setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
+ img.removeAttribute("data-src"); // Removes the data-source
+ }
}
- getFieldPreference() {
- if (!this.preferredFieldName) {
- return null;
- }
- const fieldValue = engrid_ENGrid.getFieldValue(this.preferredFieldName);
- if (!fieldValue) {
- this.logger.log(`Preferred payment field "${this.preferredFieldName}" is empty. Moving on.`);
- return null;
+ // Process video
+ for (let i = 0; i < this.videoBackground.length; i++) {
+ let video = this.videoBackground[i];
+ // Process one or more defined sources in the tag
+ this.videoBackgroundSource = video.querySelectorAll("source");
+ if (this.videoBackgroundSource) {
+ // loop through all the sources
+ for (let j = 0; j < this.videoBackgroundSource.length; j++) {
+ let videoSource = this.videoBackgroundSource[j];
+ if (videoSource) {
+ let videoBackgroundSourcedDataSrc = videoSource.getAttribute("data-src");
+ if (videoBackgroundSourcedDataSrc) {
+ videoSource.setAttribute("src", videoBackgroundSourcedDataSrc);
+ videoSource.setAttribute("data-engrid-data-src-processed", "true"); // Sets an attribute to mark that it has been processed by ENgrid
+ videoSource.removeAttribute("data-src"); // Removes the data-source
+ }
+ }
}
- this.logger.log(`Preferred payment from field "${this.preferredFieldName}" resolved to "${fieldValue}".`);
- return fieldValue;
- }
- getUrlPreference() {
- const urlValue = engrid_ENGrid.getUrlParameter("payment");
- if (typeof urlValue === "string" && urlValue.trim() !== "") {
- this.logger.log(`Preferred payment from URL parameter: "${urlValue}".`);
- return urlValue;
+ // To get the browser to request the video asset defined we need to remove the tag and re-add it
+ let videoBackgroundParent = video.parentNode; // Determine the parent of the tag
+ let copyOfVideoBackground = video; // Copy the tag
+ if (videoBackgroundParent && copyOfVideoBackground) {
+ videoBackgroundParent.replaceChild(copyOfVideoBackground, video); // Replace the with the copy of itself
+ // Update the video to auto play, mute, loop
+ video.muted = true; // Mute the video by default
+ video.controls = false; // Hide the browser controls
+ video.loop = true; // Loop the video
+ video.playsInline = true; // Encourage the user agent to display video content within the element's playback area
+ video.play(); // Plays the video
}
- return null;
+ }
}
- tryCandidateAtIndex(index, candidates) {
- if (this.selectionFinalized) {
- return;
- }
- if (index >= candidates.length) {
- this.logger.log("No preferred payment method was applied.");
- return;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/set-recurr-freq.js
+
+
+class set_recurr_freq_setRecurrFreq {
+ constructor() {
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this.linkClass = "setRecurrFreq-";
+ this.checkboxName = "engrid.recurrfreq";
+ // Watch the links that starts with linkClass
+ document.querySelectorAll(`a[class^="${this.linkClass}"]`).forEach(element => {
+ element.addEventListener("click", e => {
+ // Get the right class
+ const setRecurrFreqClass = element.className.split(" ").filter(linkClass => linkClass.startsWith(this.linkClass));
+ if (dist_engrid_ENGrid.debug) console.log(setRecurrFreqClass);
+ if (setRecurrFreqClass.length) {
+ e.preventDefault();
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrfreq", setRecurrFreqClass[0].substring(this.linkClass.length).toUpperCase());
+ this._frequency.load();
}
- const method = candidates[index];
- if (!this.paymentMethodExists(method)) {
- this.logger.log(`Payment method "${method}" not found. Skipping.`);
- this.tryCandidateAtIndex(index + 1, candidates);
- return;
+ });
+ });
+ const currentFrequency = dist_engrid_ENGrid.getFieldValue("transaction.recurrfreq").toUpperCase();
+ // Watch checkboxes with the name checkboxName
+ document.getElementsByName(this.checkboxName).forEach(element => {
+ // Set checked status per currently-set frequency
+ const frequency = element.value.toUpperCase();
+ if (frequency === currentFrequency) {
+ element.checked = true;
+ } else {
+ element.checked = false;
+ }
+ element.addEventListener("change", () => {
+ const frequency = element.value.toUpperCase();
+ if (element.checked) {
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrfreq", frequency);
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrpay", "Y");
+ this._frequency.load();
+ this._amount.setAmount(this._amount.amount, false);
+ } else if (frequency !== "ONETIME") {
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrfreq", "ONETIME");
+ dist_engrid_ENGrid.setFieldValue("transaction.recurrpay", "N");
+ this._frequency.load();
+ this._amount.setAmount(this._amount.amount, false);
}
- if (this.isPaymentMethodAvailable(method)) {
- this.logger.success(`Selecting available payment method "${method}".`);
- this.applySelection(method);
- return;
+ });
+ });
+ // Uncheck the checkbox when frequency != checkbox value
+ this._frequency.onFrequencyChange.subscribe(() => {
+ const currentFrequency = this._frequency.frequency.toUpperCase();
+ document.getElementsByName(this.checkboxName).forEach(element => {
+ const elementFrequency = element.value.toUpperCase();
+ if (element.checked && elementFrequency !== currentFrequency) {
+ element.checked = false;
+ } else if (!element.checked && elementFrequency === currentFrequency) {
+ element.checked = true;
}
- this.logger.log(`Payment method "${method}" exists but is not available yet. Waiting up to ${this.availabilityTimeoutMs}ms.`);
- this.waitForAvailability(method, () => {
- if (this.selectionFinalized)
- return;
- if (this.isPaymentMethodAvailable(method)) {
- this.logger.success(`Selecting payment method "${method}" once it became available.`);
- this.applySelection(method);
- }
- }, () => {
- if (this.selectionFinalized)
- return;
- this.logger.log(`Payment method "${method}" still unavailable after waiting. Trying next option.`);
- this.tryCandidateAtIndex(index + 1, candidates);
- });
+ });
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/page-background.js
+
+class page_background_PageBackground {
+ constructor() {
+ // @TODO: Change page-backgroundImage to page-background
+ this.pageBackground = document.querySelector(".page-backgroundImage");
+ this.mutationObserver = null;
+ this.logger = new dist_logger_EngridLogger("PageBackground", "lightblue", "darkblue", "πΌοΈ");
+ if (!this.pageBackground) {
+ this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");
+ return;
}
- waitForAvailability(method, onAvailable, onTimeout) {
- const observers = [];
- const cleanup = () => {
- observers.forEach((observer) => observer.disconnect());
- observers.length = 0;
- this.cleanupHandlers = this.cleanupHandlers.filter((fn) => fn !== cleanup);
- window.clearTimeout(timeoutId);
- };
- this.cleanupHandlers.push(cleanup);
- const checkAvailability = () => {
- if (this.selectionFinalized) {
- cleanup();
- return;
- }
- if (this.isPaymentMethodAvailable(method)) {
- cleanup();
- onAvailable();
- }
- };
- const fieldContainer = this.getGiveBySelectContainer() || document.body;
- const domObserver = new MutationObserver(() => checkAvailability());
- domObserver.observe(fieldContainer, {
- attributes: true,
- attributeFilter: ["class", "style"],
- childList: true,
- subtree: true,
+ this.initializeBackgroundImage();
+ this.setDataAttributes();
+ this.processAttributionPositioning();
+ this.setupMutationObserver();
+ }
+ /**
+ * Initialize background image by finding and setting CSS custom property
+ */
+ initializeBackgroundImage() {
+ if (!this.pageBackground) return;
+ const pageBackgroundImg = this.pageBackground.querySelector("img");
+ if (!pageBackgroundImg) {
+ this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");
+ return;
+ }
+ const dataSrc = pageBackgroundImg.getAttribute("data-src");
+ const src = pageBackgroundImg.src;
+ if (dataSrc) {
+ this.setBackgroundImageUrl(dataSrc, "data-src");
+ } else if (src) {
+ this.setBackgroundImageUrl(src, "src");
+ } else {
+ this.logger.log("A background image set in the page was found but without a data-src or src value, no action taken", pageBackgroundImg);
+ }
+ }
+ /**
+ * Set the background image URL as a CSS custom property
+ */
+ setBackgroundImageUrl(imageUrl, sourceType) {
+ if (!this.pageBackground || !imageUrl) return;
+ try {
+ const cssUrl = `url('${imageUrl}')`;
+ this.pageBackground.style.setProperty("--engrid__page-backgroundImage_url", cssUrl);
+ this.logger.log(`A background image set in the page was found with a ${sourceType} value, setting it as --engrid__page-backgroundImage_url`, imageUrl);
+ } catch (error) {
+ this.logger.error("Error setting background image URL:", error);
+ }
+ }
+ /**
+ * Processes attribution positioning for background images by moving positioning classes
+ * and data attributes from images to their parent column containers.
+ *
+ * This function handles two attribution patterns:
+ * 1. Class-based:
+ * 2. Data attribute-based:
+ *
+ * Examples:
+ *
+ * Class-based attribution:
+ *
+ * β Moves "attribution-bottomright" class to parent .en__component--column
+ *
+ * Data attribute-based attribution:
+ *
+ * β Converts to "attribution-top" class and moves to parent .en__component--column
+ *
+ * Supported positioning values:
+ * - center
+ * - top, topcenter (these result in the same positioning)
+ * - right, rightcenter (these result in the same positioning)
+ * - bottom, bottomcenter (these result in the same positioning)
+ * - left, leftcenter (these result in the same positioning)
+ * - topright
+ * - bottomright
+ * - bottomleft
+ * - topleft
+ */
+ processAttributionPositioning() {
+ if (!this.pageBackground) {
+ this.logger.log("No background section found for attribution positioning processing");
+ return;
+ }
+ this.logger.log("Processing attribution positioning for background section:", this.pageBackground);
+ // Define all supported attribution positioning classes
+ const allowedClasses = ["attribution-center", "attribution-bottom", "attribution-bottomcenter", "attribution-bottomright", "attribution-bottomleft", "attribution-top", "attribution-topcenter", "attribution-topright", "attribution-topleft", "attribution-left", "attribution-leftcenter", "attribution-right", "attribution-rightcenter"];
+ try {
+ // Find all images in the background section (after any DOM transformations)
+ const images = this.pageBackground.querySelectorAll("img");
+ this.logger.log("Found images in background section:", images.length);
+ images.forEach(img => {
+ this.processImageAttribution(img, allowedClasses);
+ });
+ } catch (error) {
+ this.logger.error("Error processing attribution positioning:", error);
+ }
+ }
+ /**
+ * Process attribution for a single image
+ */
+ processImageAttribution(img, allowedClasses) {
+ // Pattern 1: Check for class-based attribution positioning
+ // Example:
+ const matchedClass = allowedClasses.find(cls => img.classList.contains(cls));
+ // Pattern 2: Check for data attribute-based attribution positioning
+ // Example:
+ const dataPosition = img.getAttribute("data-background-position");
+ if (matchedClass) {
+ this.handleClassBasedAttribution(img, matchedClass);
+ } else if (dataPosition) {
+ this.handleDataAttributeAttribution(img, dataPosition);
+ }
+ }
+ /**
+ * Handle class-based attribution positioning
+ */
+ handleClassBasedAttribution(img, matchedClass) {
+ this.logger.log("Found attribution class on image:", matchedClass, img);
+ const parentDiv = img.closest(".en__component--column");
+ if (parentDiv) {
+ // Move the class from image to parent column
+ img.classList.remove(matchedClass);
+ parentDiv.classList.add(matchedClass);
+ this.logger.log("Moved attribution class from image to parent column:", matchedClass, parentDiv);
+ } else {
+ this.logger.log("No parent .en__component--column found for image:", img);
+ }
+ }
+ /**
+ * Handle data attribute-based attribution positioning
+ */
+ handleDataAttributeAttribution(img, dataPosition) {
+ // Convert data attribute value to attribution class format
+ const attributionClass = `attribution-${dataPosition}`;
+ this.logger.log("Found data-background-position on image:", dataPosition, "->", attributionClass, img);
+ const parentDiv = img.closest(".en__component--column");
+ if (parentDiv) {
+ // Remove data attribute from image and add class to parent column
+ img.removeAttribute("data-background-position");
+ parentDiv.classList.add(attributionClass);
+ this.logger.log("Moved data-background-position from image to parent column as class:", attributionClass, parentDiv);
+ } else {
+ this.logger.log("No parent .en__component--column found for image:", img);
+ }
+ }
+ setupMutationObserver() {
+ if (!this.pageBackground || !window.MutationObserver) {
+ if (!window.MutationObserver) {
+ this.logger.log("MutationObserver not supported in this browser");
+ }
+ return;
+ }
+ try {
+ this.mutationObserver = new MutationObserver(mutations => {
+ let shouldReprocess = false;
+ mutations.forEach(mutation => {
+ // Check if nodes were added or attributes changed
+ if (mutation.type === "childList" || mutation.type === "attributes") {
+ shouldReprocess = true;
+ }
});
- observers.push(domObserver);
- const attributeFilters = this.getAvailabilityAttributeFilters(method);
- if (attributeFilters.length > 0) {
- const attrObserver = new MutationObserver(() => checkAvailability());
- attrObserver.observe(document.body, {
- attributes: true,
- attributeFilter: attributeFilters,
- });
- observers.push(attrObserver);
+ if (shouldReprocess) {
+ this.logger.log("DOM changes detected in background section, reprocessing attribution classes");
+ // Use a small delay to ensure all changes are complete
+ setTimeout(() => {
+ this.processAttributionPositioning();
+ }, 100);
}
- const timeoutId = window.setTimeout(() => {
- cleanup();
- onTimeout();
- }, this.availabilityTimeoutMs);
+ });
+ // Start observing the background section
+ this.mutationObserver.observe(this.pageBackground, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ attributeFilter: ["class"]
+ });
+ this.logger.log("MutationObserver set up for background section");
+ } catch (error) {
+ this.logger.error("Error setting up MutationObserver:", error);
}
- applySelection(method) {
- if (this.selectionFinalized) {
- return;
- }
- const input = this.findPaymentInput(method);
- if (!input) {
- this.logger.log(`Unable to locate give-by-select input for "${method}" during selection.`);
- return;
+ }
+ // Public method to manually trigger reprocessing
+ reprocessAttributionPositioning() {
+ this.logger.log("Manually reprocessing attribution positioning");
+ this.processAttributionPositioning();
+ }
+ /**
+ * Clean up resources and observers
+ */
+ destroy() {
+ if (this.mutationObserver) {
+ this.mutationObserver.disconnect();
+ this.mutationObserver = null;
+ this.logger.log("MutationObserver disconnected");
+ }
+ }
+ setDataAttributes() {
+ if (this.hasVideoBackground()) {
+ return dist_engrid_ENGrid.setBodyData("page-background", "video");
+ }
+ if (this.hasImageBackground()) {
+ return dist_engrid_ENGrid.setBodyData("page-background", "image");
+ }
+ return dist_engrid_ENGrid.setBodyData("page-background", "empty");
+ }
+ hasVideoBackground() {
+ if (!this.pageBackground) {
+ return false;
+ }
+ return !!this.pageBackground.querySelector("video");
+ }
+ hasImageBackground() {
+ if (!this.pageBackground) {
+ return false;
+ }
+ return !this.hasVideoBackground() && !!this.pageBackground.querySelector("img");
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/neverbounce.js
+
+
+class neverbounce_NeverBounce {
+ constructor(apiKey, dateField = null, statusField = null, dateFormat) {
+ this.apiKey = apiKey;
+ this.dateField = dateField;
+ this.statusField = statusField;
+ this.dateFormat = dateFormat;
+ this.form = events_en_form_EnForm.getInstance();
+ this.emailField = null;
+ this.emailWrapper = document.querySelector(".en__field--emailAddress");
+ this.nbDate = null;
+ this.nbStatus = null;
+ this.logger = new dist_logger_EngridLogger("NeverBounce", "#039bc4", "#dfdfdf", "π§");
+ this.shouldRun = true;
+ this.nbLoaded = false;
+ this.bypassEmails = ["noaddress.ea"];
+ this.neverBounceTimeout = dist_engrid_ENGrid.getOption("NeverBounceTimeout") || 10000;
+ this.neverBounceTimeoutFunc = null;
+ const searchParams = new URLSearchParams(window.location.search);
+ if (searchParams.has("bypassemailvalidation")) {
+ this.logger.log("Bypass Email Validation Enabled - not running NeverBounce");
+ return;
+ }
+ this.emailField = document.getElementById("en__field_supporter_emailAddress");
+ window._NBSettings = {
+ apiKey: this.apiKey,
+ autoFieldHookup: false,
+ inputLatency: 1500,
+ displayPoweredBy: false,
+ loadingMessage: "Validating...",
+ softRejectMessage: "Invalid email",
+ acceptedMessage: "Email validated!",
+ feedback: false,
+ // Set NB timeout 1 second than our timeout. Ensures NB response will always be before our timeout if there is not a server error.
+ timeout: Math.floor((this.neverBounceTimeout - 1000) / 1000)
+ };
+ dist_engrid_ENGrid.loadJS("https://cdn.neverbounce.com/widget/dist/NeverBounce.js");
+ if (this.emailField) {
+ if (this.emailField.value) {
+ this.logger.log("E-mail Field Found");
+ this.shouldRun = false;
+ }
+ this.emailField.addEventListener("change", e => {
+ var _a;
+ if (!this.nbLoaded) {
+ this.shouldRun = true;
+ this.init();
+ if ((_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value) {
+ setTimeout(function () {
+ window._nb.fields.get(document.querySelector("[data-nb-id]"))[0].forceUpdate();
+ }, 100);
+ }
}
- if (!this.isPaymentMethodAvailable(method)) {
- this.logger.log(`Payment method "${method}" is not available to select.`);
- return;
+ });
+ window.setTimeout(() => {
+ if (this.emailField && this.emailField.value) {
+ this.logger.log("E-mail Filled Programatically");
+ this.shouldRun = false;
}
- input.checked = true;
- input.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
- engrid_ENGrid.setPaymentType(method);
- this.syncPreferredField(input.value);
- this.selectionFinalized = true;
- this.cleanupAllObservers();
+ this.init();
+ }, 1000);
}
- paymentMethodExists(method) {
- return !!this.findPaymentInput(method);
+ this.form.onValidate.subscribe(this.validate.bind(this));
+ }
+ init() {
+ if (!this.shouldRun) {
+ this.logger.log("Should Not Run");
+ return;
}
- isPaymentMethodAvailable(method) {
- const input = this.findPaymentInput(method);
- if (!input || input.disabled) {
- return false;
- }
- const container = this.getInputContainer(input);
- return container ? engrid_ENGrid.isVisible(container) : engrid_ENGrid.isVisible(input);
+ if (this.nbLoaded) {
+ this.logger.log("Already Loaded");
+ return;
}
- findPaymentInput(method) {
- const normalized = this.normalizePaymentValue(method);
- if (!normalized) {
- return null;
+ this.logger.log("Init Function");
+ if (this.dateField && document.getElementsByName(this.dateField).length) this.nbDate = document.querySelector("[name='" + this.dateField + "']");
+ if (this.statusField && document.getElementsByName(this.statusField).length) this.nbStatus = document.querySelector("[name='" + this.statusField + "']");
+ if (!this.emailField) {
+ this.logger.log("E-mail Field Not Found");
+ return;
+ }
+ this.wrap(this.emailField, document.createElement("div"));
+ const parentNode = this.emailField.parentNode;
+ parentNode.id = "nb-wrapper";
+ // Define HTML structure for a Custom NB Message and insert it after Email field
+ const nbCustomMessageHTML = document.createElement("div");
+ nbCustomMessageHTML.innerHTML = 'Enter a valid email.
';
+ this.insertAfter(nbCustomMessageHTML, this.emailField);
+ const NBClass = this;
+ document.body.addEventListener("nb:registered", function (event) {
+ const field = document.querySelector('[data-nb-id="' + event.detail.id + '"]');
+ field.addEventListener("nb:loading", function (e) {
+ dist_engrid_ENGrid.disableSubmit("Validating Your Email");
+ NBClass.setEmailStatus("loading");
+ NBClass.clearTimeout();
+ NBClass.neverBounceTimeoutFunc = setTimeout(() => {
+ NBClass.setEmailStatus("unknown");
+ if (NBClass.nbDate) {
+ NBClass.nbDate.value = dist_engrid_ENGrid.formatDate(new Date(), NBClass.dateFormat);
+ }
+ if (NBClass.nbStatus) {
+ NBClass.nbStatus.value = "unknown";
+ }
+ dist_engrid_ENGrid.enableSubmit();
+ window._nb.fields.unregisterListener(NBClass.emailField);
+ NBClass.nbLoaded = false;
+ NBClass.logger.log("NeverBounce Timeout Reached. Bypassing validation, setting unknown status and removing NB.");
+ }, NBClass.neverBounceTimeout);
+ });
+ // Never Bounce: Do work when input changes or when API responds with an error
+ field.addEventListener("nb:clear", function (e) {
+ if (!NBClass.nbLoaded) return;
+ NBClass.clearTimeout();
+ NBClass.setEmailStatus("clear");
+ dist_engrid_ENGrid.enableSubmit();
+ if (NBClass.nbDate) NBClass.nbDate.value = "";
+ if (NBClass.nbStatus) NBClass.nbStatus.value = "";
+ });
+ // Never Bounce: Do work when results have an input that does not look like an email (i.e. missing @ or no .com/.net/etc...)
+ field.addEventListener("nb:soft-result", function (e) {
+ if (!NBClass.nbLoaded) return;
+ NBClass.clearTimeout();
+ NBClass.setEmailStatus("soft-result");
+ if (NBClass.nbDate) NBClass.nbDate.value = "";
+ if (NBClass.nbStatus) NBClass.nbStatus.value = "";
+ dist_engrid_ENGrid.enableSubmit();
+ });
+ // Never Bounce: When results have been received
+ field.addEventListener("nb:result", function (e) {
+ if (!NBClass.nbLoaded) return;
+ NBClass.clearTimeout();
+ if (e.detail.result.is(window._nb.settings.getAcceptedStatusCodes())) {
+ NBClass.setEmailStatus("valid");
+ if (NBClass.nbDate) NBClass.nbDate.value = dist_engrid_ENGrid.formatDate(new Date(), NBClass.dateFormat);
+ if (NBClass.nbStatus) NBClass.nbStatus.value = e.detail.result.response.result;
+ } else {
+ NBClass.setEmailStatus("invalid");
+ if (NBClass.nbDate) NBClass.nbDate.value = "";
+ if (NBClass.nbStatus) NBClass.nbStatus.value = "";
}
- const inputs = this.getGiveBySelectInputs();
- return (Array.from(inputs).find((input) => input.value && this.normalizePaymentValue(input.value) === normalized) || null);
+ dist_engrid_ENGrid.enableSubmit();
+ });
+ });
+ // Never Bounce: Register field with the widget and broadcast nb:registration event
+ window._nb.fields.registerListener(NBClass.emailField, true);
+ this.nbLoaded = true;
+ }
+ clearStatus() {
+ if (!this.emailField) {
+ this.logger.log("E-mail Field Not Found");
+ return;
}
- getGiveBySelectInputs() {
- return document.getElementsByName("transaction.giveBySelect");
+ this.emailField.classList.remove("rm-error");
+ // Search page for the NB Wrapper div and set as variable
+ const nb_email_field_wrapper = document.getElementById("nb-wrapper");
+ // Search page for the NB Feedback div and set as variable
+ const nb_email_feedback_field = document.getElementById("nb-feedback");
+ nb_email_field_wrapper.className = "";
+ nb_email_feedback_field.className = "en__field__error nb-hidden";
+ nb_email_feedback_field.innerHTML = "";
+ this.emailWrapper.classList.remove("en__field--validationFailed");
+ }
+ deleteENFieldError() {
+ const errorField = document.querySelector(".en__field--emailAddress>div.en__field__error");
+ if (errorField) errorField.remove();
+ }
+ setEmailStatus(status) {
+ this.logger.log("Status:", status);
+ if (!this.emailField) {
+ this.logger.log("E-mail Field Not Found");
+ return;
}
- getGiveBySelectContainer() {
- return document.querySelector(".en__field--give-by-select, .give-by-select");
+ if (this.isBypassEmail()) {
+ this.logger.log("Bypass email detected. Skipping status update.");
+ return;
}
- getInputContainer(input) {
- return (input.closest(".en__field__item") ||
- input.closest(".en__field__element") ||
- input.parentElement);
+ // Search page for the NB Wrapper div and set as variable
+ const nb_email_field_wrapper = document.getElementById("nb-wrapper");
+ // Search page for the NB Feedback div and set as variable
+ let nb_email_feedback_field = document.getElementById("nb-feedback");
+ // classes to add or remove based on neverbounce results
+ const nb_email_field_wrapper_success = "nb-success";
+ const nb_email_field_wrapper_error = "nb-error";
+ const nb_email_feedback_hidden = "nb-hidden";
+ const nb_email_feedback_loading = "nb-loading";
+ const nb_email_field_error = "rm-error";
+ if (!nb_email_feedback_field) {
+ const nbWrapperDiv = nb_email_field_wrapper.querySelector("div");
+ if (nbWrapperDiv) nbWrapperDiv.innerHTML = 'Enter a valid email.
';
+ nb_email_feedback_field = document.getElementById("nb-feedback");
+ }
+ if (status == "valid") {
+ this.clearStatus();
+ } else {
+ nb_email_field_wrapper.classList.remove(nb_email_field_wrapper_success);
+ nb_email_field_wrapper.classList.add(nb_email_field_wrapper_error);
+ switch (status) {
+ case "required":
+ // special case status that we added ourselves -- doesn't come from NB
+ this.deleteENFieldError();
+ nb_email_feedback_field.innerHTML = "A valid email is required";
+ nb_email_feedback_field.classList.remove(nb_email_feedback_loading);
+ nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
+ this.emailField.classList.add(nb_email_field_error);
+ break;
+ case "soft-result":
+ if (this.emailField.value) {
+ this.deleteENFieldError();
+ nb_email_feedback_field.innerHTML = "Invalid email";
+ nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
+ this.emailField.classList.add(nb_email_field_error);
+ } else {
+ this.clearStatus();
+ }
+ break;
+ case "invalid":
+ this.deleteENFieldError();
+ nb_email_feedback_field.innerHTML = "Invalid email";
+ nb_email_feedback_field.classList.remove(nb_email_feedback_loading);
+ nb_email_feedback_field.classList.remove(nb_email_feedback_hidden);
+ this.emailField.classList.add(nb_email_field_error);
+ break;
+ case "loading":
+ case "clear":
+ default:
+ this.clearStatus();
+ break;
+ }
}
- findLabelForInput(input) {
- if (input.id) {
- const externalLabel = document.querySelector(`label[for="${input.id}"]`);
- if (externalLabel) {
- return externalLabel;
- }
- }
- return input.closest("label");
+ }
+ // Function to insert HTML after a DIV
+ insertAfter(el, referenceNode) {
+ var _a;
+ (_a = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(el, referenceNode.nextSibling);
+ }
+ // to Wrap HTML around a DIV
+ wrap(el, wrapper) {
+ var _a;
+ (_a = el.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, el);
+ wrapper.appendChild(el);
+ }
+ isBypassEmail() {
+ if (!this.emailField || !this.emailField.value) return false;
+ const email = this.emailField.value.toLowerCase();
+ return this.bypassEmails.some(bypassEmail => email.includes(bypassEmail.toLowerCase()));
+ }
+ validate() {
+ var _a;
+ if (!this.form.validate) return;
+ const nbResult = dist_engrid_ENGrid.getFieldValue("nb-result");
+ if (!this.emailField || !this.shouldRun || !this.nbLoaded || !nbResult) {
+ this.logger.log("validate(): Should Not Run. Returning true.");
+ return;
}
- normalizePaymentValue(value) {
- return value.trim().toLowerCase();
+ if (this.isBypassEmail()) {
+ this.logger.log("Bypass email detected. Skipping validation.");
+ return;
}
- getAvailabilityAttributeFilters(method) {
- const map = {
- stripedigitalwallet: [
- "data-engrid-payment-type-option-apple-pay",
- "data-engrid-payment-type-option-google-pay",
- ],
- paypaltouch: [
- "data-engrid-payment-type-option-paypal-one-touch",
- "data-engrid-payment-type-option-venmo",
- ],
- daf: ["data-engrid-payment-type-option-daf"],
- };
- return map[method] || [];
+ if (this.nbStatus) {
+ this.nbStatus.value = nbResult;
}
- cleanupAllObservers() {
- this.cleanupHandlers.forEach((cleanup) => cleanup());
- this.cleanupHandlers = [];
+ if (!["catchall", "unknown", "valid"].includes(nbResult)) {
+ this.setEmailStatus("required");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ this.logger.log("NB-Result:", dist_engrid_ENGrid.getFieldValue("nb-result"));
+ this.form.validate = false;
}
+ }
+ /**
+ * Clears the backup timeout function if it exists.
+ * @private
+ */
+ clearTimeout() {
+ if (this.neverBounceTimeoutFunc) {
+ clearTimeout(this.neverBounceTimeoutFunc);
+ this.neverBounceTimeoutFunc = null;
+ }
+ }
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/freshaddress.js
+// According to the FreshAddress documentation, you need to add the following code to your page:
+// jQuery library.
+//
+// FreshAddress client-side integration library
+//
+//
+// I know. jQuery. But it's not my fault. It's FreshAddress's fault.
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/version.js
-const AppVersion = "0.25.2";
-
-;// CONCATENATED MODULE: ./node_modules/@4site/engrid-scripts/dist/index.js
- // Runs first so it can change the DOM markup before any markup dependent code fires
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// Events
-
-// Version
-
-
-// EXTERNAL MODULE: ./node_modules/smoothscroll-polyfill/dist/smoothscroll.js
-var smoothscroll = __webpack_require__(1196);
-var smoothscroll_default = /*#__PURE__*/__webpack_require__.n(smoothscroll);
-;// CONCATENATED MODULE: ./src/scripts/donation-lightbox-form.js
-const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
-const donation_lightbox_form_tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
-if (isSafari) {
- window.__forceSmoothScrollPolyfill__ = true;
-}
-
-smoothscroll_default().polyfill();
-class DonationLightboxForm {
- constructor(DonationAmount, DonationFrequency, App) {
- if (!this.isIframe() || document.querySelector("body").dataset.engridSubtheme !== "multistep" && document.querySelector("body").dataset.engridSubtheme !== "one-step-lightbox") return;
- this.amount = DonationAmount;
- this.frequency = DonationFrequency;
- this.app = App;
- this.ipCountry = "";
- this.isDonation = ["donation", "premiumgift"].includes(window.pageJson.pageType);
- this.upsellSection = null;
- this.upsellSectionId = null;
- console.log("DonationLightboxForm: constructor");
- // Adjust Field Tooltip
- const fieldTooltip = document.querySelectorAll(".en__field__notice");
- if (fieldTooltip && donation_lightbox_form_tippy) {
- fieldTooltip.forEach(tooltip => {
- const fieldTooltipContent = tooltip.innerHTML;
- // Replace the tooltip content with an i icon
- tooltip.innerHTML = `
-
-
-
- `;
- // Move the tooltip block to the email field
- const parentField = tooltip.closest(".en__field").querySelector(".en__field__element");
- if (parentField) {
- parentField.appendChild(tooltip);
- }
- // Add the tooltip content to the tippy instance
- donation_lightbox_form_tippy(tooltip, {
- content: fieldTooltipContent,
- allowHTML: true,
- arrow: true,
- arrowType: "default",
- placement: "top",
- trigger: "click mouseenter focus",
- interactive: true
- });
- });
+class freshaddress_FreshAddress {
+ constructor() {
+ var _a;
+ this.form = events_en_form_EnForm.getInstance();
+ this.emailField = null;
+ this.emailWrapper = document.querySelector(".en__field--emailAddress");
+ this.faDate = null;
+ this.faStatus = null;
+ this.faMessage = null;
+ this.logger = new dist_logger_EngridLogger("FreshAddress", "#039bc4", "#dfdfdf", "π§");
+ this.shouldRun = true;
+ this.options = dist_engrid_ENGrid.getOption("FreshAddress");
+ if (this.options === false || !window.FreshAddress && !((_a = this.options) === null || _a === void 0 ? void 0 : _a.proxyUrl)) {
+ return;
}
-
- // Each EN Row is a Section
- this.sections = document.querySelectorAll("form.en__component > .en__component");
- this.currentSectionId = 0;
- // Check if we're on the Thank You page
- if (pageJson.pageNumber === pageJson.pageCount) {
- this.sendMessage("status", "loaded");
- if (this.isDonation) this.sendMessage("status", "celebrate");
- this.sendMessage("class", "thank-you");
- document.querySelector("body").dataset.thankYou = "true";
- // Get Query Strings
- const urlParams = new URLSearchParams(window.location.search);
- if (urlParams.get("name")) {
- let engrid = document.querySelector("#engrid");
- if (engrid) {
- let engridContent = engrid.innerHTML;
- engridContent = engridContent.replace("{user_data~First Name}", urlParams.get("name"));
- engridContent = engridContent.replace("{receipt_data~recurringFrequency}", urlParams.get("frequency"));
- engridContent = engridContent.replace("{receipt_data~amount}", "$" + urlParams.get("amount"));
- engrid.innerHTML = engridContent;
- this.sendMessage("firstname", urlParams.get("name"));
+ this.emailField = document.getElementById("en__field_supporter_emailAddress");
+ if (this.emailField) {
+ this.createFields();
+ this.addEventListeners();
+ window.FreshAddressStatus = "idle";
+ if (this.emailField.value) {
+ this.logger.log("E-mail Field Found");
+ this.shouldRun = false;
+ }
+ window.setTimeout(() => {
+ if (this.emailField && this.emailField.value) {
+ this.logger.log("E-mail Filled Programatically");
+ this.shouldRun = false;
}
+ }, 1000);
+ } else {
+ this.logger.log("E-mail Field Not Found");
+ }
+ }
+ createFields() {
+ if (!this.options) return;
+ this.options.dateField = this.options.dateField || "fa_date";
+ this.faDate = dist_engrid_ENGrid.getField(this.options.dateField);
+ if (!this.faDate) {
+ this.logger.log("Date Field Not Found. Creating...");
+ dist_engrid_ENGrid.createHiddenInput(this.options.dateField, "");
+ this.faDate = dist_engrid_ENGrid.getField(this.options.dateField);
+ }
+ this.options.statusField = this.options.statusField || "fa_status";
+ this.faStatus = dist_engrid_ENGrid.getField(this.options.statusField);
+ if (!this.faStatus) {
+ this.logger.log("Status Field Not Found. Creating...");
+ dist_engrid_ENGrid.createHiddenInput(this.options.statusField, "");
+ this.faStatus = dist_engrid_ENGrid.getField(this.options.statusField);
+ }
+ this.options.messageField = this.options.messageField || "fa_message";
+ this.faMessage = dist_engrid_ENGrid.getField(this.options.messageField);
+ if (!this.faMessage) {
+ this.logger.log("Message Field Not Found. Creating...");
+ dist_engrid_ENGrid.createHiddenInput(this.options.messageField, "");
+ this.faMessage = dist_engrid_ENGrid.getField(this.options.messageField);
+ }
+ }
+ writeToFields(status, message) {
+ if (!this.options) return;
+ this.faDate.value = dist_engrid_ENGrid.formatDate(new Date(), this.options.dateFieldFormat || "yyyy-MM-dd");
+ this.faStatus.value = status;
+ this.faMessage.value = message;
+ this.emailWrapper.dataset.freshaddressSafetosendstatus = status.toLowerCase();
+ }
+ addEventListeners() {
+ var _a;
+ if (!this.options) return;
+ // Add event listeners to fields
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.addEventListener("change", () => {
+ var _a, _b;
+ if (!this.shouldRun || ((_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value.includes("@4sitestudios.com"))) {
+ dist_engrid_ENGrid.removeError(this.emailWrapper);
+ this.writeToFields("Valid", "Skipped");
+ this.logger.log("Skipping E-mail Validation");
+ return;
+ }
+ this.logger.log("Validating " + ((_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value));
+ if (this.options && this.options.proxyUrl) {
+ this.callProxy();
} else {
- // Try to get the first name
- const thisClass = this;
- const pageDataUrl = location.protocol + "//" + location.host + location.pathname + "/pagedata";
- fetch(pageDataUrl).then(function (response) {
- return response.json();
- }).then(function (json) {
- if (json.hasOwnProperty("firstName") && json.firstName !== null) {
- thisClass.sendMessage("firstname", json.firstName);
- } else {
- thisClass.sendMessage("firstname", "Friend");
- }
- }).catch(error => {
- console.error("PageData Error:", error);
- });
+ this.callAPI();
}
- const bequestContainer = document.querySelector(".bequest-container");
- const bequestBtn = document.querySelector(".bequest-btn");
- if (bequestContainer && bequestBtn) {
- bequestBtn.addEventListener("click", e => {
- e.preventDefault();
- const overlay = document.querySelector(".engrid-modal__overlay");
- if (overlay) {
- overlay.classList.toggle("hide");
- if (!overlay.classList.contains("hide")) {
- // Listen for the close event from iframe
- window.addEventListener("message", function (event) {
- if (event.data === "iframeSubmitted") {
- overlay.classList.add("hide");
- bequestContainer.classList.add("hide");
- bequestBtn.classList.add("hide");
- }
- }, false);
- }
- }
- });
+ });
+ // Add event listener to submit
+ this.form.onValidate.subscribe(this.validate.bind(this));
+ }
+ callAPI() {
+ var _a;
+ if (!this.options || !window.FreshAddress) return;
+ if (!this.shouldRun) return;
+ window.FreshAddressStatus = "validating";
+ const email = (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value;
+ const options = {
+ emps: false,
+ rtc_timeout: 1200
+ };
+ const ret = window.FreshAddress.validateEmail(email, options).then(response => {
+ this.logger.log("Validate API Response", JSON.parse(JSON.stringify(response)));
+ return this.validateResponse(response);
+ });
+ }
+ validateResponse(data) {
+ var _a;
+ /* ERROR HANDLING: Let through in case of a service error. Enable form submission. */
+ if (data.isServiceError()) {
+ this.logger.log("Service Error");
+ this.writeToFields("Service Error", data.getErrorResponse());
+ return true;
+ }
+ /* CHECK RESULT: */
+ if (data.isValid()) {
+ // Set response message. No action required.
+ this.writeToFields("Valid", data.getComment());
+ dist_engrid_ENGrid.removeError(this.emailWrapper);
+ if (data.hasSuggest()) {
+ // Valid, with Suggestion
+ dist_engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
+ this.emailField.value = data.getSuggEmail();
+ }
+ } else if (data.isError()) {
+ // Error Condition 1 - the service should always respond with finding E/W/V
+ this.writeToFields("Invalid", data.getErrorResponse());
+ dist_engrid_ENGrid.setError(this.emailWrapper, data.getErrorResponse());
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ if (data.hasSuggest()) {
+ // Error, with Suggestion
+ dist_engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
+ this.emailField.value = data.getSuggEmail();
+ this.writeToFields("Error", data.getErrorResponse());
}
- return false;
+ } else if (data.isWarning()) {
+ this.writeToFields("Invalid", data.getErrorResponse());
+ dist_engrid_ENGrid.setError(this.emailWrapper, data.getErrorResponse());
+ if (data.hasSuggest()) {
+ // Warning, with Suggestion
+ dist_engrid_ENGrid.setError(this.emailWrapper, `Did you mean ${data.getSuggEmail()}?`);
+ this.emailField.value = data.getSuggEmail();
+ this.writeToFields("Warning", data.getErrorResponse());
+ }
+ } else {
+ // Error Condition 2 - the service should always respond with finding E/W/V
+ this.writeToFields("API Error", "Unknown Error");
+ }
+ window.FreshAddressStatus = "idle";
+ dist_engrid_ENGrid.enableSubmit();
+ }
+ validate() {
+ var _a;
+ dist_engrid_ENGrid.removeError(this.emailWrapper);
+ if (!this.form.validate) return;
+ if (!this.options) {
+ this.form.validate = true;
+ return;
}
- if (!this.sections.length) {
- // No section or no Donation Page was found
- this.sendMessage("error", "No sections found");
- return false;
+ if (!this.shouldRun) {
+ this.form.validate = true;
+ return;
}
- if (document.querySelector("body").dataset.engridSubtheme === "one-step-lightbox") {
- document.querySelector(".en__submit button")?.addEventListener("click", e => {
- e.preventDefault();
- this.submitLogic();
+ if (window.FreshAddressStatus === "validating") {
+ this.logger.log("Waiting for API Response");
+ // Self resolving Promise that waits 1000ms
+ const wait = new Promise((resolve, reject) => {
+ setTimeout(() => {
+ var _a;
+ const status = this.faStatus.value;
+ if (status === "" || status === "Invalid") {
+ this.logger.log("Promise Rejected");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ reject(false);
+ return;
+ }
+ this.logger.log("Promise Resolved");
+ resolve(true);
+ }, 700);
});
+ this.form.validatePromise = wait;
+ return;
+ } else if (this.faStatus.value === "Invalid") {
+ this.form.validate = false;
+ window.setTimeout(() => {
+ dist_engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ }, 100);
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ dist_engrid_ENGrid.enableSubmit();
return false;
}
- console.log(this.sections);
- if (this.isIframe()) {
- // If iFrame
- this.buildSectionNavigation();
- // If Form Submission Failed
- if (this.checkNested(EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && EngagingNetworks.require._defined.enjs.checkSubmissionFailed()) {
- console.log("DonationLightboxForm: Submission Failed");
- this.showHideDynamicSection(false);
- window.setTimeout(() => {
- if (this.validateForm()) {
- // Front-End Validation Passed, get first Error Message
- const error = document.querySelector("li.en__error");
- if (error) {
- // Check if error contains "problem processing" to send a smaller message
- if (error.innerHTML.toLowerCase().indexOf("problem processing") > -1) {
- this.sendMessage("error", "Sorry! There's a problem processing your donation.");
- this.scrollToElement(document.querySelector(".en__field--ccnumber"));
- } else {
- this.sendMessage("error", error.textContent);
- }
- // Check if error contains "payment" or "account" and scroll to the right section
- if (error.innerHTML.toLowerCase().indexOf("payment") > -1 || error.innerHTML.toLowerCase().indexOf("account") > -1) {
- this.scrollToElement(document.querySelector(".en__field--ccnumber"));
- } else if (error.innerHTML.toLowerCase().indexOf("routing") > -1 || error.innerHTML.toLowerCase().indexOf("account") > -1 || error.innerHTML.toLowerCase().indexOf("bank") > -1) {
- this.scrollToElement(document.querySelector(".en__field--bankRoutingNumber"));
- }
- }
- }
- }, 100);
+ this.form.validate = true;
+ return true;
+ }
+ callProxy() {
+ var _a, _b;
+ if (!this.options || !this.shouldRun) return;
+ window.FreshAddressStatus = "validating";
+ dist_engrid_ENGrid.disableSubmit("Validating Email Address...");
+ // Before calling the API, do a basic check to see if the email is in a valid format.
+ // This is to prevent unnecessary API calls.
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(this.emailField.value)) {
+ this.logger.log("Invalid Email Format from Basic Check");
+ this.writeToFields("Invalid", "Invalid Email Format");
+ dist_engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ dist_engrid_ENGrid.enableSubmit();
+ return;
+ }
+ fetch(this.options.proxyUrl, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({
+ email: (_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value
+ }),
+ signal: AbortSignal.timeout(5000)
+ }).then(response => {
+ if (!response.ok) {
+ throw new Error(`HTTP error ${response.status}`);
}
- document.querySelectorAll("form.en__component input.en__field__input").forEach(e => {
- e.addEventListener("focus", event => {
- // Run after 50ms - We need this or else some browsers will disregard the scroll due to the focus event
- const nextSectionId = Number(this.getSectionId(e));
- const currentSectionId = Number(this.currentSectionId);
- console.log("Focus on", nextSectionId, currentSectionId);
- setTimeout(() => {
- const focusIsOnNextSection = nextSectionId === currentSectionId + 1 || nextSectionId > currentSectionId + 1 && !this.isVisible(this.sections[currentSectionId + 1]);
+ return response.json();
+ }).then(data => {
+ this.logger.log("Proxy API Response", data);
+ this.validateProxyResponse(data);
+ }).catch(error => {
+ // 422 (Unprocessable Content) - This means the email is in an invalid format.
+ if (error.message.includes("422")) {
+ this.logger.log("Invalid Email Format");
+ this.writeToFields("Invalid", "Invalid Email Format");
+ dist_engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ return;
+ }
+ if (error.name === "AbortError") {
+ this.logger.log("Proxy API request timed out");
+ this.writeToFields("Request Timeout", "The request took too long.");
+ return;
+ }
+ this.logger.log("Proxy API Error", error);
+ this.writeToFields("Service Error", error.toString());
+ }).finally(() => {
+ window.FreshAddressStatus = "idle";
+ dist_engrid_ENGrid.enableSubmit();
+ });
+ }
+ /*
+ * Validate a request proxied to AtData's Safe To Send API.
+ * https://docs.atdata.com/reference/safe-to-send
+ * https://docs.atdata.com/reference/email-status
+ * https://docs.atdata.com/reference/status-codes-safe-to-send
+ */
+ validateProxyResponse(data) {
+ var _a;
+ // If response is not in expected format, log error and let through.
+ if (!data.safe_to_send) {
+ this.logger.log("Invalid Proxy Response");
+ this.writeToFields("Service Error", "Invalid Proxy Response");
+ return true;
+ }
+ const res = data.safe_to_send;
+ dist_engrid_ENGrid.removeError(this.emailWrapper);
+ this.writeToFields(res.status, res.status_code);
+ if (["invalid", "trap"].includes(res.status)) {
+ this.writeToFields("Invalid", res.status_code); // Must be "Invalid" to trigger validation error on submit
+ dist_engrid_ENGrid.setError(this.emailWrapper, "This email address is not valid.");
+ (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
+ if (res.email_corrections && res.email_corrections.length > 0) {
+ this.emailField.value = res.email_corrections[0];
+ dist_engrid_ENGrid.setError(this.emailWrapper, `This email address is not valid. Did you mean ${res.email_corrections[0]}?`);
+ }
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/progress-bar.js
- // if (focusIsOnNextSection && this.validateForm(currentSectionId)) {
- if (focusIsOnNextSection) {
- // // Only scroll if the current section doesn't have radio elements
- // const radioElement =
- // this.sections[currentSectionId].querySelector(
- // ".en__field--radio"
- // );
- // if (!radioElement) this.scrollToElement(e);
- return;
- }
- }, 50);
- // If the field is the credit card number, remove the error class from the parent
- if ("id" in e && e.id === "en__field_transaction_ccnumber") {
- const parent = e.closest(".en__field");
- if (parent) {
- parent.classList.remove("has-error");
- }
- }
- });
+class progress_bar_ProgressBar {
+ constructor() {
+ var _a, _b;
+ const progressIndicator = document.querySelector("span[data-engrid-progress-indicator]");
+ const pageCount = dist_engrid_ENGrid.getPageCount();
+ const pageNumber = dist_engrid_ENGrid.getPageNumber();
+ if (!progressIndicator || !pageCount || !pageNumber) {
+ return;
+ }
+ let maxValue = (_a = progressIndicator.getAttribute("max")) !== null && _a !== void 0 ? _a : 100;
+ if (typeof maxValue === "string") maxValue = parseInt(maxValue);
+ let amountValue = (_b = progressIndicator.getAttribute("amount")) !== null && _b !== void 0 ? _b : 0;
+ if (typeof amountValue === "string") amountValue = parseInt(amountValue);
+ const prevPercentage = pageNumber === 1 ? 0 : Math.ceil((pageNumber - 1) / pageCount * maxValue);
+ let percentage = pageNumber === 1 ? 0 : Math.ceil(pageNumber / pageCount * maxValue);
+ const scalePrev = prevPercentage / 100;
+ let scale = percentage / 100;
+ if (amountValue) {
+ percentage = Math.ceil(amountValue) > Math.ceil(maxValue) ? maxValue : amountValue;
+ scale = percentage / 100;
+ }
+ progressIndicator.innerHTML = `
+
+
+ ${percentage}%
+
`;
+ if (percentage !== prevPercentage) {
+ const progress = document.querySelector(".indicator__progress");
+ requestAnimationFrame(function () {
+ progress.style.transform = `scaleX(${scale})`;
});
- // For TAB navigation, ensure the script will scroll to the focused element's section. So we will watch for the keydown event on the document.
-
- document.addEventListener("keydown", event => {
- if (event.keyCode === 9) {
- const focusedElement = document.activeElement;
- // If the focused element is not inside the form, return
- if (!focusedElement.closest("form.en__component")) return;
- console.log("Tabbed to", focusedElement);
- const nextSectionId = Number(this.getSectionId(focusedElement));
- const currentSectionId = Number(this.currentSectionId);
- if (currentSectionId !== nextSectionId) {
- event.preventDefault();
- if (this.validateForm(currentSectionId)) {
- this.scrollToSection(nextSectionId, currentSectionId);
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/remember-me.js
+
+
+const dist_remember_me_tippy = (__webpack_require__(716)/* ["default"] */ .Ay);
+class remember_me_RememberMe {
+ constructor(options) {
+ this._form = events_en_form_EnForm.getInstance();
+ this._events = remember_me_events_RememberMeEvents.getInstance();
+ this.iframe = null;
+ this.remoteUrl = options.remoteUrl ? options.remoteUrl : null;
+ this.cookieName = options.cookieName ? options.cookieName : "engrid-autofill";
+ this.cookieExpirationDays = options.cookieExpirationDays ? options.cookieExpirationDays : 365;
+ this.rememberMeOptIn = options.checked ? options.checked : false;
+ this.fieldNames = options.fieldNames ? options.fieldNames : [];
+ this.fieldDonationAmountRadioName = options.fieldDonationAmountRadioName ? options.fieldDonationAmountRadioName : "transaction.donationAmt";
+ this.fieldDonationAmountOtherName = options.fieldDonationAmountOtherName ? options.fieldDonationAmountOtherName : "transaction.donationAmt.other";
+ this.fieldDonationRecurrPayRadioName = options.fieldDonationRecurrPayRadioName ? options.fieldDonationRecurrPayRadioName : "transaction.recurrpay";
+ this.fieldDonationAmountOtherCheckboxID = options.fieldDonationAmountOtherCheckboxID ? options.fieldDonationAmountOtherCheckboxID : "#en__field_transaction_donationAmt4";
+ this.fieldOptInSelectorTarget = options.fieldOptInSelectorTarget ? options.fieldOptInSelectorTarget : ".en__field--emailAddress.en__field";
+ this.fieldOptInSelectorTargetLocation = options.fieldOptInSelectorTargetLocation ? options.fieldOptInSelectorTargetLocation : "after";
+ this.fieldClearSelectorTarget = options.fieldClearSelectorTarget ? options.fieldClearSelectorTarget : 'label[for="en__field_supporter_firstName"]';
+ this.fieldClearSelectorTargetLocation = options.fieldClearSelectorTargetLocation ? options.fieldClearSelectorTargetLocation : "before";
+ this.fieldData = {};
+ if (this.useRemote()) {
+ this.createIframe(() => {
+ if (this.iframe && this.iframe.contentWindow) {
+ this.iframe.contentWindow.postMessage(JSON.stringify({
+ key: this.cookieName,
+ operation: "read"
+ }), "*");
+ this._form.onSubmit.subscribe(() => {
+ if (this.rememberMeOptIn) {
+ this.readFields();
+ this.saveCookieToRemote();
}
+ });
+ }
+ }, event => {
+ let data;
+ if (event.data && typeof event.data === "string" && this.isJson(event.data)) {
+ data = JSON.parse(event.data);
+ }
+ if (data && data.key && data.value !== undefined && data.key === this.cookieName) {
+ this.updateFieldData(data.value);
+ this.writeFields();
+ let hasFieldData = Object.keys(this.fieldData).length > 0;
+ if (!hasFieldData) {
+ this.insertRememberMeOptin();
+ } else {
+ this.insertClearRememberMeLink();
}
}
});
- // Map the enter key to the next button
- document.querySelectorAll("form.en__component input.en__field__input").forEach(e => {
- e.addEventListener("keydown", event => {
- if (event.keyCode === 13) {
- event.preventDefault();
- const sectionId = Number(this.getSectionId(e));
- if (this.validateForm(sectionId)) {
- this.scrollToSection(sectionId + 1, sectionId);
- }
- }
- });
+ } else {
+ this.readCookie();
+ let hasFieldData = Object.keys(this.fieldData).length > 0;
+ if (!hasFieldData) {
+ this.insertRememberMeOptin();
+ this.rememberMeOptIn = false;
+ } else {
+ this.insertClearRememberMeLink();
+ this.rememberMeOptIn = true;
+ }
+ this.writeFields();
+ this._form.onSubmit.subscribe(() => {
+ if (this.rememberMeOptIn) {
+ this.readFields();
+ this.saveCookie();
+ }
});
}
- let paymentOpts = document.querySelector(".payment-options");
- if (paymentOpts) {
- this.clickPaymentOptions(paymentOpts);
- }
- this.addTabIndexToLabels();
- this.putArrowUpSVG();
- this.bounceArrow(this.frequency.getInstance().frequency);
- this.addEvents();
- this.changeSubmitButton();
- this.hideAnnualFrequency();
- this.sendMessage("status", "loaded");
- // Check if theres a color value in the url
- const urlParams = new URLSearchParams(window.location.search);
- if (urlParams.get("color")) {
- document.body.style.setProperty("--color_primary", urlParams.get("color"));
+ }
+ updateFieldData(jsonData) {
+ if (jsonData) {
+ let data = JSON.parse(jsonData);
+ for (let i = 0; i < this.fieldNames.length; i++) {
+ if (data[this.fieldNames[i]] !== undefined) {
+ this.fieldData[this.fieldNames[i]] = decodeURIComponent(data[this.fieldNames[i]]);
+ }
+ }
}
- window.addEventListener("message", this.receiveMessage.bind(this), false);
- this.sendMessage("isMobile");
- this.showHideDynamicSection(false);
- App.watchForError(() => {
- this.sendMessage("status", "loaded");
- if (this.validateForm(false, false)) {
- // Front-End Validation Passed, get first Error Message
- const error = document.querySelector("li.en__error");
- if (error) {
- // Check if error contains "processing" to send a smaller message
- if (error.innerHTML.toLowerCase().indexOf("processing") > -1) {
- this.sendMessage("error", "Sorry! There's a problem processing your donation.");
- this.scrollToElement(document.querySelector(".en__field--ccnumber"));
- } else if (error.innerHTML.toLowerCase().indexOf("captcha") > -1) {
- console.error("Captcha Error");
- this.scrollToElement(document.querySelector(".en__captcha"));
- } else {
- this.sendMessage("error", error.textContent);
- }
- // Check if error contains "payment" or "account" and scroll to the right section
- if (error.innerHTML.toLowerCase().indexOf("payment") > -1 || error.innerHTML.toLowerCase().indexOf("account") > -1 || error.innerHTML.toLowerCase().indexOf("card") > -1) {
- this.scrollToElement(document.querySelector(".en__field--ccnumber"));
- }
+ }
+ insertClearRememberMeLink() {
+ let clearRememberMeField = document.getElementById("clear-autofill-data");
+ if (!clearRememberMeField) {
+ const clearAutofillLabel = "clear autofill";
+ clearRememberMeField = document.createElement("a");
+ clearRememberMeField.setAttribute("id", "clear-autofill-data");
+ clearRememberMeField.classList.add("label-tooltip");
+ clearRememberMeField.setAttribute("style", "cursor: pointer;");
+ clearRememberMeField.innerHTML = `(${clearAutofillLabel})`;
+ const targetField = this.getElementByFirstSelector(this.fieldClearSelectorTarget);
+ if (targetField) {
+ if (this.fieldClearSelectorTargetLocation === "after") {
+ targetField.appendChild(clearRememberMeField);
+ } else {
+ targetField.prepend(clearRememberMeField);
}
}
+ }
+ clearRememberMeField.addEventListener("click", e => {
+ e.preventDefault();
+ this.clearFields(["supporter.country" /*, 'supporter.emailAddress'*/]);
+ if (this.useRemote()) {
+ this.clearCookieOnRemote();
+ } else {
+ this.clearCookie();
+ }
+ let clearAutofillLink = document.getElementById("clear-autofill-data");
+ if (clearAutofillLink) {
+ clearAutofillLink.style.display = "none";
+ }
+ this.rememberMeOptIn = false;
+ this._events.dispatchClear();
+ window.dispatchEvent(new CustomEvent("RememberMe_Cleared"));
});
- // Custom class and label for the Stripe Digital Wallets Payment Method
- const digitalWallets = document.querySelector(".give-by-select .stripedigitalwallet");
- if (digitalWallets) {
- const digitalWalletsLabel = digitalWallets.querySelector("span");
- if (digitalWalletsLabel) {
- const isApplePay = window.hasOwnProperty("ApplePaySession");
- digitalWalletsLabel.innerHTML = isApplePay ? "APPLE PAY" : "GOOGLE PAY";
- digitalWallets.classList.add(isApplePay ? "apple-pay" : "google-pay");
+ this._events.dispatchLoad(true);
+ window.dispatchEvent(new CustomEvent("RememberMe_Loaded", {
+ detail: {
+ withData: true
+ }
+ }));
+ }
+ getElementByFirstSelector(selectorsString) {
+ // iterate through the selectors until we find one that exists
+ let targetField = null;
+ const selectorTargets = selectorsString.split(",");
+ for (let i = 0; i < selectorTargets.length; i++) {
+ targetField = document.querySelector(selectorTargets[i]);
+ if (targetField) {
+ break;
}
}
+ return targetField;
}
- // Send iframe message to parent
- sendMessage(key, value) {
- const message = {
- key: key,
- value: value
- };
- window.parent.postMessage(message, "*");
+ insertRememberMeOptin() {
+ let rememberMeOptInField = document.getElementById("remember-me-opt-in");
+ if (!rememberMeOptInField) {
+ const rememberMeLabel = "Remember Me";
+ const rememberMeInfo = `
+ Check βRemember meβ to complete forms on this device faster.
+ While your financial information wonβt be stored, you should only check this box from a personal device.
+ Click βClear autofillβ to remove the information from your device at any time.
+ `;
+ const rememberMeOptInFieldChecked = this.rememberMeOptIn ? "checked" : "";
+ const rememberMeOptInField = document.createElement("div");
+ rememberMeOptInField.classList.add("en__field", "en__field--checkbox", "en__field--question", "rememberme-wrapper");
+ rememberMeOptInField.setAttribute("id", "remember-me-opt-in");
+ rememberMeOptInField.setAttribute("style", "overflow-x: hidden;");
+ rememberMeOptInField.innerHTML = `
+
+
+
+
+
+ ${rememberMeLabel}
+
+
+
+
+
+
+
+ `;
+ const targetField = this.getElementByFirstSelector(this.fieldOptInSelectorTarget);
+ if (targetField && targetField.parentNode) {
+ targetField.parentNode.insertBefore(rememberMeOptInField, this.fieldOptInSelectorTargetLocation == "before" ? targetField : targetField.nextSibling);
+ const rememberMeCheckbox = document.getElementById("remember-me-checkbox");
+ if (rememberMeCheckbox) {
+ rememberMeCheckbox.addEventListener("change", () => {
+ if (rememberMeCheckbox.checked) {
+ this.rememberMeOptIn = true;
+ } else {
+ this.rememberMeOptIn = false;
+ }
+ });
+ }
+ dist_remember_me_tippy("#rememberme-learn-more-toggle", {
+ content: rememberMeInfo
+ });
+ }
+ } else if (this.rememberMeOptIn) {
+ rememberMeOptInField.checked = true;
+ }
+ this._events.dispatchLoad(false);
+ window.dispatchEvent(new CustomEvent("RememberMe_Loaded", {
+ detail: {
+ withData: false
+ }
+ }));
}
- // Receive iframe message from parent
- receiveMessage(event) {
- if (event.data.key === "isMobile" && event.data.value === true) {
- document.body.classList.add("is-mobile");
+ useRemote() {
+ return !!this.remoteUrl && typeof window.postMessage === "function" && window.JSON && window.localStorage;
+ }
+ createIframe(iframeLoaded, messageReceived) {
+ if (this.remoteUrl) {
+ let iframe = document.createElement("iframe");
+ iframe.style.cssText = "position:absolute;width:1px;height:1px;left:-9999px;";
+ iframe.src = this.remoteUrl;
+ iframe.setAttribute("sandbox", "allow-same-origin allow-scripts");
+ iframe.setAttribute("title", "Remember Me iframe");
+ this.iframe = iframe;
+ document.body.appendChild(this.iframe);
+ this.iframe.addEventListener("load", () => iframeLoaded(), false);
+ window.addEventListener("message", event => {
+ var _a;
+ if (((_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) === event.source) {
+ messageReceived(event);
+ }
+ }, false);
}
- if (event.data.key === "isMobile" && event.data.value === false) {
- document.body.classList.remove("is-mobile");
+ }
+ clearCookie() {
+ this.fieldData = {};
+ this.saveCookie();
+ }
+ clearCookieOnRemote() {
+ this.fieldData = {};
+ this.saveCookieToRemote();
+ }
+ saveCookieToRemote() {
+ if (this.iframe && this.iframe.contentWindow) {
+ this.iframe.contentWindow.postMessage(JSON.stringify({
+ key: this.cookieName,
+ value: this.fieldData,
+ operation: "write",
+ expires: this.cookieExpirationDays
+ }), "*");
}
}
-
- // Check if is iFrame
- isIframe() {
- return window.self !== window.top;
+ readCookie() {
+ this.updateFieldData(cookie_get(this.cookieName) || "");
}
- submitLogic() {
- if (this.isDonation) {
- console.log("DonationLightboxForm: submitLogic - Donation");
- // Send Basic User Data to Parent
- this.sendMessage("donationinfo", JSON.stringify({
- name: document.querySelector("#en__field_supporter_firstName").value,
- amount: this.getDonationTotal(),
- frequency: this.frequency.getInstance().frequency
- }));
- // Only shows cortain if payment is not paypal
- const paymentType = document.querySelector("#en__field_transaction_paymenttype").value;
- if (paymentType.toLowerCase() != "paypal") {
- if (document.querySelector("body").dataset.engridSubtheme === "one-step-lightbox") {
- const waitForUpsellModal = () => {
- const upsellModal = document.querySelector("#en__upsellModal");
- if (upsellModal) {
- return Promise.resolve(upsellModal);
- }
- return new Promise(resolve => {
- const observer = new MutationObserver(mutations => {
- for (const mutation of mutations) {
- for (const node of mutation.addedNodes) {
- if (!(node instanceof HTMLElement)) continue;
- const modal = node.id === "en__upsellModal" ? node : node.querySelector?.("#en__upsellModal");
- if (modal) {
- observer.disconnect();
- resolve(modal);
- return;
- }
+ saveCookie() {
+ cookie_set(this.cookieName, JSON.stringify(this.fieldData), {
+ expires: this.cookieExpirationDays
+ });
+ }
+ readFields() {
+ for (let i = 0; i < this.fieldNames.length; i++) {
+ let fieldSelector = "[name='" + this.fieldNames[i] + "']";
+ let field = document.querySelector(fieldSelector);
+ if (field) {
+ if (field.tagName === "INPUT") {
+ let type = field.getAttribute("type");
+ if (type === "radio" || type === "checkbox") {
+ field = document.querySelector(fieldSelector + ":checked");
+ }
+ this.fieldData[this.fieldNames[i]] = encodeURIComponent(field.value);
+ } else if (field.tagName === "SELECT") {
+ this.fieldData[this.fieldNames[i]] = encodeURIComponent(field.value);
+ }
+ }
+ }
+ }
+ setFieldValue(field, value, overwrite = false) {
+ value = decodeURIComponent(value || "");
+ if (field && value !== undefined) {
+ if ("type" in field) {
+ switch (field.type) {
+ case "select-one":
+ case "select-multiple":
+ {
+ const selectField = field;
+ for (const option of Array.from(selectField.options)) {
+ if (option.value === value) {
+ if (selectField.value && overwrite || !selectField.value) {
+ option.selected = true;
+ selectField.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
}
+ break;
}
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
- });
- };
- waitForUpsellModal().then(modal => {
- document.querySelector("#en__upsellModal__yes button")?.addEventListener("click", () => {
- this.sendMessage("status", "loading");
- });
- document.querySelector("#en__upsellModal__no button")?.addEventListener("click", () => {
- this.sendMessage("status", "loading");
- });
- });
- } else {
- this.sendMessage("status", "loading");
+ }
+ break;
+ }
+ case "checkbox":
+ case "radio":
+ {
+ const inputField = field;
+ if (inputField.value === value) {
+ inputField.checked = true;
+ inputField.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ }
+ break;
+ }
+ case "textarea":
+ case "text":
+ default:
+ if (field.value && overwrite || !field.value) {
+ field.value = value;
+ field.dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ field.dispatchEvent(new Event("blur", {
+ bubbles: true
+ }));
+ }
}
+ }
+ }
+ }
+ clearFields(skipFields) {
+ for (let key in this.fieldData) {
+ if (skipFields.includes(key)) {
+ delete this.fieldData[key];
+ } else if (this.fieldData[key] === "") {
+ delete this.fieldData[key];
} else {
- // If Paypal, submit the form on a new tab
- const thisClass = this;
- document.addEventListener("visibilitychange", function () {
- if (document.visibilityState === "visible") {
- thisClass.sendMessage("status", "submitted");
+ this.fieldData[key] = "";
+ }
+ }
+ this.writeFields(true);
+ }
+ /**
+ * Writes the values from the fieldData object to the corresponding HTML input fields.
+ *
+ * This function iterates over the fieldNames array and for each field name, it selects the corresponding HTML input field.
+ * If the field is found and its tag name is "INPUT", it checks if the field name matches certain conditions (like being a donation recurring payment radio button or a donation amount radio button).
+ * Depending on these conditions, it either clicks the field or sets its value using the setFieldValue function.
+ * If the field tag name is "SELECT", it sets its value using the setFieldValue function.
+ *
+ * @param overwrite - A boolean indicating whether to overwrite the existing value of the fields. Defaults to false.
+ */
+ writeFields(overwrite = false) {
+ for (let i = 0; i < this.fieldNames.length; i++) {
+ let fieldSelector = "[name='" + this.fieldNames[i] + "']";
+ let field = document.querySelector(fieldSelector);
+ if (field) {
+ if (field.tagName === "INPUT") {
+ if (this.fieldNames[i] === this.fieldDonationRecurrPayRadioName) {
+ if (this.fieldData[this.fieldNames[i]] === "Y") {
+ field.click();
+ }
+ } else if (this.fieldDonationAmountRadioName === this.fieldNames[i]) {
+ field = document.querySelector(fieldSelector + "[value='" + this.fieldData[this.fieldNames[i]] + "']");
+ if (field) {
+ field.click();
+ } else {
+ field = document.querySelector("input[name='" + this.fieldDonationAmountOtherName + "']");
+ this.setFieldValue(field, this.fieldData[this.fieldNames[i]], true);
+ }
} else {
- thisClass.sendMessage("status", "loading");
+ this.setFieldValue(field, this.fieldData[this.fieldNames[i]], overwrite);
}
- });
- document.querySelector("form.en__component").target = "_blank";
+ } else if (field.tagName === "SELECT") {
+ this.setFieldValue(field, this.fieldData[this.fieldNames[i]], true);
+ }
}
- if (this.checkNested(window.EngagingNetworks, "require", "_defined", "enDefaults", "validation", "_getSubmitPromise")) {
- console.log("DonationLightboxForm: Using EN Validation Promise");
- window.EngagingNetworks.require._defined.enDefaults.validation._getSubmitPromise().then(function () {
- document.querySelector("form.en__component").submit();
- });
+ }
+ }
+ isJson(str) {
+ try {
+ JSON.parse(str);
+ } catch (e) {
+ return false;
+ }
+ return true;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/show-if-amount.js
+
+
+class show_if_amount_ShowIfAmount {
+ constructor() {
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this.logger = new dist_logger_EngridLogger("ShowIfAmount", "yellow", "black", "π");
+ this._elements = document.querySelectorAll('[class*="showifamount"]');
+ if (this._elements.length > 0) {
+ this._amount.onAmountChange.subscribe(() => this.init());
+ this.init();
+ return;
+ }
+ this.logger.log("Show If Amount: NO ELEMENTS FOUND");
+ }
+ init() {
+ //If we are on a thank you page, use the window.pageJson.amount
+ const amount = dist_engrid_ENGrid.getGiftProcess() ? window.pageJson.amount : this._amount.amount;
+ this._elements.forEach(element => {
+ this.lessthan(amount, element);
+ this.lessthanorequalto(amount, element);
+ this.equalto(amount, element);
+ this.greaterthanorequalto(amount, element);
+ this.greaterthan(amount, element);
+ this.between(amount, element);
+ });
+ }
+ getClassNameByOperand(classList, operand) {
+ let myClass = null;
+ classList.forEach(className => {
+ if (className.includes(`showifamount-${operand}-`)) {
+ myClass = className;
+ }
+ });
+ return myClass;
+ }
+ lessthan(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "lessthan");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount < Number(amountCheck)) {
+ this.logger.log("(lessthan):", element);
+ element.classList.add("engrid-open");
} else {
- console.log("DonationLightboxForm: Using standard submit");
- document.querySelector("form.en__component").requestSubmit();
+ element.classList.remove("engrid-open");
}
- } else {
- console.log("DonationLightboxForm: submitLogic - Non Donation");
- this.sendMessage("status", "loading");
- document.querySelector("form.en__component").requestSubmit();
}
}
- // Build Section Navigation
- buildSectionNavigation() {
- console.log("DonationLightboxForm: buildSectionNavigation");
- this.sections.forEach((section, key) => {
- section.dataset.sectionId = key;
- const isUpsellSection = section.querySelector(".upsell-buttons");
- if (isUpsellSection) {
- this.upsellSection = section;
- this.upsellSectionId = key;
- section.dataset.upsellSection = true;
- this.replaceUpsellMergeTags();
+ lessthanorequalto(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "lessthanorequalto");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount <= Number(amountCheck)) {
+ this.logger.log("(lessthanorequalto):", element);
+ element.classList.add("engrid-open");
+ } else {
+ element.classList.remove("engrid-open");
}
- const sectionNavigation = document.createElement("div");
- sectionNavigation.classList.add("section-navigation");
- const sectionCount = document.createElement("div");
- sectionCount.classList.add("section-count");
- const sectionTotal = this.sections.length;
- if (sectionTotal > 1) {
- if (key == 0) {
- sectionNavigation.innerHTML = `
-
- Donate Today
-
-
-
-
- `;
- } else if (key == this.sections.length - 1) {
- // Add Last Section Data Attribute
- section.dataset.lastSection = true;
- sectionNavigation.innerHTML = `
-
-
-
-
-
-
- Give Now
-
- `;
- } else if (key == this.upsellSectionId) {
- // Add only the back button to the upsell section
- sectionNavigation.innerHTML = `
-
-
-
-
-
- `;
- } else {
- sectionNavigation.innerHTML = `
-
-
-
-
-
-
- Continue
-
-
-
-
- `;
- }
- if (key + 1 < sectionTotal) {
- sectionCount.innerHTML = `
- ${key + 1} of
- ${sectionTotal}
- `;
- }
+ }
+ }
+ equalto(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "equalto");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount == Number(amountCheck)) {
+ this.logger.log("(equalto):", element);
+ element.classList.add("engrid-open");
} else {
- // Single Section Pages
- const submitButtonLabel = document.querySelector(".en__submit button")?.innerText || "Submit";
- sectionNavigation.innerHTML = `
-
- ${submitButtonLabel}
-
- `;
+ element.classList.remove("engrid-open");
}
- sectionNavigation.querySelector(".section-navigation__previous")?.addEventListener("click", e => {
- e.preventDefault();
- this.scrollToSection(key - 1, key);
+ }
+ }
+ greaterthanorequalto(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "greaterthanorequalto");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount >= Number(amountCheck)) {
+ this.logger.log("(greaterthanorequalto):", element);
+ element.classList.add("engrid-open");
+ } else {
+ element.classList.remove("engrid-open");
+ }
+ }
+ }
+ greaterthan(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "greaterthan");
+ if (showifamountClass) {
+ let amountCheck = showifamountClass.split("-").slice(-1)[0];
+ if (amount > Number(amountCheck)) {
+ this.logger.log("(greaterthan):", element);
+ element.classList.add("engrid-open");
+ } else {
+ element.classList.remove("engrid-open");
+ }
+ }
+ }
+ between(amount, element) {
+ const showifamountClass = this.getClassNameByOperand(element.classList, "between");
+ if (showifamountClass) {
+ let amountCheckMin = showifamountClass.split("-").slice(-2, -1)[0];
+ let amountCheckMax = showifamountClass.split("-").slice(-1)[0];
+ if (amount > Number(amountCheckMin) && amount < Number(amountCheckMax)) {
+ this.logger.log("(between):", element);
+ element.classList.add("engrid-open");
+ } else {
+ element.classList.remove("engrid-open");
+ }
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/other-amount.js
+// This class automatically select other radio input when an amount is entered into it.
+
+class other_amount_OtherAmount {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("OtherAmount", "green", "black", "π°");
+ this._amount = donation_amount_DonationAmount.getInstance();
+ "focusin input".split(" ").forEach(e => {
+ var _a;
+ // We're attaching this event to the body because sometimes the other amount input is not in the DOM yet and comes via AJAX.
+ (_a = document.querySelector("body")) === null || _a === void 0 ? void 0 : _a.addEventListener(e, event => {
+ const target = event.target;
+ if (target.classList.contains("en__field__input--other")) {
+ this.logger.log("Other Amount Field Focused");
+ this.setRadioInput();
+ }
});
- sectionNavigation.querySelector(".section-navigation__next")?.addEventListener("click", e => {
- e.preventDefault();
- if (this.validateForm(key)) {
- this.scrollToSection(key + 1, key);
+ });
+ const otherAmountField = document.querySelector("[name='transaction.donationAmt.other'");
+ if (otherAmountField) {
+ otherAmountField.setAttribute("inputmode", "decimal");
+ // ADD THE MISSING LABEL FOR IMPROVED ACCESSABILITY
+ otherAmountField.setAttribute("aria-label", "Enter your custom donation amount");
+ otherAmountField.setAttribute("autocomplete", "off");
+ otherAmountField.setAttribute("data-lpignore", "true");
+ otherAmountField.addEventListener("change", e => {
+ const target = e.target;
+ const amount = target.value;
+ const cleanAmount = dist_engrid_ENGrid.cleanAmount(amount);
+ if (amount !== cleanAmount.toString()) {
+ this.logger.log(`Other Amount Field Changed: ${amount} => ${cleanAmount}`);
+ if ("dataLayer" in window) {
+ window.dataLayer.push({
+ event: "otherAmountTransformed",
+ otherAmountTransformation: `${amount} => ${cleanAmount}`
+ });
+ }
+ target.value = cleanAmount % 1 != 0 ? cleanAmount.toFixed(2) : cleanAmount.toString();
}
});
- sectionNavigation.querySelector(".section-navigation__submit")?.addEventListener("click", e => {
- e.preventDefault();
- // Validate the entire form again
- if (this.validateForm(false, this.isDonation)) {
- this.submitLogic();
+ // On blur, if the amount is 0, select the previous amount
+ otherAmountField.addEventListener("blur", e => {
+ const target = e.target;
+ const amount = target.value;
+ const cleanAmount = dist_engrid_ENGrid.cleanAmount(amount);
+ if (cleanAmount === 0) {
+ this.logger.log("Other Amount Field Blurred with 0 amount");
+ // Get Live Amount
+ const liveAmount = this._amount.amount;
+ if (liveAmount > 0) {
+ this._amount.setAmount(liveAmount, false);
+ }
}
});
- section.querySelector(".en__component").append(sectionNavigation);
- section.querySelector(".en__component").append(sectionCount);
+ }
+ }
+ setRadioInput() {
+ const target = document.querySelector(".en__field--donationAmt .en__field__input--other");
+ if (target && target.parentNode && target.parentNode.parentNode) {
+ const targetWrapper = target.parentNode;
+ targetWrapper.classList.remove("en__field__item--hidden");
+ if (targetWrapper.parentNode) {
+ const lastRadioInput = targetWrapper.parentNode.querySelector(".en__field__item:nth-last-child(2) input");
+ lastRadioInput.checked = !0;
+ }
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/logger.js
+
+/**
+ * A better logger. It only works if debug is enabled.
+ */
+class dist_logger_EngridLogger {
+ constructor(prefix, color, background, emoji) {
+ this.prefix = "";
+ this.color = "black";
+ this.background = "white";
+ this.emoji = "";
+ if (emoji) {
+ this.emoji = emoji;
+ } else {
+ switch (color) {
+ case "red":
+ this.emoji = "π΄";
+ break;
+ case "green":
+ this.emoji = "π’";
+ break;
+ case "blue":
+ this.emoji = "π΅";
+ break;
+ case "yellow":
+ this.emoji = "π‘";
+ this.background = "black";
+ break;
+ case "purple":
+ this.emoji = "π£";
+ break;
+ case "black":
+ default:
+ this.emoji = "β«";
+ break;
+ }
+ }
+ if (prefix) {
+ this.prefix = `[ENgrid ${prefix}]`;
+ }
+ if (color) {
+ this.color = color;
+ }
+ if (background) {
+ this.background = background;
+ }
+ }
+ get log() {
+ if (!dist_engrid_ENGrid.debug && dist_engrid_ENGrid.getUrlParameter("debug") !== "log") {
+ return () => {};
+ }
+ return console.log.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+ get success() {
+ if (!dist_engrid_ENGrid.debug) {
+ return () => {};
+ }
+ return console.log.bind(window.console, "%c β
" + this.prefix + " %s", `color: green; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+ get danger() {
+ if (!dist_engrid_ENGrid.debug) {
+ return () => {};
+ }
+ return console.log.bind(window.console, "%c βοΈ " + this.prefix + " %s", `color: red; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+ get warn() {
+ if (!dist_engrid_ENGrid.debug) {
+ return () => {};
+ }
+ return console.warn.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+ get dir() {
+ if (!dist_engrid_ENGrid.debug) {
+ return () => {};
+ }
+ return console.dir.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+ get error() {
+ if (!dist_engrid_ENGrid.debug) {
+ return () => {};
+ }
+ return console.error.bind(window.console, "%c" + this.emoji + " " + this.prefix + " %s", `color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/min-max-amount.js
+// This script adds an erros message to the page if the amount is greater than the max amount or less than the min amount.
+
+class min_max_amount_MinMaxAmount {
+ constructor() {
+ var _a, _b;
+ this._form = events_en_form_EnForm.getInstance();
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this.minAmount = (_a = dist_engrid_ENGrid.getOption("MinAmount")) !== null && _a !== void 0 ? _a : 1;
+ this.maxAmount = (_b = dist_engrid_ENGrid.getOption("MaxAmount")) !== null && _b !== void 0 ? _b : 100000;
+ this.minAmountMessage = dist_engrid_ENGrid.getOption("MinAmountMessage");
+ this.maxAmountMessage = dist_engrid_ENGrid.getOption("MaxAmountMessage");
+ this.enAmountValidator = null;
+ this.logger = new dist_logger_EngridLogger("MinMaxAmount", "white", "purple", "π’");
+ if (!this.shouldRun()) {
+ // If we're not on a Donation Page, get out
+ return;
+ }
+ this.setValidationConfigFromEN();
+ this._amount.onAmountChange.subscribe(s => window.setTimeout(this.liveValidate.bind(this), 1000) // Wait 1 second for the amount to be updated
+ );
+ this._form.onValidate.subscribe(this.enOnValidate.bind(this));
+ }
+ // Should we run the script?
+ shouldRun() {
+ return dist_engrid_ENGrid.getPageType() === "DONATION";
+ }
+ // Don't submit the form if the amount is not valid
+ enOnValidate() {
+ if (!this._form.validate) return;
+ const otherAmount = document.querySelector("[name='transaction.donationAmt.other']");
+ if (this._amount.amount < this.minAmount) {
+ this.logger.log("Amount is less than min amount: " + this.minAmount);
+ if (otherAmount) {
+ otherAmount.focus();
+ }
+ this._form.validate = false;
+ } else if (this._amount.amount > this.maxAmount) {
+ this.logger.log("Amount is greater than max amount: " + this.maxAmount);
+ if (otherAmount) {
+ otherAmount.focus();
+ }
+ this._form.validate = false;
+ }
+ window.setTimeout(this.liveValidate.bind(this), 300);
+ }
+ // Disable Submit Button if the amount is not valid
+ liveValidate() {
+ const amount = dist_engrid_ENGrid.cleanAmount(this._amount.amount.toString());
+ const activeElement = document.activeElement;
+ if (activeElement && activeElement.tagName === "INPUT" && "name" in activeElement && activeElement.name === "transaction.donationAmt.other" && amount === 0) {
+ // Don't validate if the other amount has focus and the amount is 0
+ return;
+ }
+ this.logger.log(`Amount: ${amount}`);
+ if (amount < this.minAmount) {
+ this.logger.log("Amount is less than min amount: " + this.minAmount);
+ dist_engrid_ENGrid.setError(".en__field--withOther", this.minAmountMessage || "Invalid Amount");
+ } else if (amount > this.maxAmount) {
+ this.logger.log("Amount is greater than max amount: " + this.maxAmount);
+ dist_engrid_ENGrid.setError(".en__field--withOther", this.maxAmountMessage || "Invalid Amount");
+ } else {
+ dist_engrid_ENGrid.removeError(".en__field--withOther");
+ }
+ }
+ setValidationConfigFromEN() {
+ if (!dist_engrid_ENGrid.getOption("UseAmountValidatorFromEN") || !window.EngagingNetworks.validators) {
+ this.logger.log("Not setting validation config from EN.");
+ return;
+ }
+ // Find the amount validator for the donation amount field
+ // It should be of type "AMNT" or "FAMNT" and have
+ // a componentId that matches the donation amount field.
+ this.enAmountValidator = window.EngagingNetworks.validators.find(validator => {
+ var _a;
+ return (validator.type === "FAMNT" || validator.type === "AMNT") && ((_a = document.querySelector(".en__field--" + validator.componentId)) === null || _a === void 0 ? void 0 : _a.classList.contains("en__field--donationAmt"));
});
- const digitalWallets = document.querySelector(".digital-wallets-wrapper");
- if (digitalWallets) {
- // Create a back link for digital wallets
- const backLink = document.createElement("a");
- backLink.classList.add("back-link");
- backLink.innerHTML = `back`;
- backLink.href = "#";
- backLink.addEventListener("click", e => {
- e.preventDefault();
- this.scrollToSection(this.getSectionId(digitalWallets) - 1, 0);
+ if (!this.enAmountValidator || !this.enAmountValidator.format) {
+ return;
+ }
+ this.logger.log(`Detected an amount validator for donation amount on the page:`, this.enAmountValidator);
+ // Static amount validator
+ if (this.enAmountValidator.type === "AMNT") {
+ this.minAmount = Number(this.enAmountValidator.format.split("~")[0]);
+ this.maxAmount = Number(this.enAmountValidator.format.split("~")[1]);
+ this.minAmountMessage = this.enAmountValidator.errorMessage;
+ this.maxAmountMessage = this.enAmountValidator.errorMessage;
+ this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`);
+ }
+ // Frequency-based amount validator
+ if (this.enAmountValidator.type === "FAMNT") {
+ this._frequency.onFrequencyChange.subscribe(freq => {
+ if (!this.enAmountValidator || !this.enAmountValidator.format) return;
+ // In the validator, "onetime" is written as "SINGLE"
+ // Validator format for FAMNT is like SINGLE:10~100000|MONTHLY:5~100000|QUARTERLY:25~100000|ANNUAL:25~100000
+ const frequency = freq === "onetime" ? "SINGLE" : freq.toUpperCase();
+ const validationRange = this.enAmountValidator.format.split("|").find(range => range.startsWith(frequency));
+ if (!validationRange) {
+ this.logger.log(`No validation range found for frequency: ${frequency}`);
+ return;
+ }
+ const amounts = validationRange.split(":")[1].split("~");
+ this.minAmount = Number(amounts[0]);
+ this.maxAmount = Number(amounts[1]);
+ this.minAmountMessage = this.enAmountValidator.errorMessage;
+ this.maxAmountMessage = this.enAmountValidator.errorMessage;
+ this.logger.log(`Frequency changed to ${frequency}, updating min and max amounts`, validationRange);
+ this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`);
});
- digitalWallets.prepend(backLink);
}
}
- // Update section-count based on visible sections
- updateSectionCount() {
- console.log("DonationLightboxForm: updateSectionCount");
- const visibleSections = Array.from(this.sections).filter(section => this.isVisible(section));
- visibleSections.forEach((section, key) => {
- const sectionCount = section.querySelector(".section-count");
- const sectionCurrent = section.querySelector(".section-count__current");
- const sectionTotal = section.querySelector(".section-count__total");
- if (sectionCount && sectionCurrent && sectionTotal) {
- sectionCurrent.innerHTML = key + 1;
- sectionTotal.innerHTML = visibleSections.length;
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/ticker.js
+
+class ticker_Ticker {
+ constructor() {
+ this.shuffleSeed = __webpack_require__(5365);
+ this.items = [];
+ this.tickerElement = document.querySelector(".engrid-ticker");
+ this.logger = new dist_logger_EngridLogger("Ticker", "black", "beige", "π");
+ if (!this.shouldRun()) {
+ this.logger.log("Not running");
+ // If we don't find a ticker, get out
+ return;
+ }
+ const tickerList = document.querySelectorAll(".engrid-ticker li");
+ if (tickerList.length > 0) {
+ for (let i = 0; i < tickerList.length; i++) {
+ this.items.push(tickerList[i].innerText);
}
+ }
+ this.render();
+ return;
+ }
+ // Should we run the script?
+ shouldRun() {
+ return this.tickerElement !== null;
+ }
+ getSeed() {
+ return new Date().getDate() + dist_engrid_ENGrid.getPageID();
+ }
+ // Get Items
+ getItems() {
+ const total = this.tickerElement.getAttribute("data-total") || "50";
+ this.logger.log("Getting " + total + " items");
+ const seed = this.getSeed();
+ const items = this.shuffleSeed.shuffle(this.items, seed);
+ const now = new Date();
+ const hour = now.getHours();
+ const minute = now.getMinutes();
+ let pointer = Math.round((hour * 60 + minute) / 5);
+ if (pointer >= items.length) {
+ pointer = 0;
+ }
+ const ret = items.slice(pointer, pointer + total).reverse();
+ return ret;
+ }
+ // Render
+ render() {
+ var _a, _b, _c;
+ this.logger.log("Rendering");
+ const items = this.getItems();
+ let ticker = document.createElement("div");
+ ticker.classList.add("en__component");
+ ticker.classList.add("en__component--ticker");
+ let str = ``;
+ for (let i = 0; i < items.length; i++) {
+ str += '
' + items[i] + "
";
+ }
+ str = '
' + str + "
";
+ ticker.innerHTML = str;
+ (_b = (_a = this.tickerElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(ticker, this.tickerElement);
+ (_c = this.tickerElement) === null || _c === void 0 ? void 0 : _c.remove();
+ const tickerWidth = document.querySelector(".ticker").offsetWidth.toString();
+ ticker.style.setProperty("--ticker-size", tickerWidth);
+ this.logger.log("Ticker Size: " + ticker.style.getPropertyValue("--ticker-size"));
+ this.logger.log("Ticker Width: " + tickerWidth);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/data-layer.js
+// DataLayer: singleton helper for pushing structured analytics events/vars to window.dataLayer.
+// On load it emits one aggregated event `pageJsonVariablesReady` with:
+// EN_PAGEJSON_* (normalized pageJson), EN_URLPARAM_*, EN_RECURRING_FREQUENCIES (donation pages),
+// and EN_SUBMISSION_SUCCESS_{PAGETYPE} when on the final page.
+// User actions emit: EN_FORM_VALUE_UPDATED (field changes) and submission optβin/out events.
+// Queued endβofβgift events/variables (via addEndOfGiftProcessEvent / addEndOfGiftProcessVariable)
+// are replayed after a successful gift process load.
+// Sensitive payment/bank fields are excluded; selected PII fields are Base64 βhashedβ (btoa β not cryptographic).
+// Replace with a real hash (e.g., SHAβ256) if required.
+var dist_data_layer_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function (resolve) {
+ resolve(value);
});
}
- // Scroll to a section
- scrollToSection(sectionId, fromSectionId) {
- console.log("DonationLightboxForm: scrollToSection", sectionId);
- const section = document.querySelector(`[data-section-id="${sectionId}"]`);
- // Check if we're scrolling to an invisible section
- if (section && !this.isVisible(section)) {
- console.log("DonationLightboxForm: scrollToSection: Section is not visible");
- // If we're scrolling to a section that's not visible, check fromSectionId to see if we're scrolling left or right
- if (fromSectionId > sectionId) {
- // If we're scrolling left, scroll to the previous section
- this.scrollToSection(sectionId - 1, sectionId);
- } else {
- // If we're scrolling right, scroll to the next section
- this.scrollToSection(sectionId + 1, sectionId);
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
}
- return;
}
-
- // If scrolling to the first section, remove upsold attribute and reset upsell section
- if (sectionId == 0 && this.upsellSection) {
- this.upsellSection.removeAttribute("data-upsold");
- this.refreshUpsellSection();
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
+ }
}
- if (this.sections[sectionId]) {
- console.log(section);
- this.currentSectionId = sectionId;
- console.log("Changed current section ID to", sectionId);
- this.sections[sectionId].scrollIntoView({
- behavior: "smooth"
- // block: "start",
- // inline: "center",
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+class data_layer_DataLayer {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("DataLayer", "#f1e5bc", "#009cdc", "π");
+ this.dataLayer = window.dataLayer || [];
+ this._form = events_en_form_EnForm.getInstance();
+ this.encoder = new TextEncoder();
+ this.endOfGiftProcessStorageKey = "ENGRID_END_OF_GIFT_PROCESS_EVENTS";
+ // pageJson entries related to the gift process
+ this.giftFields = ["amount", "currency", "donationLogId", "feeCover", "giftProcess", "paymentType", "receiptNumber", "recurring", "transactionId", "transactionType"];
+ this.excludedFields = [
+ // Credit Card
+ "transaction.ccnumber", "transaction.ccexpire.delimiter", "transaction.ccexpire", "transaction.ccvv", "supporter.creditCardHolderName",
+ // Bank Account
+ "supporter.bankAccountNumber", "supporter.bankAccountType", "transaction.bankname", "supporter.bankRoutingNumber"];
+ this.hashedFields = [
+ // Supporter Address, Phone Numbers, and Address
+ "supporter.emailAddress", "supporter.phoneNumber", "supporter.phoneNumber2", "supporter.address1", "supporter.address2", "supporter.address3",
+ // In Honor/Memory Inform Email and Address
+ "transaction.infemail", "transaction.infadd1", "transaction.infadd2", "transaction.infadd3",
+ // Billing Address
+ "supporter.billingAddress1", "supporter.billingAddress2", "supporter.billingAddress3"];
+ this.retainedEmailField = "supporter.emailAddress";
+ this.retainedAddressFields = ["supporter.address1", "supporter.address2", "supporter.address3"];
+ this.retainedPhoneFields = ["supporter.phoneNumber2", "supporter.phoneNumber"];
+ if (dist_engrid_ENGrid.getOption("RememberMe")) {
+ remember_me_events_RememberMeEvents.getInstance().onLoad.subscribe(hasData => {
+ this.logger.log("Remember me - onLoad", hasData);
+ this.onLoad();
});
+ } else {
+ this.onLoad();
}
+ this._form.onSubmit.subscribe(() => this.onSubmit());
}
- // Scroll to an element's section
- scrollToElement(element) {
- if (element) {
- const sectionId = this.getSectionId(element);
- if (sectionId) {
- const oldSectionId = this.currentSectionId;
- this.currentSectionId = sectionId;
- console.log("Changed current section ID to", sectionId);
- this.scrollToSection(sectionId, oldSectionId);
- }
+ static getInstance() {
+ if (!data_layer_DataLayer.instance) {
+ data_layer_DataLayer.instance = new data_layer_DataLayer();
+ window._dataLayer = data_layer_DataLayer.instance;
}
+ return data_layer_DataLayer.instance;
}
- // Get Element's section id
- getSectionId(element) {
- if (element) {
- return element.closest("[data-section-id]").dataset.sectionId;
+ transformJSON(value) {
+ if (typeof value === "string") {
+ return value.toUpperCase().trim().replace(/\s+/g, "-").replace(/:-/g, "-");
}
- return false;
+ if (typeof value === "boolean") {
+ return value ? "TRUE" : "FALSE";
+ }
+ if (typeof value === "number") {
+ return value; // Preserve numeric type for analytics platforms that infer number vs string
+ }
+ return "";
}
-
- // Validate the form
- // checkCard was added to avoid checking the card if there was a server-side error (the card would be empty)
- validateForm(sectionId = false, checkCard = true) {
- const form = document.querySelector("form.en__component");
-
- // Validate Frequency
- const frequency = form.querySelector("[name='transaction.recurrfreq']:checked");
- const frequencyBlock = form.querySelector(".en__field--recurrfreq");
- const frequencySection = this.getSectionId(frequencyBlock);
- if (this.isDonation) {
- if (sectionId === false || sectionId == frequencySection) {
- if (!frequency || !frequency.value) {
- this.scrollToElement(form.querySelector("[name='transaction.recurrfreq']:checked"));
- this.sendMessage("error", "Please select a frequency");
- if (frequencyBlock) {
- frequencyBlock.classList.add("has-error");
- }
- return false;
- } else {
- if (frequencyBlock) {
- frequencyBlock.classList.remove("has-error");
- }
+ onLoad() {
+ // Collect all data layer variables to push at once
+ const dataLayerData = {};
+ const suppressEcardData = dist_engrid_ENGrid.getPageType() === "ECARD" && dist_engrid_ENGrid.getOption("SuppressPurchaseEcard");
+ if (dist_engrid_ENGrid.getGiftProcess()) {
+ // EN will chain together gift process data on the page json when redirecting from a completed donation to an ecard.
+ // Since the ecard page can be embedded on the thank you page of a donation, this can cause confusion in the data layer with events
+ // firing for both the donation and the ecard on the same page.
+ if (suppressEcardData) {
+ this.logger.log("β Gift process was detected BUT suppressing EN_SUCCESSFUL_DONATION event due to SuppressPurchaseEcard option enabled");
+ window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
+ } else {
+ this.logger.log("EN_SUCCESSFUL_DONATION");
+ this.addEndOfGiftProcessEventsToDataLayer();
+ }
+ }
+ if (window.pageJson) {
+ const pageJson = window.pageJson;
+ for (const property in pageJson) {
+ if (suppressEcardData && this.giftFields.includes(property)) {
+ continue;
}
+ const key = `EN_PAGEJSON_${property.toUpperCase()}`;
+ const value = pageJson[property];
+ dataLayerData[key] = this.transformJSON(value);
}
- // Validate Amount
- const amount = this.getDonationTotal();
- const amountBlock = form.querySelector(".en__field--donationAmt");
- const amountSection = this.getSectionId(amountBlock);
- if (sectionId === false || sectionId == amountSection) {
- if (!amount || amount <= 0) {
- this.scrollToElement(amountBlock);
- this.sendMessage("error", "Please enter a valid amount");
- if (amountBlock) {
- amountBlock.classList.add("has-error");
- }
- return false;
- } else {
- if (amount < 10) {
- this.sendMessage("error", "Amount must be at least $10 - Contact us for assistance");
- if (amountBlock) {
- amountBlock.classList.add("has-error");
- }
- return false;
- }
- const maxAmount = window.EngridOptions?.MaxAmount ?? 30000;
- if (amount > maxAmount) {
- this.sendMessage("error", `Amount must be less than $${maxAmount.toLocaleString()} - Contact us for assistance`);
- if (amountBlock) {
- amountBlock.classList.add("has-error");
- }
- return false;
- }
- if (amountBlock) {
- amountBlock.classList.remove("has-error");
+ if (dist_engrid_ENGrid.getPageCount() === dist_engrid_ENGrid.getPageNumber()) {
+ dataLayerData[`EN_SUBMISSION_SUCCESS_${pageJson.pageType.toUpperCase()}`] = "TRUE";
+ }
+ }
+ const urlParams = new URLSearchParams(window.location.search);
+ urlParams.forEach((value, key) => {
+ dataLayerData[`EN_URLPARAM_${key.toUpperCase()}`] = this.transformJSON(value);
+ });
+ this.addRetainedHashesToDataLayer(dataLayerData);
+ if (dist_engrid_ENGrid.getPageType() === "DONATION") {
+ const recurrFreqEls = document.querySelectorAll('[name="transaction.recurrfreq"]');
+ const recurrValues = [...recurrFreqEls].map(el => el.value);
+ dataLayerData[`EN_RECURRING_FREQUENCIES`] = recurrValues;
+ }
+ // Push all collected variables at once
+ if (Object.keys(dataLayerData).length > 0) {
+ dataLayerData.event = "pageJsonVariablesReady";
+ this.dataLayer.push(dataLayerData);
+ }
+ this.attachEventListeners();
+ }
+ addRetainedHashesToDataLayer(dataLayerData) {
+ if (typeof window === "undefined" || !window.localStorage) {
+ return;
+ }
+ ["EMAIL", "ADDRESS", "PHONE"].forEach(suffix => {
+ const storageKey = `EN_HASH_${suffix}`;
+ const storedValue = window.localStorage.getItem(storageKey);
+ if (storedValue) {
+ dataLayerData[storageKey] = storedValue;
+ }
+ });
+ }
+ onSubmit() {
+ const optIn = document.querySelector(".en__field__item:not(.en__field--question) input[name^='supporter.questions'][type='checkbox']:checked");
+ if (optIn) {
+ this.logger.log("EN_SUBMISSION_WITH_EMAIL_OPTIN");
+ this.dataLayer.push({
+ event: "EN_SUBMISSION_WITH_EMAIL_OPTIN"
+ });
+ } else {
+ this.logger.log("EN_SUBMISSION_WITHOUT_EMAIL_OPTIN");
+ this.dataLayer.push({
+ event: "EN_SUBMISSION_WITHOUT_EMAIL_OPTIN"
+ });
+ }
+ }
+ attachEventListeners() {
+ const textInputs = document.querySelectorAll(".en__component--advrow input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=hidden]):not([unhidden]), .en__component--advrow textarea");
+ textInputs.forEach(el => {
+ el.addEventListener("blur", e => {
+ this.handleFieldValueChange(e.target);
+ });
+ });
+ const radioAndCheckboxInputs = document.querySelectorAll(".en__component--advrow input[type=checkbox], .en__component--advrow input[type=radio]");
+ radioAndCheckboxInputs.forEach(el => {
+ el.addEventListener("change", e => {
+ this.handleFieldValueChange(e.target);
+ });
+ });
+ const selectInputs = document.querySelectorAll(".en__component--advrow select");
+ selectInputs.forEach(el => {
+ el.addEventListener("change", e => {
+ this.handleFieldValueChange(e.target);
+ });
+ });
+ }
+ handleFieldValueChange(el) {
+ var _a, _b, _c;
+ return dist_data_layer_awaiter(this, void 0, void 0, function* () {
+ if (el.value === "" || this.excludedFields.includes(el.name)) return;
+ const value = this.hashedFields.includes(el.name) ? yield this.hash(el.value) : el.value;
+ if (["checkbox", "radio"].includes(el.type)) {
+ if (el.checked) {
+ if (el.name === "en__pg") {
+ //Premium gift handling
+ this.dataLayer.push({
+ event: "EN_FORM_VALUE_UPDATED",
+ enFieldName: el.name,
+ enFieldLabel: "Premium Gift",
+ enFieldValue: (_b = (_a = el.closest(".en__pg__body")) === null || _a === void 0 ? void 0 : _a.querySelector(".en__pg__name")) === null || _b === void 0 ? void 0 : _b.textContent,
+ enProductId: (_c = document.querySelector('[name="transaction.selprodvariantid"]')) === null || _c === void 0 ? void 0 : _c.value
+ });
+ } else {
+ this.dataLayer.push({
+ event: "EN_FORM_VALUE_UPDATED",
+ enFieldName: el.name,
+ enFieldLabel: this.getFieldLabel(el),
+ enFieldValue: value
+ });
}
}
+ return;
}
- // Validate Payment Method
- const paymentType = form.querySelector("#en__field_transaction_paymenttype");
- const ccnumber = form.querySelector("#en__field_transaction_ccnumber");
- const ccnumberBlock = form.querySelector(".en__field--ccnumber");
- const ccnumberSection = this.getSectionId(ccnumberBlock);
- const isDigitalWalletPayment = ["paypal", "paypaltouch", "stripedigitalwallet", "daf"].includes(paymentType.value.toLowerCase());
- const isBankPayment = paymentType.value.toLowerCase() === "ach";
- console.log("DonationLightboxForm: validateForm", ccnumberBlock, ccnumberSection);
- if (!isDigitalWalletPayment && !isBankPayment && (sectionId === false || sectionId == ccnumberSection) && checkCard) {
- if (!paymentType || !paymentType.value) {
- this.scrollToElement(paymentType);
- this.sendMessage("error", "Please add your credit card information");
- if (ccnumberBlock) {
- ccnumberBlock.classList.add("has-error");
+ if (el.name === this.retainedEmailField) {
+ const retainedEmailValue = this.geRetainedFieldsValue("email");
+ const sha256value = yield this.hash(retainedEmailValue);
+ localStorage.setItem(`EN_HASH_EMAIL`, sha256value);
+ this.dataLayer.push({
+ event: "EN_HASH_VALUE_UPDATED",
+ enFieldName: "email",
+ enFieldLabel: this.getFieldLabel(el),
+ enFieldValue: sha256value
+ });
+ return;
+ } else if (this.retainedAddressFields.includes(el.name)) {
+ const retainedAddressValue = this.geRetainedFieldsValue("address");
+ const sha256value = yield this.hash(retainedAddressValue);
+ localStorage.setItem(`EN_HASH_ADDRESS`, sha256value);
+ this.dataLayer.push({
+ event: "EN_HASH_VALUE_UPDATED",
+ enFieldName: "address",
+ enFieldLabel: "Supporter Address",
+ enFieldValue: sha256value
+ });
+ } else if (this.retainedPhoneFields.includes(el.name)) {
+ const retainedPhoneValue = this.geRetainedFieldsValue("phone");
+ const sha256value = yield this.hash(retainedPhoneValue);
+ localStorage.setItem(`EN_HASH_PHONE`, sha256value);
+ this.dataLayer.push({
+ event: "EN_HASH_VALUE_UPDATED",
+ enFieldName: "phone",
+ enFieldLabel: "Supporter Phone",
+ enFieldValue: sha256value
+ });
+ }
+ this.dataLayer.push({
+ event: "EN_FORM_VALUE_UPDATED",
+ enFieldName: el.name,
+ enFieldLabel: this.getFieldLabel(el),
+ enFieldValue: value
+ });
+ });
+ }
+ geRetainedFieldsValue(kind) {
+ switch (kind) {
+ case "email":
+ return dist_engrid_ENGrid.getFieldValue(this.retainedEmailField);
+ case "address":
+ return this.retainedAddressFields.map(field => dist_engrid_ENGrid.getFieldValue(field)).filter(value => value !== "").join("").toLocaleLowerCase().replace(/\s+/g, "");
+ case "phone":
+ // Only return the first phone number found - prioritize phoneNumber2 over phoneNumber and remove non-numeric characters
+ for (const field of this.retainedPhoneFields) {
+ const value = dist_engrid_ENGrid.getFieldValue(field);
+ if (value !== "") {
+ return value.replace(/\D/g, "");
}
- return false;
}
- const ccValid = ccnumber instanceof HTMLInputElement ? !!ccnumber.value : ccnumber.classList.contains("vgs-collect-container__valid");
- if (!ccValid) {
- this.scrollToElement(ccnumber);
- this.sendMessage("error", "Please enter a valid credit card number");
- if (ccnumberBlock) {
- ccnumberBlock.classList.add("has-error");
- }
- return false;
- } else {
- if (ccnumberBlock) {
- ccnumberBlock.classList.remove("has-error");
- }
+ return "";
+ default:
+ return "";
+ }
+ }
+ hash(value) {
+ return dist_data_layer_awaiter(this, void 0, void 0, function* () {
+ const data = this.encoder.encode(value);
+ const hashBuffer = yield crypto.subtle.digest("SHA-256", data);
+ return Array.from(new Uint8Array(hashBuffer)).map(byte => {
+ const hex = byte.toString(16);
+ return hex.length === 1 ? "0" + hex : hex;
+ }).join("");
+ });
+ }
+ getFieldLabel(el) {
+ var _a, _b;
+ return ((_b = (_a = el.closest(".en__field")) === null || _a === void 0 ? void 0 : _a.querySelector("label")) === null || _b === void 0 ? void 0 : _b.textContent) || "";
+ }
+ addEndOfGiftProcessEvent(eventName, eventProperties = {}) {
+ this.storeEndOfGiftProcessData(Object.assign({
+ event: eventName
+ }, eventProperties));
+ }
+ addEndOfGiftProcessVariable(variableName, variableValue = "") {
+ this.storeEndOfGiftProcessData({
+ [variableName.toUpperCase()]: variableValue
+ });
+ }
+ storeEndOfGiftProcessData(data) {
+ const events = this.getEndOfGiftProcessData();
+ events.push(data);
+ window.sessionStorage.setItem(this.endOfGiftProcessStorageKey, JSON.stringify(events));
+ }
+ addEndOfGiftProcessEventsToDataLayer() {
+ this.getEndOfGiftProcessData().forEach(event => {
+ this.dataLayer.push(event);
+ });
+ window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
+ }
+ getEndOfGiftProcessData() {
+ let eventsData = window.sessionStorage.getItem(this.endOfGiftProcessStorageKey);
+ return !eventsData ? [] : JSON.parse(eventsData);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/data-replace.js
+// This script is used to replace merge tags in the EN Blocks of the page.
+// It searches for HTML elements containing the data to be replaced and replaces it.
+// The data to be replaced is passed as URL parameters, example: ?engrid_data[key]=value.
+// The merge tag, if found, is replaced with the value from the URL parameter.
+// If no value is found, the default value is used.
+// The default value is the value inside the merge tag, example: {engrid_data~key~default}.
+// If no default value is set, an empty string is used.
+
+class data_replace_DataReplace {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("DataReplace", "#333333", "#00f3ff", "‡οΈ");
+ this.enElements = new Array();
+ this.searchElements();
+ if (!this.shouldRun()) return;
+ this.logger.log("Elements Found:", this.enElements);
+ this.replaceAll();
+ }
+ /**
+ * Searches for HTML elements containing the data to be replaced.
+ */
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field
+ `);
+ if (enElements.length > 0) {
+ enElements.forEach(item => {
+ if (item instanceof HTMLElement && item.innerHTML.includes("{engrid_data~")) {
+ this.enElements.push(item);
}
- const ccexpire = form.querySelector("#en__field_transaction_ccexpire");
- const ccexpireBlock = form.querySelector(".en__field--ccexpire");
- let ccexpireValid = ccexpire ? ccexpire.classList.contains("vgs-collect-container__valid") : false;
- if (!ccexpireValid) {
- this.scrollToElement(ccexpire);
- this.sendMessage("error", "Please enter a valid expiration date");
- if (ccexpireBlock) {
- ccexpireBlock.classList.add("has-error");
- }
- return false;
+ });
+ }
+ }
+ /**
+ * Checks if there are elements to be replaced.
+ * @returns True if there are elements to be replaced, false otherwise.
+ */
+ shouldRun() {
+ return this.enElements.length > 0;
+ }
+ /**
+ * Replaces all occurrences of data in the HTML elements.
+ */
+ replaceAll() {
+ const regEx = /{engrid_data~\[([\w-]+)\]~?\[?(.+?)?\]?}/g;
+ this.enElements.forEach(item => {
+ const array = item.innerHTML.matchAll(regEx);
+ for (const match of array) {
+ this.replaceItem(item, match);
+ }
+ });
+ dist_engrid_ENGrid.setBodyData("merge-tags-processed", "");
+ }
+ /**
+ * Replaces a specific data item in the given HTML element.
+ * @param where The HTML element where the replacement should occur.
+ * @param item The matched data item.
+ * @param key The key of the data item.
+ * @param defaultValue The default value to use if the data item is not found.
+ */
+ replaceItem(where, [item, key, defaultValue]) {
+ var _a;
+ let value = (_a = dist_engrid_ENGrid.getUrlParameter(`engrid_data[${key}]`)) !== null && _a !== void 0 ? _a : defaultValue;
+ if (typeof value === "string") {
+ value = value.replace(/\r?\\n|\n|\r/g, " ");
+ } else {
+ value = "";
+ }
+ this.logger.log("Replacing", key, value);
+ where.innerHTML = where.innerHTML.replace(item, value);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/data-hide.js
+// Hides elements based on URL arguments.
+//
+// The DataHide class is used to hide elements based on URL arguments.
+// It retrieves the elements to hide from the URL arguments and hides them.
+// If no elements are found, the constructor returns early.
+// Otherwise, it logs the found elements and hides them.
+
+class data_hide_DataHide {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("DataHide", "#333333", "#f0f0f0", "π");
+ this.enElements = new Array();
+ this.logger.log("Constructor");
+ this.enElements = dist_engrid_ENGrid.getUrlParameter("engrid_hide[]");
+ if (!this.enElements || this.enElements.length === 0) {
+ this.logger.log("No Elements Found");
+ return;
+ }
+ this.logger.log("Elements Found:", this.enElements);
+ this.hideAll();
+ }
+ /**
+ * Hides all the elements based on the URL arguments.
+ */
+ hideAll() {
+ this.enElements.forEach(element => {
+ const item = Object.keys(element)[0];
+ const type = Object.values(element)[0];
+ this.hideItem(item, type);
+ });
+ return;
+ }
+ /**
+ * Hides a specific element based on the item and type.
+ * @param item - The item to hide (ID or class name).
+ * @param type - The type of the item (either "id" or "class").
+ */
+ hideItem(item, type) {
+ const regEx = /engrid_hide\[([\w-]+)\]/g;
+ const itemData = [...item.matchAll(regEx)].map(match => match[1])[0];
+ switch (type) {
+ case "id":
+ const element = document.getElementById(itemData);
+ if (element) {
+ this.logger.log("Hiding By ID", itemData, element);
+ element.setAttribute("hidden-via-url-argument", "");
} else {
- if (ccexpireBlock) {
- ccexpireBlock.classList.remove("has-error");
- }
+ this.logger.error("Element Not Found By ID", itemData);
}
- const cvv = form.querySelector("#en__field_transaction_ccvv");
- const cvvBlock = form.querySelector(".en__field--ccvv");
- const cvvValid = cvv instanceof HTMLInputElement ? !!cvv.value : cvv.classList.contains("vgs-collect-container__valid");
- if (!cvvValid) {
- this.scrollToElement(cvv);
- this.sendMessage("error", "Please enter a valid CVV");
- if (cvvBlock) {
- cvvBlock.classList.add("has-error");
+ break;
+ case "class":
+ default:
+ const elements = document.getElementsByClassName(itemData);
+ if (elements.length > 0) {
+ for (let i = 0; i < elements.length; i++) {
+ this.logger.log("Hiding By Class", itemData, elements[i]);
+ elements[i].setAttribute("hidden-via-url-argument", "");
}
- return false;
} else {
- if (cvvBlock) {
- cvvBlock.classList.remove("has-error");
- }
+ this.logger.log("No Elements Found By Class", itemData);
}
- }
- // Validate Bank Details
- if (paymentType && paymentType.value.toLowerCase() === "ach") {
- const routingNumber = form.querySelector("#en__field_supporter_bankRoutingNumber");
- if (!routingNumber) return;
- const bankSection = this.getSectionId(routingNumber);
- if (sectionId === false || sectionId == bankSection) {
- // All form fields from this section are mandatory if the payment type is ACH
- const mandatoryFields = this.sections[bankSection].querySelectorAll("input:not([type='hidden'])");
- let hasError = false;
- mandatoryFields.forEach(field => {
- if (hasError) {
- return;
+ break;
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/add-name-to-message.js
+/*
+ Adds first and last name when First Name and Last Name fields lose focus if name shortcodes aren't present
+*/
+
+class add_name_to_message_AddNameToMessage {
+ constructor() {
+ if (!this.shouldRun()) {
+ // Don't run the script if the page isn't email to target
+ return;
+ }
+ this.replaceNameShortcode("#en__field_supporter_firstName", "#en__field_supporter_lastName");
+ }
+ shouldRun() {
+ return dist_engrid_ENGrid.getPageType() === "EMAILTOTARGET";
+ }
+ replaceNameShortcode(fName, lName) {
+ const firstName = document.querySelector(fName);
+ const lastName = document.querySelector(lName);
+ let message = document.querySelector('[name="contact.message"]');
+ let addedFirstName = false;
+ let addedLastName = false;
+ if (message) {
+ if (message.value.includes("{user_data~First Name") || message.value.includes("{user_data~Last Name")) {
+ return;
+ } else {
+ if (!message.value.includes("{user_data~First Name") && firstName) {
+ firstName.addEventListener("blur", e => {
+ const target = e.target;
+ if (message && !addedFirstName) {
+ addedFirstName = true;
+ message.value = message.value.concat("\n" + target.value);
}
- const fieldElement = field;
- const fieldLabel = field.closest(".en__field").querySelector(".en__field__label");
- if (!fieldElement.value) {
- this.scrollToElement(fieldElement);
- this.sendMessage("error", "Please enter " + fieldLabel.textContent);
- fieldElement.closest(".en__field").classList.add("has-error");
- hasError = true;
- return false;
- } else if (fieldElement.type === "checkbox" && !fieldElement.checked) {
- this.scrollToElement(fieldElement);
- this.sendMessage("error", "Please check the agreement checkbox");
- fieldElement.closest(".en__field").classList.add("has-error");
- hasError = true;
- return false;
- } else {
- fieldElement.closest(".en__field").classList.remove("has-error");
+ });
+ }
+ if (!message.value.includes("{user_data~Last Name") && lastName) {
+ lastName.addEventListener("blur", e => {
+ const target = e.target;
+ if (message && !addedLastName) {
+ addedLastName = true;
+ message.value = message.value.concat(" " + target.value);
}
});
- if (hasError) {
- return false;
- }
}
}
}
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/expand-region-name.js
+// Populates hidden supporter field "Region Long Format" with expanded name (e.g FL becomes Florida)
- // Validate Recaptcha
- const recaptchaResponse = form.querySelector("#g-recaptcha-response");
- const recapchaSection = this.getSectionId(recaptchaResponse);
- if (recaptchaResponse && recaptchaResponse.value === "" && (sectionId === false || sectionId == recapchaSection)) {
- this.scrollToElement(recaptchaResponse);
- this.sendMessage("error", "Please complete the reCAPTCHA");
- return false;
- }
- // Validate Everything else
- const mandatoryFields = form.querySelectorAll(".en__mandatory");
- let hasError = false;
- mandatoryFields.forEach(field => {
- if (hasError) {
- return;
+class expand_region_name_ExpandRegionName {
+ constructor() {
+ this._form = events_en_form_EnForm.getInstance();
+ this.logger = new dist_logger_EngridLogger("ExpandRegionName", "#333333", "#00eb65", "π");
+ if (this.shouldRun()) {
+ const expandedRegionField = dist_engrid_ENGrid.getOption("RegionLongFormat");
+ console.log("expandedRegionField", expandedRegionField);
+ const hiddenRegion = document.querySelector(`[name="${expandedRegionField}"]`);
+ if (!hiddenRegion) {
+ this.logger.log(`CREATED field ${expandedRegionField}`);
+ dist_engrid_ENGrid.createHiddenInput(expandedRegionField);
}
- const fieldElement = field.querySelector(".en__field__input");
- const fieldLabel = field.querySelector(".en__field__label");
- const fieldSection = this.getSectionId(fieldElement);
- if (sectionId === false || sectionId == fieldSection) {
- if (!fieldElement.value) {
- this.scrollToElement(fieldElement);
- this.sendMessage("error", "Please enter " + fieldLabel.textContent);
- field.classList.add("has-error");
- hasError = true;
- return false;
- } else {
- field.classList.remove("has-error");
- }
- // If it's the e-mail field, check if it's a valid email
- if (fieldElement.name === "supporter.emailAddress" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(fieldElement.value) === false) {
- this.scrollToElement(fieldElement);
- this.sendMessage("error", "Please enter a valid email address");
- field.classList.add("has-error");
- hasError = true;
- return false;
+ this._form.onValidate.subscribe(() => this.expandRegion());
+ }
+ }
+ shouldRun() {
+ return !!dist_engrid_ENGrid.getOption("RegionLongFormat");
+ }
+ expandRegion() {
+ if (!this._form.validate) return;
+ const userRegion = document.querySelector('[name="supporter.region"]'); // User entered region on the page
+ const expandedRegionField = dist_engrid_ENGrid.getOption("RegionLongFormat");
+ const hiddenRegion = document.querySelector(`[name="${expandedRegionField}"]`); // Hidden region long form field
+ if (!userRegion) {
+ this.logger.log("No region field to populate the hidden region field with");
+ return; // Don't populate hidden region field if user region field isn't on page
+ }
+ if (userRegion.tagName === "SELECT" && "options" in userRegion) {
+ const regionValue = userRegion.options[userRegion.selectedIndex].innerText;
+ hiddenRegion.value = regionValue;
+ this.logger.log("Populated field", hiddenRegion.value);
+ } else if (userRegion.tagName === "INPUT") {
+ const regionValue = userRegion.value;
+ hiddenRegion.value = regionValue;
+ this.logger.log("Populated field", hiddenRegion.value);
+ }
+ return true;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/url-to-form.js
+// Component that allows to set a field value from URL parameters
+// Workflow:
+// 1. Loop through all the URL parameters
+// 2. Check if there's a match with the field name
+// 3. If there's a match AND the field is empty, set the value
+
+class url_to_form_UrlToForm {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("UrlToForm", "white", "magenta", "π");
+ this.urlParams = new URLSearchParams(document.location.search);
+ if (!this.shouldRun()) return;
+ this.urlParams.forEach((value, key) => {
+ const field = document.getElementsByName(key)[0];
+ if (field) {
+ if (field.type === "checkbox") {
+ field.checked = value === "true" || value === "Y" || value === "1";
+ dist_engrid_ENGrid.setFieldValue(key, field.checked);
+ this.logger.log(`Set: ${key} to ${field.checked}`);
+ } else if (!["text", "textarea", "email"].includes(field.type) || !field.value) {
+ dist_engrid_ENGrid.setFieldValue(key, value);
+ this.logger.log(`Set: ${key} to ${value}`);
}
}
});
- if (hasError) {
- return false;
- }
- // Validate City Characters Limit
- const city = form.querySelector("#en__field_supporter_city");
- const cityBlock = form.querySelector(".en__field--city");
- if (!this.checkCharsLimit("#en__field_supporter_city", 100)) {
- this.scrollToElement(city);
- this.sendMessage("error", "This field only allows up to 100 characters");
- if (cityBlock) {
- cityBlock.classList.add("has-error");
- }
- return false;
- } else {
- if (cityBlock) {
- cityBlock.classList.remove("has-error");
+ }
+ shouldRun() {
+ return !!document.location.search && this.hasFields();
+ }
+ hasFields() {
+ const ret = [...this.urlParams.keys()].map(key => {
+ return document.getElementsByName(key).length > 0;
+ });
+ return ret.includes(true);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/required-if-visible.js
+
+class required_if_visible_RequiredIfVisible {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("RequiredIfVisible", "#FFFFFF", "#811212", "π₯");
+ this._form = events_en_form_EnForm.getInstance();
+ this.requiredIfVisibleElements = document.querySelectorAll(`
+ .i-required .en__field,
+ .i1-required .en__field:nth-of-type(1),
+ .i2-required .en__field:nth-of-type(2),
+ .i3-required .en__field:nth-of-type(3),
+ .i4-required .en__field:nth-of-type(4),
+ .i5-required .en__field:nth-of-type(5),
+ .i6-required .en__field:nth-of-type(6),
+ .i7-required .en__field:nth-of-type(7),
+ .i8-required .en__field:nth-of-type(8),
+ .i9-required .en__field:nth-of-type(9),
+ .i10-required .en__field:nth-of-type(10),
+ .i11-required .en__field:nth-of-type(11)
+ `);
+ if (!this.shouldRun()) return;
+ this._form.onValidate.subscribe(this.validate.bind(this));
+ }
+ shouldRun() {
+ return this.requiredIfVisibleElements.length > 0;
+ }
+ validate() {
+ // We're converting the NodeListOf to an Array
+ // because we need to reverse the order of the elements so the last error
+ // is the highest element to get focus()
+ Array.from(this.requiredIfVisibleElements).reverse().forEach(field => {
+ dist_engrid_ENGrid.removeError(field);
+ if (dist_engrid_ENGrid.isVisible(field)) {
+ this.logger.log(`${field.getAttribute("class")} is visible`);
+ const fieldElement = field.querySelector("input:not([type=hidden]) , select, textarea");
+ if (fieldElement && fieldElement.closest("[data-unhidden]") === null && !dist_engrid_ENGrid.getFieldValue(fieldElement.getAttribute("name"))) {
+ const fieldLabel = field.querySelector(".en__field__label");
+ if (fieldLabel) {
+ this.logger.log(`${fieldLabel.innerText} is required`);
+ window.setTimeout(() => {
+ dist_engrid_ENGrid.setError(field, `${fieldLabel.innerText} is required`);
+ }, 100);
+ } else {
+ this.logger.log(`${fieldElement.getAttribute("name")} is required`);
+ window.setTimeout(() => {
+ dist_engrid_ENGrid.setError(field, `This field is required`);
+ }, 100);
+ }
+ fieldElement.focus();
+ this._form.validate = false;
+ }
}
- }
- // Validate Street Address line 1 Characters Limit
- const streetAddress1 = form.querySelector("#en__field_supporter_address1");
- const streetAddress1Block = form.querySelector(".en__field--address1");
- if (!this.checkCharsLimit("#en__field_supporter_address1", 35)) {
- this.scrollToElement(streetAddress1);
- this.sendMessage("error", "This field only allows up to 35 characters. Longer street addresses can be broken up between Lines 1 and 2.");
- if (streetAddress1Block) {
- streetAddress1Block.classList.add("has-error");
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/tidycontact.js
+var dist_tidycontact_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function (resolve) {
+ resolve(value);
+ });
+ }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
}
- return false;
- } else {
- if (streetAddress1Block) {
- streetAddress1Block.classList.remove("has-error");
+ }
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
}
}
- // Validate Street Address line 2 Characters Limit
- const streetAddress2 = form.querySelector("#en__field_supporter_address2");
- const streetAddress2Block = form.querySelector(".en__field--address2");
- if (!this.checkCharsLimit("#en__field_supporter_address2", 35)) {
- this.scrollToElement(streetAddress2);
- this.sendMessage("error", "This field only allows up to 35 characters. Longer street addresses can be broken up between Lines 1 and 2.");
- if (streetAddress2Block) {
- streetAddress2Block.classList.add("has-error");
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+class tidycontact_TidyContact {
+ constructor() {
+ var _a, _b, _c, _d, _e;
+ this.logger = new dist_logger_EngridLogger("TidyContact", "#FFFFFF", "#4d9068", "π§");
+ this.endpoint = "https://api.tidycontact.io";
+ this.wasCalled = false; // True if the API endpoint was called
+ this.httpStatus = 0;
+ this.timeout = 5; // Seconds to API Timeout
+ this.isDirty = false; // True if the address was changed by the user
+ this._form = events_en_form_EnForm.getInstance();
+ this.countries_list = [["Afghanistan", "af", "93", "070 123 4567"], ["Albania", "al", "355", "067 212 3456"], ["Algeria", "dz", "213", "0551 23 45 67"], ["American Samoa", "as", "1", "(684) 733-1234"], ["Andorra", "ad", "376", "312 345"], ["Angola", "ao", "244", "923 123 456"], ["Anguilla", "ai", "1", "(264) 235-1234"], ["Antigua and Barbuda", "ag", "1", "(268) 464-1234"], ["Argentina", "ar", "54", "011 15-2345-6789"], ["Armenia", "am", "374", "077 123456"], ["Aruba", "aw", "297", "560 1234"], ["Australia", "au", "61", "0412 345 678"], ["Austria", "at", "43", "0664 123456"], ["Azerbaijan", "az", "994", "040 123 45 67"], ["Bahamas", "bs", "1", "(242) 359-1234"], ["Bahrain", "bh", "973", "3600 1234"], ["Bangladesh", "bd", "880", "01812-345678"], ["Barbados", "bb", "1", "(246) 250-1234"], ["Belarus", "by", "375", "8 029 491-19-11"], ["Belgium", "be", "32", "0470 12 34 56"], ["Belize", "bz", "501", "622-1234"], ["Benin", "bj", "229", "90 01 12 34"], ["Bermuda", "bm", "1", "(441) 370-1234"], ["Bhutan", "bt", "975", "17 12 34 56"], ["Bolivia", "bo", "591", "71234567"], ["Bosnia and Herzegovina", "ba", "387", "061 123 456"], ["Botswana", "bw", "267", "71 123 456"], ["Brazil", "br", "55", "(11) 96123-4567"], ["British Indian Ocean Territory", "io", "246", "380 1234"], ["British Virgin Islands", "vg", "1", "(284) 300-1234"], ["Brunei", "bn", "673", "712 3456"], ["Bulgaria", "bg", "359", "048 123 456"], ["Burkina Faso", "bf", "226", "70 12 34 56"], ["Burundi", "bi", "257", "79 56 12 34"], ["Cambodia", "kh", "855", "091 234 567"], ["Cameroon", "cm", "237", "6 71 23 45 67"], ["Canada", "ca", "1", "(506) 234-5678"], ["Cape Verde", "cv", "238", "991 12 34"], ["Caribbean Netherlands", "bq", "599", "318 1234"], ["Cayman Islands", "ky", "1", "(345) 323-1234"], ["Central African Republic", "cf", "236", "70 01 23 45"], ["Chad", "td", "235", "63 01 23 45"], ["Chile", "cl", "56", "(2) 2123 4567"], ["China", "cn", "86", "131 2345 6789"], ["Christmas Island", "cx", "61", "0412 345 678"], ["Cocos Islands", "cc", "61", "0412 345 678"], ["Colombia", "co", "57", "321 1234567"], ["Comoros", "km", "269", "321 23 45"], ["Congo", "cd", "243", "0991 234 567"], ["Congo", "cg", "242", "06 123 4567"], ["Cook Islands", "ck", "682", "71 234"], ["Costa Rica", "cr", "506", "8312 3456"], ["CΓ΄te dβIvoire", "ci", "225", "01 23 45 6789"], ["Croatia", "hr", "385", "092 123 4567"], ["Cuba", "cu", "53", "05 1234567"], ["CuraΓ§ao", "cw", "599", "9 518 1234"], ["Cyprus", "cy", "357", "96 123456"], ["Czech Republic", "cz", "420", "601 123 456"], ["Denmark", "dk", "45", "32 12 34 56"], ["Djibouti", "dj", "253", "77 83 10 01"], ["Dominica", "dm", "1", "(767) 225-1234"], ["Dominican Republic", "do", "1", "(809) 234-5678"], ["Ecuador", "ec", "593", "099 123 4567"], ["Egypt", "eg", "20", "0100 123 4567"], ["El Salvador", "sv", "503", "7012 3456"], ["Equatorial Guinea", "gq", "240", "222 123 456"], ["Eritrea", "er", "291", "07 123 456"], ["Estonia", "ee", "372", "5123 4567"], ["Eswatini", "sz", "268", "7612 3456"], ["Ethiopia", "et", "251", "091 123 4567"], ["Falkland Islands", "fk", "500", "51234"], ["Faroe Islands", "fo", "298", "211234"], ["Fiji", "fj", "679", "701 2345"], ["Finland", "fi", "358", "041 2345678"], ["France", "fr", "33", "06 12 34 56 78"], ["French Guiana", "gf", "594", "0694 20 12 34"], ["French Polynesia", "pf", "689", "87 12 34 56"], ["Gabon", "ga", "241", "06 03 12 34"], ["Gambia", "gm", "220", "301 2345"], ["Georgia", "ge", "995", "555 12 34 56"], ["Germany", "de", "49", "01512 3456789"], ["Ghana", "gh", "233", "023 123 4567"], ["Gibraltar", "gi", "350", "57123456"], ["Greece", "gr", "30", "691 234 5678"], ["Greenland", "gl", "299", "22 12 34"], ["Grenada", "gd", "1", "(473) 403-1234"], ["Guadeloupe", "gp", "590", "0690 00 12 34"], ["Guam", "gu", "1", "(671) 300-1234"], ["Guatemala", "gt", "502", "5123 4567"], ["Guernsey", "gg", "44", "07781 123456"], ["Guinea", "gn", "224", "601 12 34 56"], ["Guinea-Bissau", "gw", "245", "955 012 345"], ["Guyana", "gy", "592", "609 1234"], ["Haiti", "ht", "509", "34 10 1234"], ["Honduras", "hn", "504", "9123-4567"], ["Hong Kong", "hk", "852", "5123 4567"], ["Hungary", "hu", "36", "06 20 123 4567"], ["Iceland", "is", "354", "611 1234"], ["India", "in", "91", "081234 56789"], ["Indonesia", "id", "62", "0812-345-678"], ["Iran", "ir", "98", "0912 345 6789"], ["Iraq", "iq", "964", "0791 234 5678"], ["Ireland", "ie", "353", "085 012 3456"], ["Isle of Man", "im", "44", "07924 123456"], ["Israel", "il", "972", "050-234-5678"], ["Italy", "it", "39", "312 345 6789"], ["Jamaica", "jm", "1", "(876) 210-1234"], ["Japan", "jp", "81", "090-1234-5678"], ["Jersey", "je", "44", "07797 712345"], ["Jordan", "jo", "962", "07 9012 3456"], ["Kazakhstan", "kz", "7", "8 (771) 000 9998"], ["Kenya", "ke", "254", "0712 123456"], ["Kiribati", "ki", "686", "72001234"], ["Kosovo", "xk", "383", "043 201 234"], ["Kuwait", "kw", "965", "500 12345"], ["Kyrgyzstan", "kg", "996", "0700 123 456"], ["Laos", "la", "856", "020 23 123 456"], ["Latvia", "lv", "371", "21 234 567"], ["Lebanon", "lb", "961", "71 123 456"], ["Lesotho", "ls", "266", "5012 3456"], ["Liberia", "lr", "231", "077 012 3456"], ["Libya", "ly", "218", "091-2345678"], ["Liechtenstein", "li", "423", "660 234 567"], ["Lithuania", "lt", "370", "(8-612) 34567"], ["Luxembourg", "lu", "352", "628 123 456"], ["Macau", "mo", "853", "6612 3456"], ["North Macedonia", "mk", "389", "072 345 678"], ["Madagascar", "mg", "261", "032 12 345 67"], ["Malawi", "mw", "265", "0991 23 45 67"], ["Malaysia", "my", "60", "012-345 6789"], ["Maldives", "mv", "960", "771-2345"], ["Mali", "ml", "223", "65 01 23 45"], ["Malta", "mt", "356", "9696 1234"], ["Marshall Islands", "mh", "692", "235-1234"], ["Martinique", "mq", "596", "0696 20 12 34"], ["Mauritania", "mr", "222", "22 12 34 56"], ["Mauritius", "mu", "230", "5251 2345"], ["Mayotte", "yt", "262", "0639 01 23 45"], ["Mexico", "mx", "52", "222 123 4567"], ["Micronesia", "fm", "691", "350 1234"], ["Moldova", "md", "373", "0621 12 345"], ["Monaco", "mc", "377", "06 12 34 56 78"], ["Mongolia", "mn", "976", "8812 3456"], ["Montenegro", "me", "382", "067 622 901"], ["Montserrat", "ms", "1", "(664) 492-3456"], ["Morocco", "ma", "212", "0650-123456"], ["Mozambique", "mz", "258", "82 123 4567"], ["Myanmar", "mm", "95", "09 212 3456"], ["Namibia", "na", "264", "081 123 4567"], ["Nauru", "nr", "674", "555 1234"], ["Nepal", "np", "977", "984-1234567"], ["Netherlands", "nl", "31", "06 12345678"], ["New Caledonia", "nc", "687", "75.12.34"], ["New Zealand", "nz", "64", "021 123 4567"], ["Nicaragua", "ni", "505", "8123 4567"], ["Niger", "ne", "227", "93 12 34 56"], ["Nigeria", "ng", "234", "0802 123 4567"], ["Niue", "nu", "683", "888 4012"], ["Norfolk Island", "nf", "672", "3 81234"], ["North Korea", "kp", "850", "0192 123 4567"], ["Northern Mariana Islands", "mp", "1", "(670) 234-5678"], ["Norway", "no", "47", "406 12 345"], ["Oman", "om", "968", "9212 3456"], ["Pakistan", "pk", "92", "0301 2345678"], ["Palau", "pw", "680", "620 1234"], ["Palestine", "ps", "970", "0599 123 456"], ["Panama", "pa", "507", "6123-4567"], ["Papua New Guinea", "pg", "675", "7012 3456"], ["Paraguay", "py", "595", "0961 456789"], ["Peru", "pe", "51", "912 345 678"], ["Philippines", "ph", "63", "0905 123 4567"], ["Poland", "pl", "48", "512 345 678"], ["Portugal", "pt", "351", "912 345 678"], ["Puerto Rico", "pr", "1", "(787) 234-5678"], ["Qatar", "qa", "974", "3312 3456"], ["RΓ©union", "re", "262", "0692 12 34 56"], ["Romania", "ro", "40", "0712 034 567"], ["Russia", "ru", "7", "8 (912) 345-67-89"], ["Rwanda", "rw", "250", "0720 123 456"], ["Saint BarthΓ©lemy", "bl", "590", "0690 00 12 34"], ["Saint Helena", "sh", "290", "51234"], ["Saint Kitts and Nevis", "kn", "1", "(869) 765-2917"], ["Saint Lucia", "lc", "1", "(758) 284-5678"], ["Saint Martin", "mf", "590", "0690 00 12 34"], ["Saint Pierre and Miquelon", "pm", "508", "055 12 34"], ["Saint Vincent and the Grenadines", "vc", "1", "(784) 430-1234"], ["Samoa", "ws", "685", "72 12345"], ["San Marino", "sm", "378", "66 66 12 12"], ["SΓ£o TomΓ© and PrΓncipe", "st", "239", "981 2345"], ["Saudi Arabia", "sa", "966", "051 234 5678"], ["Senegal", "sn", "221", "70 123 45 67"], ["Serbia", "rs", "381", "060 1234567"], ["Seychelles", "sc", "248", "2 510 123"], ["Sierra Leone", "sl", "232", "(025) 123456"], ["Singapore", "sg", "65", "8123 4567"], ["Sint Maarten", "sx", "1", "(721) 520-5678"], ["Slovakia", "sk", "421", "0912 123 456"], ["Slovenia", "si", "386", "031 234 567"], ["Solomon Islands", "sb", "677", "74 21234"], ["Somalia", "so", "252", "7 1123456"], ["South Africa", "za", "27", "071 123 4567"], ["South Korea", "kr", "82", "010-2000-0000"], ["South Sudan", "ss", "211", "0977 123 456"], ["Spain", "es", "34", "612 34 56 78"], ["Sri Lanka", "lk", "94", "071 234 5678"], ["Sudan", "sd", "249", "091 123 1234"], ["Suriname", "sr", "597", "741-2345"], ["Svalbard and Jan Mayen", "sj", "47", "412 34 567"], ["Sweden", "se", "46", "070-123 45 67"], ["Switzerland", "ch", "41", "078 123 45 67"], ["Syria", "sy", "963", "0944 567 890"], ["Taiwan", "tw", "886", "0912 345 678"], ["Tajikistan", "tj", "992", "917 12 3456"], ["Tanzania", "tz", "255", "0621 234 567"], ["Thailand", "th", "66", "081 234 5678"], ["Timor-Leste", "tl", "670", "7721 2345"], ["Togo", "tg", "228", "90 11 23 45"], ["Tokelau", "tk", "690", "7290"], ["Tonga", "to", "676", "771 5123"], ["Trinidad and Tobago", "tt", "1", "(868) 291-1234"], ["Tunisia", "tn", "216", "20 123 456"], ["Turkey", "tr", "90", "0501 234 56 78"], ["Turkmenistan", "tm", "993", "8 66 123456"], ["Turks and Caicos Islands", "tc", "1", "(649) 231-1234"], ["Tuvalu", "tv", "688", "90 1234"], ["U.S. Virgin Islands", "vi", "1", "(340) 642-1234"], ["Uganda", "ug", "256", "0712 345678"], ["Ukraine", "ua", "380", "050 123 4567"], ["United Arab Emirates", "ae", "971", "050 123 4567"], ["United Kingdom", "gb", "44", "07400 123456"], ["United States", "us", "1", "(201) 555-0123"], ["Uruguay", "uy", "598", "094 231 234"], ["Uzbekistan", "uz", "998", "8 91 234 56 78"], ["Vanuatu", "vu", "678", "591 2345"], ["Vatican City", "va", "39", "312 345 6789"], ["Venezuela", "ve", "58", "0412-1234567"], ["Vietnam", "vn", "84", "091 234 56 78"], ["Wallis and Futuna", "wf", "681", "82 12 34"], ["Western Sahara", "eh", "212", "0650-123456"], ["Yemen", "ye", "967", "0712 345 678"], ["Zambia", "zm", "260", "095 5123456"], ["Zimbabwe", "zw", "263", "071 234 5678"], ["Γ
land Islands", "ax", "358", "041 2345678"]];
+ this.countries_dropdown = null;
+ this.country_ip = null;
+ this.options = dist_engrid_ENGrid.getOption("TidyContact");
+ if (this.options === false || !((_a = this.options) === null || _a === void 0 ? void 0 : _a.cid)) return;
+ if (!this.shouldRun()) {
+ this.logger.log("TidyContact is disabled on this page type");
+ return;
+ }
+ this.loadOptions();
+ if (!this.hasAddressFields() && !this.phoneEnabled()) {
+ this.logger.log("No address fields found");
+ return;
+ }
+ this.createFields();
+ this.addEventListeners();
+ if (dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && !window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed() && dist_engrid_ENGrid.getFieldValue((_c = (_b = this.options) === null || _b === void 0 ? void 0 : _b.address_fields) === null || _c === void 0 ? void 0 : _c.address1) != "") {
+ this.logger.log("Address Field is not empty");
+ this.isDirty = true;
+ }
+ if (this.phoneEnabled()) {
+ this.createPhoneFields();
+ this.createPhoneMarginVariable();
+ this.logger.log("Phone Standardization is enabled");
+ if (this.countryDropDownEnabled()) {
+ this.renderFlagsDropDown();
}
- return false;
- } else {
- if (streetAddress2Block) {
- streetAddress2Block.classList.remove("has-error");
+ const phoneField = dist_engrid_ENGrid.getField((_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.address_fields) === null || _e === void 0 ? void 0 : _e.phone);
+ if (phoneField) {
+ phoneField.addEventListener("keyup", e => {
+ this.handlePhoneInputKeydown(e);
+ });
+ this.setDefaultPhoneCountry();
}
}
- // Validate Zip Code Characters Limit
- const zipCode = form.querySelector("#en__field_supporter_postcode");
- const zipCodeBlock = form.querySelector(".en__field--postcode");
- if (!this.checkCharsLimit("#en__field_supporter_postcode", 20)) {
- this.scrollToElement(zipCode);
- this.sendMessage("error", "This field only allows up to 20 characters");
- if (zipCodeBlock) {
- zipCodeBlock.classList.add("has-error");
+ }
+ shouldRun() {
+ if (this.options && this.options.page_types && this.options.page_types.length > 0) {
+ return this.options.page_types.includes(dist_engrid_ENGrid.getPageType());
+ }
+ return true;
+ }
+ loadOptions() {
+ var _a, _b, _c, _d;
+ if (this.options) {
+ if (!this.options.address_fields) {
+ this.options.address_fields = {
+ address1: "supporter.address1",
+ address2: "supporter.address2",
+ address3: "supporter.address3",
+ city: "supporter.city",
+ region: "supporter.region",
+ postalCode: "supporter.postcode",
+ country: "supporter.country",
+ phone: "supporter.phoneNumber2" // Phone field
+ };
}
- return false;
- } else {
- if (zipCodeBlock) {
- zipCodeBlock.classList.remove("has-error");
+ this.options.address_enable = (_a = this.options.address_enable) !== null && _a !== void 0 ? _a : true;
+ if (this.options.phone_enable) {
+ this.options.phone_flags = (_b = this.options.phone_flags) !== null && _b !== void 0 ? _b : true;
+ this.options.phone_country_from_ip = (_c = this.options.phone_country_from_ip) !== null && _c !== void 0 ? _c : true;
+ this.options.phone_preferred_countries = (_d = this.options.phone_preferred_countries) !== null && _d !== void 0 ? _d : [];
}
}
-
- // Validate First Name Characters Limit
- const firstName = form.querySelector("#en__field_supporter_firstName");
- const firstNameBlock = form.querySelector(".en__field--firstName");
- if (!this.checkCharsLimit("#en__field_supporter_firstName", 100)) {
- this.scrollToElement(firstName);
- this.sendMessage("error", "This field only allows up to 100 characters");
- if (firstNameBlock) {
- firstNameBlock.classList.add("has-error");
+ }
+ createFields() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options || !this.hasAddressFields()) return;
+ // Creating Latitude and Longitude fields
+ const latitudeField = dist_engrid_ENGrid.getField("supporter.geo.latitude");
+ const longitudeField = dist_engrid_ENGrid.getField("supporter.geo.longitude");
+ if (!latitudeField) {
+ dist_engrid_ENGrid.createHiddenInput("supporter.geo.latitude", "");
+ this.logger.log("Creating Hidden Field: supporter.geo.latitude");
+ }
+ if (!longitudeField) {
+ dist_engrid_ENGrid.createHiddenInput("supporter.geo.longitude", "");
+ this.logger.log("Creating Hidden Field: supporter.geo.longitude");
+ }
+ if (this.options.record_field) {
+ const recordField = dist_engrid_ENGrid.getField(this.options.record_field);
+ if (!recordField) {
+ dist_engrid_ENGrid.createHiddenInput(this.options.record_field, "");
+ this.logger.log("Creating Hidden Field: " + this.options.record_field);
}
- return false;
- } else {
- if (firstNameBlock) {
- firstNameBlock.classList.remove("has-error");
+ }
+ if (this.options.date_field) {
+ const dateField = dist_engrid_ENGrid.getField(this.options.date_field);
+ if (!dateField) {
+ dist_engrid_ENGrid.createHiddenInput(this.options.date_field, "");
+ this.logger.log("Creating Hidden Field: " + this.options.date_field);
}
}
- // Validate Last Name Characters Limit
- const lastName = form.querySelector("#en__field_supporter_lastName");
- const lastNameBlock = form.querySelector(".en__field--lastName");
- if (!this.checkCharsLimit("#en__field_supporter_lastName", 100)) {
- this.scrollToElement(lastName);
- this.sendMessage("error", "This field only allows up to 100 characters");
- if (lastNameBlock) {
- lastNameBlock.classList.add("has-error");
+ if (this.options.status_field) {
+ const statusField = dist_engrid_ENGrid.getField(this.options.status_field);
+ if (!statusField) {
+ dist_engrid_ENGrid.createHiddenInput(this.options.status_field, "");
+ this.logger.log("Creating Hidden Field: " + this.options.status_field);
}
- return false;
- } else {
- if (lastNameBlock) {
- lastNameBlock.classList.remove("has-error");
+ }
+ // If there's no Address 2 or Address 3 field, create them
+ if (!dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address2)) {
+ dist_engrid_ENGrid.createHiddenInput((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2, "");
+ this.logger.log("Creating Hidden Field: " + ((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.address2));
+ }
+ if (!dist_engrid_ENGrid.getField((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.address3)) {
+ dist_engrid_ENGrid.createHiddenInput((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.address3, "");
+ this.logger.log("Creating Hidden Field: " + ((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.address3));
+ }
+ }
+ createPhoneFields() {
+ if (!this.options) return;
+ dist_engrid_ENGrid.createHiddenInput("tc.phone.country", "");
+ this.logger.log("Creating hidden field: tc.phone.country");
+ if (this.options.phone_record_field) {
+ const recordField = dist_engrid_ENGrid.getField(this.options.phone_record_field);
+ if (!recordField) {
+ dist_engrid_ENGrid.createHiddenInput(this.options.phone_record_field, "");
+ this.logger.log("Creating hidden field: " + this.options.phone_record_field);
}
}
- console.log("DonationLightboxForm: validateForm PASSED");
- return true;
- }
- checkCharsLimit(field, max) {
- const fieldElement = document.querySelector(field);
- if (fieldElement && fieldElement.value.length > max) {
- return false;
+ if (this.options.phone_date_field) {
+ const dateField = dist_engrid_ENGrid.getField(this.options.phone_date_field);
+ if (!dateField) {
+ dist_engrid_ENGrid.createHiddenInput(this.options.phone_date_field, "");
+ this.logger.log("Creating hidden field: " + this.options.phone_date_field);
+ }
}
- return true;
- }
-
- // Bounce Arrow Up and Down
- bounceArrow(freq) {
- const arrow = document.querySelector(".monthly-upsell-message");
- if (!arrow) return;
- if (arrow && freq === "onetime") {
- arrow.classList.add("bounce");
- // setTimeout(() => {
- // arrow.classList.remove("bounce");
- // }, 1000);
- } else {
- arrow.classList.remove("bounce");
+ if (this.options.phone_status_field) {
+ const statusField = dist_engrid_ENGrid.getField(this.options.phone_status_field);
+ if (!statusField) {
+ dist_engrid_ENGrid.createHiddenInput(this.options.phone_status_field, "");
+ this.logger.log("Creating hidden field: " + this.options.phone_status_field);
+ }
}
}
- changeSubmitButton() {
- const submit = document.querySelector(".section-navigation__submit");
- let amount = "$" + this.app.formatNumber(this.getDonationTotal());
- // If amount ends with .00, remove it
- if (amount && amount.endsWith(".00")) {
- amount = amount.slice(0, -3);
+ createPhoneMarginVariable() {
+ var _a;
+ if (!this.options) return;
+ const phone = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ if (phone) {
+ const phoneStyle = window.getComputedStyle(phone);
+ const marginTop = phoneStyle.marginTop;
+ const marginBottom = phoneStyle.marginBottom;
+ document.documentElement.style.setProperty("--tc-phone-margin-top", marginTop);
+ document.documentElement.style.setProperty("--tc-phone-margin-bottom", marginBottom);
}
- let frequency = this.frequency.getInstance().frequency;
- let label = submit ? submit.dataset.label : "";
- frequency = frequency === "onetime" ? "" : frequency === "monthly" ? "/mo " : frequency === "annual" ? "/yr " : "";
- if (amount) {
- label = label.replace("$AMOUNT", amount);
- label = label.replace("$FREQUENCY", frequency);
- } else {
- label = label.replace("$AMOUNT", "");
- label = label.replace("$FREQUENCY", "");
+ }
+ addEventListeners() {
+ if (!this.options) return;
+ // Add event listeners to fields
+ if (this.options.address_fields) {
+ for (const [key, value] of Object.entries(this.options.address_fields)) {
+ const field = dist_engrid_ENGrid.getField(value);
+ if (!field) continue;
+ field.addEventListener("change", () => {
+ this.logger.log("Changed " + field.name, true);
+ this.isDirty = true;
+ });
+ }
}
- if (submit && label) {
- submit.innerHTML = `${label} `;
+ // Add event listener to submit
+ this._form.onSubmit.subscribe(this.callAPI.bind(this));
+ // Attach the API call event to the Give By Select to anticipate the use of Digital Wallets
+ const transactionGiveBySelect = document.getElementsByName("transaction.giveBySelect");
+ if (transactionGiveBySelect) {
+ transactionGiveBySelect.forEach(giveBySelect => {
+ giveBySelect.addEventListener("change", () => {
+ if (["stripedigitalwallet", "paypaltouch"].includes(giveBySelect.value.toLowerCase())) {
+ this.logger.log("Clicked Digital Wallet Button");
+ window.setTimeout(() => {
+ this.callAPI();
+ }, 500);
+ }
+ });
+ });
}
}
- clickPaymentOptions(opts) {
- opts.querySelectorAll("button").forEach(btn => {
- btn.addEventListener("click", e => {
- e.preventDefault();
- const paymentType = document.querySelector("#en__field_transaction_paymenttype");
- if (paymentType) {
- paymentType.value = btn.className.substr(15);
- // Go to the next section
- this.scrollToSection(parseInt(btn.closest("[data-section-id]").dataset.sectionId) + 1, this.currentSectionId);
- }
- });
+ checkSum(str) {
+ return dist_tidycontact_awaiter(this, void 0, void 0, function* () {
+ // encode as UTF-8
+ const msgBuffer = new TextEncoder().encode(str);
+ // hash the message
+ const hashBuffer = yield crypto.subtle.digest("SHA-256", msgBuffer);
+ // convert ArrayBuffer to Array
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ // convert bytes to hex string
+ const hashHex = hashArray.map(b => ("00" + b.toString(16)).slice(-2)).join("");
+ return hashHex;
});
}
- // Append arrow SVG to the monthly upsell message
- putArrowUpSVG() {
- const arrow = document.querySelector(".monthly-upsell-message");
- if (arrow) {
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
- svg.classList.add(this.setArrowPosition());
- svg.classList.add("monthly-upsell-message__arrow");
- svg.setAttribute("viewBox", "0 0 55 40");
- svg.setAttribute("fill", "none");
- svg.innerHTML = ` `;
- arrow.appendChild(svg);
+ todaysDate() {
+ return new Date().toLocaleString("en-ZA", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit"
+ }).replace(/\/+/g, ""); // Format date as YYYYMMDD
+ }
+ countryAllowed(country) {
+ var _a;
+ if (!this.options) return false;
+ // If the country list is empty, allow all countries
+ if (!this.options.countries || this.options.countries.length === 0) {
+ return true;
}
+ return !!((_a = this.options.countries) === null || _a === void 0 ? void 0 : _a.includes(country.toLowerCase()));
}
- // Return the arrow position
- setArrowPosition() {
- const frequencyWrapper = document.querySelector(".en__field--recurrfreq .en__field__element--radio");
- if (frequencyWrapper) {
- const left = frequencyWrapper.querySelector('.en__field__item:first-child input[value="MONTHLY"]');
- const right = frequencyWrapper.querySelector('.en__field__item:last-child input[value="MONTHLY"]');
- if (left) {
- return "left";
+ fetchTimeOut(url, params) {
+ const abort = new AbortController();
+ const signal = abort.signal;
+ params = Object.assign(Object.assign({}, params), {
+ signal
+ });
+ const promise = fetch(url, params);
+ if (signal) signal.addEventListener("abort", () => abort.abort());
+ const timeout = setTimeout(() => abort.abort(), this.timeout * 1000);
+ return promise.finally(() => clearTimeout(timeout));
+ }
+ writeError(error) {
+ if (!this.options) return;
+ const recordField = dist_engrid_ENGrid.getField(this.options.record_field);
+ const dateField = dist_engrid_ENGrid.getField(this.options.date_field);
+ const statusField = dist_engrid_ENGrid.getField(this.options.status_field);
+ if (recordField) {
+ let errorType = "";
+ switch (this.httpStatus) {
+ case 400:
+ errorType = "Bad Request";
+ break;
+ case 401:
+ errorType = "Unauthorized";
+ break;
+ case 403:
+ errorType = "Forbidden";
+ break;
+ case 404:
+ errorType = "Not Found";
+ break;
+ case 408:
+ errorType = "API Request Timeout";
+ break;
+ case 500:
+ errorType = "Internal Server Error";
+ break;
+ case 503:
+ errorType = "Service Unavailable";
+ break;
+ default:
+ errorType = "Unknown Error";
+ break;
}
- if (right) {
- return "right";
+ const errorData = {
+ status: this.httpStatus,
+ error: typeof error === "string" ? error : errorType.toUpperCase()
+ };
+ recordField.value = JSON.stringify(errorData);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "ERROR-API";
+ }
+ }
+ setFields(data) {
+ var _a, _b, _c, _d, _e;
+ if (!this.options || !this.options.address_enable) return {};
+ let response = {};
+ const country = this.getCountry();
+ const postalCodeValue = dist_engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.postalCode);
+ const zipDivider = (_b = this.options.us_zip_divider) !== null && _b !== void 0 ? _b : "+";
+ // Check if there's no address2 field
+ const address2Field = dist_engrid_ENGrid.getField((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.address2);
+ if ("address2" in data && !address2Field) {
+ const address = dist_engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.address1);
+ if (address == data.address1 + " " + data.address2) {
+ delete data.address1;
+ delete data.address2;
+ } else {
+ data.address1 = data.address1 + " " + data.address2;
+ delete data.address2;
}
}
- return null;
+ if ("postalCode" in data && postalCodeValue.replace("+", zipDivider) === data.postalCode.replace("+", zipDivider)) {
+ // Postal code is the same
+ delete data.postalCode;
+ }
+ // Set the fields
+ for (const key in data) {
+ const fieldKey = this.options.address_fields && Object.keys(this.options.address_fields).includes(key) ? this.options.address_fields[key] : key;
+ const field = dist_engrid_ENGrid.getField(fieldKey);
+ if (field) {
+ let value = data[key];
+ if (key === "postalCode" && ["US", "USA", "United States"].includes(country)) {
+ value = (_e = value.replace("+", zipDivider)) !== null && _e !== void 0 ? _e : ""; // Replace the "+" with the zip divider
+ }
+ response[key] = {
+ from: field.value,
+ to: value
+ };
+ this.logger.log(`Set ${field.name} to ${value} (${field.value})`);
+ dist_engrid_ENGrid.setFieldValue(fieldKey, value, false);
+ } else {
+ this.logger.log(`Field ${key} not found`);
+ }
+ }
+ return response;
+ }
+ hasAddressFields() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options || !this.options.address_enable) return false;
+ const address1 = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
+ const address2 = dist_engrid_ENGrid.getField((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2);
+ const city = dist_engrid_ENGrid.getField((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.city);
+ const region = dist_engrid_ENGrid.getField((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.region);
+ const postalCode = dist_engrid_ENGrid.getField((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.postalCode);
+ const country = dist_engrid_ENGrid.getField((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.country);
+ return !!(address1 || address2 || city || region || postalCode || country);
+ }
+ canUseAPI() {
+ var _a, _b, _c, _d;
+ if (!this.options || !this.hasAddressFields()) return false;
+ const country = !!this.getCountry();
+ const address1 = !!dist_engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
+ const city = !!dist_engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.city);
+ const region = !!dist_engrid_ENGrid.getFieldValue((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.region);
+ const postalCode = !!dist_engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.postalCode);
+ if (country && address1) {
+ return city && region || postalCode;
+ }
+ this.logger.log("API cannot be used");
+ return false;
}
- checkNested(obj, level, ...rest) {
- if (obj === undefined) return false;
- if (rest.length == 0 && obj.hasOwnProperty(level)) return true;
- return this.checkNested(obj[level], ...rest);
+ canUsePhoneAPI() {
+ var _a;
+ if (!this.options) return false;
+ if (this.phoneEnabled()) {
+ const phone = !!dist_engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ const countryPhone = !!dist_engrid_ENGrid.getFieldValue("tc.phone.country");
+ return phone && countryPhone;
+ }
+ this.logger.log("Phone API is not enabled");
+ return false;
}
- // Add Tabindex to Labels
- addTabIndexToLabels() {
- const labels = document.querySelectorAll(".en__field__label.en__field__label--item");
- labels.forEach(label => {
- label.tabIndex = 0;
- });
+ getCountry() {
+ var _a, _b;
+ if (!this.options) return "";
+ const countryFallback = (_a = this.options.country_fallback) !== null && _a !== void 0 ? _a : "";
+ const country = dist_engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.country);
+ return country || countryFallback.toUpperCase();
+ }
+ getCountryByCode(code) {
+ var _a;
+ const countryItem = (_a = this.countries_list.find(country => country.includes(code))) !== null && _a !== void 0 ? _a : "";
+ if (countryItem) {
+ return {
+ name: countryItem[0],
+ code: countryItem[1],
+ dialCode: countryItem[2],
+ placeholder: countryItem[3]
+ };
+ }
+ return null;
}
- isVisible(element) {
- return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
+ phoneEnabled() {
+ return !!(this.options && this.options.phone_enable);
}
- addEvents() {
- const feeCover = document.querySelector("#en__field_transaction_feeCover");
- if (feeCover) {
- feeCover.addEventListener("change", () => {
- this.changeSubmitButton();
+ countryDropDownEnabled() {
+ return !!(this.options && this.options.phone_flags);
+ }
+ getCountryFromIP() {
+ return dist_tidycontact_awaiter(this, void 0, void 0, function* () {
+ return fetch(`https://${window.location.hostname}/cdn-cgi/trace`).then(res => res.text()).then(t => {
+ let data = t.replace(/[\r\n]+/g, '","').replace(/\=+/g, '":"');
+ data = '{"' + data.slice(0, data.lastIndexOf('","')) + '"}';
+ const jsondata = JSON.parse(data);
+ this.country_ip = jsondata.loc;
+ return this.country_ip;
});
- }
- this.frequency.getInstance().onFrequencyChange.subscribe(s => this.bounceArrow(s));
- this.frequency.getInstance().onFrequencyChange.subscribe(() => this.changeSubmitButton());
- this.frequency.getInstance().onFrequencyChange.subscribe(() => {
- this.showHideDynamicSection(false);
});
- this.amount.getInstance().onAmountChange.subscribe(() => this.changeSubmitButton());
- // Payment Type Radio Change
- const paymentType = document.querySelectorAll("input[name='transaction.giveBySelect']");
- if (paymentType.length) {
- paymentType.forEach(item => {
- item.addEventListener("change", () => {
- this.showHideDynamicSection(item.value.toLowerCase());
- if (item.value === "card") {
- const paymentType = document.querySelector("#en__field_transaction_paymenttype");
- if (paymentType) {
- paymentType.value = "card";
- }
- }
- console.log(`Payment type changed to: ${item.value.toLowerCase()}`);
- window.setTimeout(() => {
- this.scrollToElement(item.closest(".en__component"));
- }, 100);
- });
- });
- }
- const recaptchaContainer = document.querySelector(".en__captcha");
- if (recaptchaContainer) {
- if (typeof window._grecaptchaExpireCallback === "function") {
- // Add our own callback to the recaptcha
- const oldCallback = window._grecaptchaExpireCallback;
- window._grecaptchaExpireCallback = () => {
- oldCallback();
- window.setTimeout(() => {
- this.scrollToElement(recaptchaContainer.closest(".en__component"));
- this.sendMessage("error", "reCAPTCHA expired");
- }, 400);
- };
- }
- }
- if (this.upsellSection) {
- this.frequency.getInstance().onFrequencyChange.subscribe(() => this.refreshUpsellSection());
- this.amount.getInstance().onAmountChange.subscribe(() => this.refreshUpsellSection());
- const upsellButtons = this.upsellSection.querySelectorAll(".upsell-buttons button");
- upsellButtons.forEach(btn => {
- btn.addEventListener("click", e => {
- e.preventDefault();
- const upsellFrequency = btn.dataset.freq || "onetime";
- const upsellAmount = parseFloat(btn.dataset.amount) || this.getDonationTotal();
- if (upsellAmount === 0) {
- return;
- }
- if (upsellFrequency === "onetime") {
- this.upsellSection.dataset.upsold = "false";
- } else {
- this.upsellSection.dataset.upsold = "true";
- }
- this.amount.getInstance().setAmount(upsellAmount);
- this.frequency.getInstance().setFrequency(upsellFrequency);
- this.scrollToElement(document.querySelector(".give-by-select"));
- // this.changeSubmitButton();
- });
- });
- }
}
- // paymentType is any of the values from the giveBySelect radio buttons
- // it can also be false, in which case it will try to get the value from the paymentType field
- showHideDynamicSection(paymentType) {
- let ptValue = paymentType;
- if (!paymentType) {
- const payment = document.querySelector("#en__field_transaction_paymenttype");
- if (payment && ["visa", "mastercard", "amex", "discover", "diners", "jcb", "card"].includes(payment.value)) {
- ptValue = "card";
- // Check Card transaction.giveBySelect
- const card = document.querySelector("[name='transaction.giveBySelect'][value='card']");
- if (card) {
- card.checked = true;
- const event = new Event("change");
- card.dispatchEvent(event);
- }
+ renderFlagsDropDown() {
+ var _a;
+ if (!this.options) return;
+ const phoneInput = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ if (!phoneInput) return;
+ this.countries_dropdown = document.createElement("div");
+ this.countries_dropdown.classList.add("tc-flags-container");
+ const selectedFlag = document.createElement("div");
+ selectedFlag.classList.add("tc-selected-flag");
+ selectedFlag.setAttribute("role", "combobox");
+ selectedFlag.setAttribute("aria-haspopup", "listbox");
+ selectedFlag.setAttribute("aria-expanded", "false");
+ selectedFlag.setAttribute("aria-owns", "tc-flags-list");
+ selectedFlag.setAttribute("aria-label", "Select Country");
+ selectedFlag.setAttribute("tabindex", "0");
+ const seletedFlagInner = document.createElement("div");
+ seletedFlagInner.classList.add("tc-flag");
+ // seletedFlagInner.innerHTML = this.getFlagImage("us", "United States");
+ const flagArrow = document.createElement("div");
+ flagArrow.classList.add("tc-flag-arrow");
+ // flagArrow.innerHTML = "▼";
+ selectedFlag.appendChild(seletedFlagInner);
+ selectedFlag.appendChild(flagArrow);
+ selectedFlag.addEventListener("click", e => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (selectedFlag.classList.contains("tc-open")) {
+ this.closeCountryDropDown();
} else {
- ptValue = payment ? payment.value.toLowerCase() : null;
- const giveBySelectItem = document.querySelector(`[name='transaction.giveBySelect'][value='${ptValue}']`);
- if (giveBySelectItem) {
- giveBySelectItem.checked = true;
- const event = new Event("change");
- giveBySelectItem.dispatchEvent(event);
+ this.openCountryDropDown();
+ }
+ });
+ const countryList = document.createElement("ul");
+ countryList.classList.add("tc-country-list");
+ countryList.classList.add("tc-hide");
+ countryList.setAttribute("id", "tc-country-list");
+ countryList.setAttribute("role", "listbox");
+ countryList.setAttribute("aria-label", "List of Countries");
+ countryList.setAttribute("aria-hidden", "true");
+ if (this.options.phone_preferred_countries.length > 0) {
+ const preferredCountries = [];
+ this.options.phone_preferred_countries.forEach(country => {
+ const countryItem = this.getCountryByCode(country);
+ if (countryItem) {
+ preferredCountries.push(countryItem);
+ }
+ });
+ this.appendCountryItems(countryList, preferredCountries, "tc-country-list-item", true);
+ const divider = document.createElement("li");
+ divider.classList.add("tc-divider");
+ divider.setAttribute("role", "separator");
+ divider.setAttribute("aria-disabled", "true");
+ countryList.appendChild(divider);
+ this.logger.log("Rendering preferred countries", JSON.stringify(preferredCountries));
+ }
+ const countryListItems = [];
+ this.countries_list.forEach(country => {
+ countryListItems.push({
+ name: country[0],
+ code: country[1],
+ dialCode: country[2],
+ placeholder: country[3]
+ });
+ });
+ this.appendCountryItems(countryList, countryListItems, "tc-country-list-item");
+ countryList.addEventListener("click", e => {
+ e.preventDefault();
+ e.stopPropagation();
+ const target = e.target.closest("li");
+ if (target.classList.contains("tc-country-list-item")) {
+ const countryItem = this.getCountryByCode(target.getAttribute("data-country-code"));
+ if (countryItem) {
+ this.setPhoneCountry(countryItem);
}
}
- }
- // Get every element that has the CSS class giveBySelect-*
- const giveBySelectItems = document.querySelectorAll("[class*='giveBySelect-']");
- console.log(`Found ${giveBySelectItems.length} total giveBySelect- elements`);
-
- // Create a Set of sections that have giveBySelect- elements (excluding those in digital-wallets-wrapper)
- const sectionsWithGiveBySelect = new Set();
- giveBySelectItems.forEach(item => {
- // Skip if the element is inside digital-wallets-wrapper
- if (item.closest(".digital-wallets-wrapper")) {
- console.log(`Skipping giveBySelect- element in digital-wallets-wrapper: ${item.className}`);
- return;
+ });
+ countryList.addEventListener("mouseover", e => {
+ e.preventDefault();
+ e.stopPropagation();
+ const target = e.target.closest("li.tc-country-list-item");
+ if (target) {
+ this.highlightCountry(target.getAttribute("data-country-code"));
}
- const section = this.getSectionId(item);
- if (section !== false) {
- sectionsWithGiveBySelect.add(section);
- console.log(`Section ${section} has giveBySelect- element: ${item.className}`);
+ });
+ this.countries_dropdown.appendChild(selectedFlag);
+ this.countries_dropdown.appendChild(countryList);
+ phoneInput.parentNode.insertBefore(this.countries_dropdown, phoneInput);
+ phoneInput.parentNode.classList.add("tc-has-country-flags");
+ this.countries_dropdown.addEventListener("keydown", e => {
+ var _a, _b;
+ const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
+ if (isDropdownHidden && ["ArrowUp", "Up", "ArrowDown", "Down", " ", "Enter"].indexOf(e.key) !== -1) {
+ // prevent form from being submitted if "ENTER" was pressed
+ e.preventDefault();
+ // prevent event from being handled again by document
+ e.stopPropagation();
+ this.openCountryDropDown();
}
+ // allow navigation from dropdown to input on TAB
+ if (e.key === "Tab") this.closeCountryDropDown();
});
- console.log(`Found ${sectionsWithGiveBySelect.size} sections with giveBySelect- elements`);
-
- // First, handle sections without giveBySelect- elements
- this.sections.forEach((section, sectionId) => {
- if (!sectionsWithGiveBySelect.has(sectionId) && sectionId !== this.upsellSectionId) {
- section.style.display = "block";
- console.log(`Showing section ${sectionId} (no giveBySelect elements)`);
+ document.addEventListener("keydown", e => {
+ var _a, _b;
+ const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
+ if (!isDropdownHidden) {
+ // prevent down key from scrolling the whole page,
+ // and enter key from submitting a form etc
+ e.preventDefault();
+ // up and down to navigate
+ if (e.key === "ArrowUp" || e.key === "Up" || e.key === "ArrowDown" || e.key === "Down") this.handleUpDownKey(e.key);
+ // enter to select
+ else if (e.key === "Enter") this.handleEnterKey();
+ // esc to close
+ else if (e.key === "Escape") this.closeCountryDropDown();
}
});
-
- // Then, handle sections with giveBySelect- elements
- sectionsWithGiveBySelect.forEach(sectionId => {
- const section = this.sections[sectionId];
- // Only get giveBySelect- elements that are not in digital-wallets-wrapper
- const sectionItems = Array.from(section.querySelectorAll("[class*='giveBySelect-']")).filter(item => !item.closest(".digital-wallets-wrapper"));
- console.log(`Section ${sectionId} has ${sectionItems.length} giveBySelect- elements (excluding digital-wallets-wrapper)`);
- let shouldShow = false;
- sectionItems.forEach(item => {
- // Get the value of the class
- let value = item.className.split("giveBySelect-")[1];
- // Get the value until the next space
- value = value.split(" ")[0];
- console.log(`Checking giveBySelect- element in section ${sectionId}: ${value} against payment type: ${ptValue}`);
- // If the value is the same as the payment type, show the section
- if (value.toLowerCase() === ptValue) {
- shouldShow = true;
- console.log(`Match found for section ${sectionId}`);
- }
- });
- section.style.display = shouldShow ? "block" : "none";
- console.log(`${shouldShow ? "Showing" : "Hiding"} section ${sectionId} (payment type: ${ptValue})`);
+ document.addEventListener("click", e => {
+ var _a, _b;
+ const isDropdownHidden = (_b = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-country-list")) === null || _b === void 0 ? void 0 : _b.classList.contains("tc-hide");
+ if (!isDropdownHidden && !e.target.closest(".tc-country-list")) {
+ this.closeCountryDropDown();
+ }
});
- this.updateSectionCount();
}
- getDonationTotal() {
- return this.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationTotal") ? window.EngagingNetworks.require._defined.enjs.getDonationTotal() : 0;
+ handleUpDownKey(key) {
+ var _a;
+ const highlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
+ if (highlightedCountry) {
+ let next = key === "ArrowUp" || key === "Up" ? highlightedCountry.previousElementSibling : highlightedCountry.nextElementSibling;
+ if (next) {
+ if (next.classList.contains("tc-divider")) {
+ next = key === "ArrowUp" || key === "Up" ? next.previousElementSibling : next.nextElementSibling;
+ }
+ this.highlightCountry(next === null || next === void 0 ? void 0 : next.getAttribute("data-country-code"));
+ }
+ }
}
- getDonationFee() {
- return this.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getDonationFee") ? window.EngagingNetworks.require._defined.enjs.getDonationFee() : 0;
+ handleEnterKey() {
+ var _a;
+ const highlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
+ if (highlightedCountry) {
+ const countryItem = this.getCountryByCode(highlightedCountry === null || highlightedCountry === void 0 ? void 0 : highlightedCountry.getAttribute("data-country-code"));
+ this.setPhoneCountry(countryItem);
+ }
}
- // Return the Suggested Upsell Amount
- getUpsellAmount(freq = "monthly") {
- const amount = this.getDonationTotal() - this.getDonationFee();
- let upsellAmount = 0;
- if ("EngridMultistepUpsell" in window && freq in window.EngridMultistepUpsell) {
- const amountRange = window.EngridMultistepUpsell[freq];
- for (let i = 0; i < amountRange.length; i++) {
- let val = amountRange[i];
- if (upsellAmount == 0 && amount <= val.max) {
- upsellAmount = val.suggestion;
- if (upsellAmount === 0) return 0;
- if (typeof upsellAmount !== "number") {
- const suggestionMath = upsellAmount.replace("amount", amount.toFixed(2));
- upsellAmount = parseFloat(Function('"use strict";return (' + suggestionMath + ")")());
- }
- break;
+ handlePhoneInputKeydown(e) {
+ const phoneInput = e.target;
+ const phoneNumber = phoneInput.value;
+ if (phoneNumber.charAt(0) === "+") {
+ if (phoneNumber.length > 2) {
+ const countryItem = this.getCountryByCode(phoneNumber.substring(1, 3));
+ if (countryItem) {
+ this.setPhoneCountry(countryItem);
+ } else {
+ this.setDefaultPhoneCountry();
}
}
}
- return upsellAmount;
}
- replaceUpsellMergeTags() {
- if (this.upsellSection === null) return;
- const upsellSectionContent = this.upsellSection.querySelector(".en__component--column");
- if (!upsellSectionContent) return;
- let content = upsellSectionContent.innerHTML;
- content = content.replace(/{old-amount}/g, " ");
- content = content.replace(/{new-amount-monthly}/g, " ");
- content = content.replace(/{new-amount-annual}/g, " ");
- upsellSectionContent.innerHTML = content;
+ openCountryDropDown() {
+ if (!this.countries_dropdown) return;
+ const countryList = this.countries_dropdown.querySelector(".tc-country-list");
+ const selectedFlag = this.countries_dropdown.querySelector(".tc-selected-flag");
+ if (countryList && selectedFlag) {
+ countryList.classList.remove("tc-hide");
+ selectedFlag.setAttribute("aria-expanded", "true");
+ selectedFlag.classList.add("tc-open");
+ }
+ }
+ closeCountryDropDown() {
+ var _a;
+ if (!this.options) return;
+ if (!this.countries_dropdown) return;
+ const countryList = this.countries_dropdown.querySelector(".tc-country-list");
+ const selectedFlag = this.countries_dropdown.querySelector(".tc-selected-flag");
+ if (countryList && selectedFlag) {
+ countryList.classList.add("tc-hide");
+ selectedFlag.setAttribute("aria-expanded", "false");
+ selectedFlag.classList.remove("tc-open");
+ }
+ const phoneInput = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ phoneInput.focus();
+ }
+ getFlagImage(code, name) {
+ return `
+
+
+
+ `;
}
- refreshUpsellSection() {
- if (this.upsellSection === null || this.upsellSection.dataset.upsold) return;
- // Update merge tags
- const amount = this.getDonationTotal() - this.getDonationFee();
- const upsellAmountMonthly = this.getUpsellAmount("monthly");
- const upsellAmountAnnual = this.getUpsellAmount("annual");
- if (upsellAmountMonthly === 0 && upsellAmountAnnual === 0) {
- // If both upsell amounts are 0, hide the upsell section
- this.upsellSection.style.display = "none";
- this.updateSectionCount();
+ appendCountryItems(countryContainer, countries, className, preferred = false) {
+ let html = "";
+ // for each country
+ for (let i = 0; i < countries.length; i++) {
+ const c = countries[i];
+ const idSuffix = !!preferred ? "-preferred" : true && "" !== void 0 ? "" : "";
+ // open the list item
+ html += ``;
+ // add the flag
+ html += `${this.getFlagImage(c.code, c.name)}
`;
+ // and the country name and dial code
+ html += `${c.name} `;
+ html += `+${c.dialCode} `;
+ // close the list item
+ html += " ";
+ }
+ countryContainer.insertAdjacentHTML("beforeend", html);
+ }
+ setDefaultPhoneCountry() {
+ var _a;
+ if (!this.options) return;
+ // First, try to get the country from IP
+ if (this.options.phone_country_from_ip) {
+ this.getCountryFromIP().then(country => {
+ this.logger.log("Country from IP:", country);
+ this.setPhoneCountry(this.getCountryByCode((country !== null && country !== void 0 ? country : "us").toLowerCase()));
+ }).catch(error => {
+ this.setPhoneCountry(this.getCountryByCode("us"));
+ });
return;
}
- const oldAmounts = this.upsellSection.querySelectorAll(".upsell_amount");
- const newAmountsMonthly = this.upsellSection.querySelectorAll(".upsell_suggestion_monthly");
- const newAmountsAnnual = this.upsellSection.querySelectorAll(".upsell_suggestion_annual");
- const monthlyBtn = this.upsellSection.querySelector(".upsell-buttons button[data-freq='monthly']");
- const annualBtn = this.upsellSection.querySelector(".upsell-buttons button[data-freq='annual']");
- const onetimeBtn = this.upsellSection.querySelector(".upsell-buttons button[data-freq='onetime']");
- if (monthlyBtn) {
- monthlyBtn.dataset.amount = upsellAmountMonthly;
+ // Then, get the default country Text
+ const countryField = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.country);
+ if (countryField) {
+ const countryText = countryField.options[countryField.selectedIndex].text;
+ // Then, get the country code from the Text
+ const countryData = this.getCountryByCode(countryText);
+ if (countryData) {
+ this.setPhoneCountry(countryData);
+ return;
+ } else if (this.options.phone_preferred_countries.length > 0) {
+ // If no country code is found, use the first priority country
+ this.setPhoneCountry(this.getCountryByCode(this.options.phone_preferred_countries[0]));
+ return;
+ }
}
- if (annualBtn) {
- annualBtn.dataset.amount = upsellAmountAnnual;
+ // If nothing works, GO USA!
+ this.setPhoneCountry(this.getCountryByCode("us"));
+ }
+ setPhoneCountry(country) {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options || !country) return;
+ const countryInput = dist_engrid_ENGrid.getField("tc.phone.country");
+ if (countryInput.value === country.code) return;
+ const phoneInput = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ if (this.countryDropDownEnabled()) {
+ const selectedFlag = (_b = this.countries_dropdown) === null || _b === void 0 ? void 0 : _b.querySelector(".tc-selected-flag");
+ const flagElement = (_c = this.countries_dropdown) === null || _c === void 0 ? void 0 : _c.querySelector(".tc-flag");
+ if (selectedFlag && flagElement) {
+ flagElement.innerHTML = this.getFlagImage(country.code, country.name);
+ selectedFlag.setAttribute("data-country", country.code);
+ }
+ const currentSelectedCountry = (_d = this.countries_dropdown) === null || _d === void 0 ? void 0 : _d.querySelector(".tc-country-list-item[aria-selected='true']");
+ if (currentSelectedCountry) {
+ currentSelectedCountry.classList.remove("tc-selected");
+ currentSelectedCountry.setAttribute("aria-selected", "false");
+ }
+ const currentHighlightedCountry = (_e = this.countries_dropdown) === null || _e === void 0 ? void 0 : _e.querySelector(".tc-highlight");
+ if (currentHighlightedCountry) {
+ currentHighlightedCountry.classList.remove("tc-highlight");
+ }
+ const countryListItem = (_f = this.countries_dropdown) === null || _f === void 0 ? void 0 : _f.querySelector(`.tc-country-list-item[data-country-code='${country.code}']`);
+ if (countryListItem) {
+ countryListItem.classList.add("tc-selected");
+ countryListItem.setAttribute("aria-selected", "true");
+ countryListItem.classList.add("tc-highlight");
+ }
+ if (selectedFlag === null || selectedFlag === void 0 ? void 0 : selectedFlag.classList.contains("tc-open")) this.closeCountryDropDown();
+ }
+ phoneInput.setAttribute("placeholder", country.placeholder);
+ countryInput.value = country.code;
+ this.logger.log(`Setting phone country to ${country.code} - ${country.name}`);
+ }
+ highlightCountry(countryCode) {
+ var _a, _b;
+ if (!countryCode) return;
+ const currentHighlightedCountry = (_a = this.countries_dropdown) === null || _a === void 0 ? void 0 : _a.querySelector(".tc-highlight");
+ if (currentHighlightedCountry) {
+ currentHighlightedCountry.classList.remove("tc-highlight");
+ }
+ const countryList = (_b = this.countries_dropdown) === null || _b === void 0 ? void 0 : _b.querySelector(".tc-country-list");
+ if (countryList) {
+ const country = countryList.querySelector(`.tc-country[data-country-code='${countryCode}']`);
+ if (country) {
+ country.classList.add("tc-highlight");
+ country.scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ inline: "nearest"
+ });
+ }
+ }
+ }
+ setPhoneDataFromAPI(data, id) {
+ var _a;
+ return dist_tidycontact_awaiter(this, void 0, void 0, function* () {
+ if (!this.options) return;
+ const phoneField = dist_engrid_ENGrid.getField((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.phone);
+ const recordField = dist_engrid_ENGrid.getField(this.options.phone_record_field);
+ const dateField = dist_engrid_ENGrid.getField(this.options.phone_date_field);
+ const statusField = dist_engrid_ENGrid.getField(this.options.phone_status_field);
+ let record = {};
+ record["formData"] = {
+ [phoneField.name]: phoneField.value
+ };
+ record["formatted"] = data.formatted;
+ record["number_type"] = data.number_type;
+ if (data.valid === true) {
+ if (phoneField.value !== data.formatted.e164) {
+ record["phone"] = {
+ from: phoneField.value,
+ to: data.formatted.e164
+ };
+ phoneField.value = data.formatted.e164;
+ }
+ yield this.checkSum(JSON.stringify(record)).then(checksum => {
+ this.logger.log("Phone Checksum", checksum);
+ record["requestId"] = id; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if (recordField) {
+ record = Object.assign({
+ date: this.todaysDate(),
+ status: "SUCCESS"
+ }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "SUCCESS";
+ }
+ } else {
+ yield this.checkSum(JSON.stringify(record)).then(checksum => {
+ this.logger.log("Phone Checksum", checksum);
+ record["requestId"] = id; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if (recordField) {
+ record = Object.assign({
+ date: this.todaysDate(),
+ status: "ERROR"
+ }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "error" in data ? `ERROR: ` + data.error : "INVALIDPHONE";
+ }
+ }
+ });
+ }
+ callAPI() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.options) return;
+ if (!this.isDirty || this.wasCalled) return;
+ if (!this._form.submit) {
+ this.logger.log("Form Submission Interrupted by Other Component");
+ return;
+ }
+ const recordField = dist_engrid_ENGrid.getField(this.options.record_field);
+ const dateField = dist_engrid_ENGrid.getField(this.options.date_field);
+ const statusField = dist_engrid_ENGrid.getField(this.options.status_field);
+ const latitudeField = dist_engrid_ENGrid.getField("supporter.geo.latitude");
+ const longitudeField = dist_engrid_ENGrid.getField("supporter.geo.longitude");
+ if (!this.canUseAPI() && !this.canUsePhoneAPI()) {
+ this.logger.log("Not Enough Data to Call API");
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "PARTIALADDRESS";
+ }
+ return true;
+ }
+ // Call the API
+ const address1 = dist_engrid_ENGrid.getFieldValue((_a = this.options.address_fields) === null || _a === void 0 ? void 0 : _a.address1);
+ const address2 = dist_engrid_ENGrid.getFieldValue((_b = this.options.address_fields) === null || _b === void 0 ? void 0 : _b.address2);
+ const city = dist_engrid_ENGrid.getFieldValue((_c = this.options.address_fields) === null || _c === void 0 ? void 0 : _c.city);
+ const region = dist_engrid_ENGrid.getFieldValue((_d = this.options.address_fields) === null || _d === void 0 ? void 0 : _d.region);
+ const postalCode = dist_engrid_ENGrid.getFieldValue((_e = this.options.address_fields) === null || _e === void 0 ? void 0 : _e.postalCode);
+ const country = this.getCountry();
+ if (!this.countryAllowed(country)) {
+ this.logger.log("Country not allowed: " + country);
+ if (recordField) {
+ let record = {};
+ record = Object.assign({
+ date: this.todaysDate(),
+ status: "DISALLOWED"
+ }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "DISALLOWED";
+ }
+ return true;
+ }
+ let formData = {
+ url: window.location.href,
+ cid: this.options.cid
+ };
+ if (this.canUseAPI()) {
+ formData = Object.assign(formData, {
+ address1,
+ address2,
+ city,
+ region,
+ postalCode,
+ country
+ });
+ }
+ if (this.canUsePhoneAPI()) {
+ formData.phone = dist_engrid_ENGrid.getFieldValue((_f = this.options.address_fields) === null || _f === void 0 ? void 0 : _f.phone);
+ formData.phoneCountry = dist_engrid_ENGrid.getFieldValue("tc.phone.country");
+ }
+ this.wasCalled = true;
+ this.logger.log("FormData", JSON.parse(JSON.stringify(formData)));
+ const ret = this.fetchTimeOut(this.endpoint, {
+ headers: {
+ "Content-Type": "application/json; charset=utf-8"
+ },
+ method: "POST",
+ body: JSON.stringify(formData)
+ }).then(response => {
+ this.httpStatus = response.status;
+ return response.json();
+ }).then(data => dist_tidycontact_awaiter(this, void 0, void 0, function* () {
+ this.logger.log("callAPI response", JSON.parse(JSON.stringify(data)));
+ if (data.valid === true) {
+ let record = {};
+ if ("changed" in data) {
+ record = this.setFields(data.changed);
+ }
+ record["formData"] = formData;
+ yield this.checkSum(JSON.stringify(record)).then(checksum => {
+ this.logger.log("Checksum", checksum);
+ record["requestId"] = data.requestId; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if ("latitude" in data) {
+ latitudeField.value = data.latitude;
+ record["latitude"] = data.latitude;
+ }
+ if ("longitude" in data) {
+ longitudeField.value = data.longitude;
+ record["longitude"] = data.longitude;
+ }
+ if (recordField) {
+ record = Object.assign({
+ date: this.todaysDate(),
+ status: "SUCCESS"
+ }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "SUCCESS";
+ }
+ } else {
+ let record = {};
+ record["formData"] = formData;
+ yield this.checkSum(JSON.stringify(record)).then(checksum => {
+ this.logger.log("Checksum", checksum);
+ record["requestId"] = data.requestId; // We don't want to add the requestId to the checksum
+ record["checksum"] = checksum;
+ });
+ if (recordField) {
+ record = Object.assign({
+ date: this.todaysDate(),
+ status: "ERROR"
+ }, record);
+ recordField.value = JSON.stringify(record);
+ }
+ if (dateField) {
+ dateField.value = this.todaysDate();
+ }
+ if (statusField) {
+ statusField.value = "error" in data ? `ERROR: ` + data.error : "INVALIDADDRESS";
+ }
+ }
+ if (this.phoneEnabled() && "phone" in data) {
+ yield this.setPhoneDataFromAPI(data.phone, data.requestId);
+ }
+ })).catch(error => {
+ if (error.toString().includes("AbortError")) {
+ // fetch aborted due to timeout
+ this.logger.log("Fetch aborted");
+ this.httpStatus = 408;
+ }
+ // network error or json parsing error
+ this.writeError(error);
+ });
+ this._form.submitPromise = ret;
+ return ret;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/live-currency.js
+// This script enables live currency symbol and code to the page.
+
+class live_currency_LiveCurrency {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("LiveCurrency", "#1901b1", "#feb47a", "π²");
+ this.elementsFound = false;
+ this.isUpdating = false;
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._fees = processing_fees_ProcessingFees.getInstance();
+ this.searchElements();
+ if (!this.shouldRun()) return;
+ dist_engrid_ENGrid.setBodyData("live-currency", "active");
+ this.updateCurrency();
+ this.addEventListeners();
+ // Make labels visible on page load
+ document.querySelectorAll(".en__field--donationAmt .en__field__element--radio .en__field__item").forEach(node => {
+ node.setAttribute("data-engrid-currency-symbol-updated", "true");
+ });
+ }
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field label,
+ .en__submit
+ `);
+ if (enElements.length > 0) {
+ this.elementsFound = true;
+ const currency = dist_engrid_ENGrid.getCurrencySymbol();
+ const currencyCode = dist_engrid_ENGrid.getCurrencyCode();
+ const currencyElement = `${currency} `;
+ const currencyCodeElement = `${currencyCode} `;
+ enElements.forEach(item => {
+ // If item starts with
+//
+// This will override the default CustomCurrency options for that page.
+//
+
+class custom_currency_CustomCurrency {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("CustomCurrency", "#1901b1", "#00cc95", "π€");
+ this.currencyElement = document.querySelector("[name='transaction.paycurrency']");
+ this._country = country_Country.getInstance();
+ if (!this.shouldRun()) return;
+ this.addEventListeners();
+ this.loadCurrencies();
+ }
+ shouldRun() {
+ // Only run if the currency field is present, and the CustomCurrency option is not false
+ if (!this.currencyElement || !dist_engrid_ENGrid.getOption("CustomCurrency")) {
+ return false;
+ }
+ return true;
+ }
+ addEventListeners() {
+ if (this._country.countryField) {
+ this._country.onCountryChange.subscribe(country => {
+ this.loadCurrencies(country);
});
}
- // If frequency is anything other than onetime, hide the upsell section
- window.setTimeout(() => {
- const frequency = this.frequency.getInstance().frequency;
- if (this.upsellSection && !this.upsellSection.dataset.upsold) {
- if (frequency === "onetime") {
- this.upsellSection.style.display = "block";
- } else {
- this.upsellSection.style.display = "none";
- }
- }
- this.updateSectionCount();
- }, 600);
- // Update visibility
}
- hideAnnualFrequency() {
- const annualFreqField = document.querySelector("[name='transaction.recurrfreq'][value='ANNUAL']");
- if (annualFreqField) {
- const annualFrequency = annualFreqField.closest(".en__field__item");
- if (annualFrequency) {
- annualFrequency.classList.add("hide");
- }
+ // Changes the options in the currency field to match the selected country options
+ loadCurrencies(country = "default") {
+ const options = dist_engrid_ENGrid.getOption("CustomCurrency");
+ if (!options) return;
+ const label = options.label || `Give with [$$$]`;
+ let currencies = options.default;
+ if (options.countries && options.countries[country]) {
+ currencies = options.countries[country];
}
+ if (!currencies) {
+ this.logger.log(`No currencies found for ${country}`);
+ return;
+ }
+ this.logger.log(`Loading currencies for ${country}`);
+ this.currencyElement.innerHTML = "";
+ for (const currency in currencies) {
+ const option = document.createElement("option");
+ option.value = currency;
+ option.text = label.replace("[$$$]", currency).replace("[$]", currencies[currency]);
+ option.setAttribute("data-currency-code", currency);
+ option.setAttribute("data-currency-symbol", currencies[currency]);
+ this.currencyElement.appendChild(option);
+ }
+ // Set the currency to the first option and trigger a change event
+ this.currencyElement.selectedIndex = 0;
+ const event = new Event("change", {
+ bubbles: true
+ });
+ this.currencyElement.dispatchEvent(event);
}
}
-;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/typeof.js
-function _typeof(o) {
- "@babel/helpers - typeof";
-
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
- return typeof o;
- } : function (o) {
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
- }, _typeof(o);
-}
-
-;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/toPrimitive.js
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/autosubmit.js
+// Automatically submits the page if a URL argument is present
-function toPrimitive(t, r) {
- if ("object" != _typeof(t) || !t) return t;
- var e = t[Symbol.toPrimitive];
- if (void 0 !== e) {
- var i = e.call(t, r || "default");
- if ("object" != _typeof(i)) return i;
- throw new TypeError("@@toPrimitive must return a primitive value.");
+class autosubmit_Autosubmit {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Autosubmit", "#f0f0f0", "#ff0000", "π");
+ this._form = events_en_form_EnForm.getInstance();
+ if (dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && !window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed() && dist_engrid_ENGrid.getUrlParameter("autosubmit") === "Y") {
+ this.logger.log("Autosubmitting Form");
+ // Fix EN ?chain parameter not working with email addresses with + in them
+ dist_engrid_ENGrid.setFieldValue("supporter.emailAddress", dist_engrid_ENGrid.getFieldValue("supporter.emailAddress").replace(/\s/g, "+"));
+ this._form.submitForm();
+ }
}
- return ("string" === r ? String : Number)(t);
-}
-
-;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js
-
-
-function toPropertyKey(t) {
- var i = toPrimitive(t, "string");
- return "symbol" == _typeof(i) ? i : i + "";
}
-
-;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/defineProperty.js
-
-function _defineProperty(e, r, t) {
- return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
- value: t,
- enumerable: !0,
- configurable: !0,
- writable: !0
- }) : e[r] = t, e;
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/event-tickets.js
+class event_tickets_EventTickets {
+ constructor() {
+ // --------------------------------------------
+ // Format ticket amounts as currency.
+ const ticketCostElements = document.getElementsByClassName("en__ticket__field--cost");
+ const ticketCurrencyElements = document.getElementsByClassName("en__ticket__currency");
+ for (const ticketCurrencyElement of ticketCurrencyElements) {
+ ticketCurrencyElement.classList.add("en__ticket__currency__hidden");
+ }
+ for (const ticketCostElement of ticketCostElements) {
+ const ticketAmountElement = ticketCostElement.getElementsByClassName("en__ticket__price")[0];
+ const ticketCurrencyElement = ticketCostElement.getElementsByClassName("en__ticket__currency")[0];
+ const formatterOptions = {
+ style: "currency",
+ currency: ticketCurrencyElement.innerText
+ };
+ let ticketAmountAsCurrency = Intl.NumberFormat(undefined, formatterOptions).format(Number(ticketAmountElement.innerText));
+ if (ticketAmountAsCurrency.slice(-3) === ".00") {
+ ticketAmountAsCurrency = ticketAmountAsCurrency.slice(0, -3);
+ }
+ ticketAmountElement.innerText = ticketAmountAsCurrency;
+ }
+ }
}
-
-;// CONCATENATED MODULE: ./src/scripts/tracking.js
-
-function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
-function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/swap-amounts.js
+// This script allows you to override the default donation amounts in Engaging Networks
+// with a custom list of amounts.
+// If the URL contains a query parameter "engrid-amounts" with a comma separated values, the script will load the
+// amounts from the parameter and set them as the default amounts for the donation
+// form.
/**
- * @typedef {Object} Window
- * @property {Object} utag
- * @property {Object} utag_data
- * @property {String} utag_data.page_name
- * @property {Object} pageJson
- * @property {String} pageJson.pageType
+ * Example:
+ * window.EngridAmounts = {
+ * "onetime": {
+ * amounts: {
+ * "10": 10,
+ * "30": 30,
+ * "50": 50,
+ * "100": 100,
+ * "Other": "other",
+ * },
+ * default: 30,
+ * stickyDefault: false, // Optional. When true, every swap forces the default amount to be (re)selected
+ * },
+ * "monthly": {
+ * amounts: {
+ * "5": 5,
+ * "15": 15,
+ * "25": 25,
+ * "30": 30,
+ * "Other": "other",
+ * },
+ * default: 15,
+ * stickyDefault: true, // Example forcing default on each frequency swap
+ * },
+ * };
*/
-function trackEvent(eventName, eventData) {
- if (typeof utag !== "undefined") {
- utag.link(_objectSpread({
- event_name: eventName
- }, eventData));
- } else {
- window.utagQueue = window.utagQueue || [];
- window.utagQueue.push(_objectSpread({
- event_name: eventName
- }, eventData));
- const tealiumScript = document.querySelector('script[src*="//tags.tiqcdn.com/utag/tnc/global/prod/utag.js"]');
- if (tealiumScript) {
- tealiumScript.onload = () => {
- window.utagQueue.forEach(event => {
- utag.link(event);
- });
- window.utagQueue = [];
+class swap_amounts_SwapAmounts {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("SwapAmounts", "purple", "white", "π°");
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this.defaultChange = false; // Tracks if user changed away from default after swap
+ this.swapped = false; // Tracks if we've already executed at least one swap
+ this.loadAmountsFromUrl();
+ if (!this.shouldRun()) return;
+ // Respond when frequency changes
+ this._frequency.onFrequencyChange.subscribe(() => this.swapAmounts());
+ // Track if donor moves away from the swapped default amount
+ this._amount.onAmountChange.subscribe(() => {
+ const configs = window.EngridAmounts;
+ if (!configs) return;
+ const freq = this._frequency.frequency;
+ if (!(freq in configs)) return;
+ if (!this.swapped) return; // ignore early changes before initial swap
+ const currentConfig = configs[freq];
+ this.defaultChange = this._amount.amount !== currentConfig.default;
+ });
+ }
+ loadAmountsFromUrl() {
+ const urlParams = new URLSearchParams(window.location.search);
+ const amounts = urlParams.get("engrid-amounts");
+ if (amounts) {
+ this.defaultChange = true; // if amounts come from URL, treat as user-set
+ const amountArray = amounts.split(",").map(amt => amt.trim()).filter(Boolean);
+ if (!amountArray.length) return;
+ const urlDefaultParam = dist_engrid_ENGrid.getUrlParameter("transaction.donationAmt");
+ const parsedFirst = parseFloat(amountArray[0]);
+ const defaultAmount = urlDefaultParam && parseFloat(urlDefaultParam) || parsedFirst;
+ const amountsObj = {};
+ amountArray.forEach(raw => {
+ const numeric = parseFloat(raw);
+ amountsObj[raw] = isNaN(numeric) ? raw : numeric;
+ });
+ // Ensure Other choice always present at the end
+ amountsObj["Other"] = "other";
+ const config = {
+ amounts: amountsObj,
+ default: defaultAmount
+ // stickyDefault omitted so it defaults to false behavior
+ };
+ window.EngridAmounts = {
+ onetime: config,
+ monthly: config
};
}
}
-}
-function setDonationDataSessionStorage(App, DonationAmount) {
- const donationData = {};
- donationData.productId = utag_data.page_name.slice(0, -2);
- donationData.campaignId = pageJson.campaignId;
- donationData.campaignPageId = App.getPageID();
- donationData.state = App.getFieldValue("supporter.region");
- donationData.zipCode = App.getFieldValue("supporter.postcode");
- donationData.emailAddress = App.getFieldValue("supporter.emailAddress");
- donationData.originalDonationAmount = DonationAmount.getInstance().amount;
- donationData.extraAmount = 0;
- // New donationData fields for Google Ads Enhanced Conversions
- donationData.firstName = App.getFieldValue("supporter.firstName");
- donationData.lastName = App.getFieldValue("supporter.lastName");
- donationData.address1 = App.getFieldValue("supporter.address1");
- donationData.city = App.getFieldValue("supporter.city");
- donationData.country = App.getFieldValue("supporter.country");
- donationData.phoneNumber = App.getFieldValue("supporter.phoneNumber2");
- donationData.isEmailOptInChecked = ["supporter.questions.848518", "supporter.questions.848520", "supporter.questions.848521", "supporter.questions.848522", "supporter.questions.848523"].some(field => {
- /** @type {HTMLInputElement} */
- const el = App.getField(field);
- return el && el.checked;
- });
-
- /** @type {HTMLInputElement} */
- //If fee cover is checked, set extra amount to 3% of donation amount and subtract from original donation amount
- const feeCoverCheckbox = App.getField("transaction.feeCover");
- if (feeCoverCheckbox && feeCoverCheckbox.checked) {
- donationData.extraAmount = (DonationAmount.getInstance().amount * 0.03).toFixed(2);
- donationData.originalDonationAmount = donationData.originalDonationAmount - donationData.extraAmount;
- }
- const sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
- if (sendEcardCheckbox && sendEcardCheckbox.checked) {
- donationData.ecardSelected = "true";
+ swapAmounts() {
+ const configs = window.EngridAmounts;
+ if (!configs) return;
+ const freq = this._frequency.frequency;
+ const config = configs[freq];
+ if (!config) return;
+ const stickyDefault = !!config.stickyDefault;
+ // If stickyDefault, always ignore current value so selected flag in list enforces default
+ const ignoreCurrentValue = stickyDefault ? true : this.ignoreCurrentValue();
+ window.EngagingNetworks.require._defined.enjs.swapList("donationAmt", this.toEnAmountList(config), {
+ ignoreCurrentValue
+ });
+ this._amount.load();
+ this.logger.log("Amounts Swapped To", config, {
+ ignoreCurrentValue
+ });
+ this.swapped = true;
}
- sessionStorage.setItem("donationData", JSON.stringify(donationData));
-}
-function trackFormSubmit(App, DonationAmount) {
- //Donation page submits
- if (App.getPageType() === "DONATION" && App.getPageNumber() === 1) {
- setDonationDataSessionStorage(App, DonationAmount);
+ /**
+ * Convert the internal config object into the structure Engaging Networks expects
+ */
+ toEnAmountList(config) {
+ return Object.entries(config.amounts).map(([label, value]) => ({
+ selected: value === config.default,
+ label,
+ value: value.toString()
+ }));
}
-
- //Mobile phone data (for "F32 - Real Time SMS Push" script - opts user into SMS via API)
- /** @type {HTMLInputElement} */
- const mobilePhoneNumber = App.getField("supporter.phoneNumber2");
- if (mobilePhoneNumber) {
- const mobilePhoneData = {};
- mobilePhoneData.phoneNumber = mobilePhoneNumber.value;
- /** @type {HTMLInputElement} */
- const mobilePhoneOptIn = App.getField("supporter.questions.848527") || App.getField("supporter.questions.1952175") || App.getField("supporter.questions.2268563");
- if (mobilePhoneOptIn && mobilePhoneOptIn.checked) {
- mobilePhoneData.optIn = "Y";
+ shouldRun() {
+ const hasNSG = window.EngagingNetworks.suggestedGift !== undefined && Object.keys(window.EngagingNetworks.suggestedGift).length > 0;
+ if (!!window.EngridAmounts && hasNSG) {
+ this.logger.log("Not swapping amounts because NSG is active on page");
+ }
+ return !!window.EngridAmounts && !hasNSG;
+ }
+ ignoreCurrentValue() {
+ const urlParam = dist_engrid_ENGrid.getUrlParameter("transaction.donationAmt");
+ if (urlParam !== null) {
+ const urlAmount = parseFloat(urlParam);
+ return this._amount.amount !== urlAmount;
+ }
+ // If submission failed or donor manually changed away from default, respect current value
+ const submissionFailed = window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed();
+ return !(submissionFailed || this.defaultChange);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/debug-panel.js
+
+class debug_panel_DebugPanel {
+ constructor(pageLayouts) {
+ var _a, _b;
+ this.logger = new dist_logger_EngridLogger("Debug Panel", "#f0f0f0", "#ff0000", "π₯");
+ this.brandingHtml = new branding_html_BrandingHtml();
+ this.element = null;
+ this.currentTimestamp = this.getCurrentTimestamp();
+ this.quickFills = {
+ "pi-general": [{
+ name: "supporter.title",
+ value: "Ms"
+ }, {
+ name: "supporter.firstName",
+ value: "4Site"
+ }, {
+ name: "supporter.lastName",
+ value: "Studio"
+ }, {
+ name: "supporter.emailAddress",
+ value: "en-test@4sitestudios.com"
+ }, {
+ name: "supporter.phoneNumber",
+ value: "555-555-5555"
+ }],
+ "pi-unique": [{
+ name: "supporter.title",
+ value: "Ms"
+ }, {
+ name: "supporter.firstName",
+ value: `4Site ${this.currentTimestamp}`
+ }, {
+ name: "supporter.lastName",
+ value: "Studio"
+ }, {
+ name: "supporter.emailAddress",
+ value: `en-test+${this.currentTimestamp}@4sitestudios.com`
+ }, {
+ name: "supporter.phoneNumber",
+ value: "555-555-5555"
+ }],
+ "us-address": [{
+ name: "supporter.address1",
+ value: "3431 14th St NW"
+ }, {
+ name: "supporter.address2",
+ value: "Suite 1"
+ }, {
+ name: "supporter.city",
+ value: "Washington"
+ }, {
+ name: "supporter.region",
+ value: "DC"
+ }, {
+ name: "supporter.postcode",
+ value: "20010"
+ }, {
+ name: "supporter.country",
+ value: "US"
+ }],
+ "us-address-senate-rep": [{
+ name: "supporter.address1",
+ value: "20 W 34th Street"
+ }, {
+ name: "supporter.address2",
+ value: ""
+ }, {
+ name: "supporter.city",
+ value: "New York"
+ }, {
+ name: "supporter.region",
+ value: "NY"
+ }, {
+ name: "supporter.postcode",
+ value: "10001"
+ }, {
+ name: "supporter.country",
+ value: "US"
+ }],
+ "us-address-nonexistent": [{
+ name: "supporter.address1",
+ value: "12345 Main Street"
+ }, {
+ name: "supporter.address2",
+ value: ""
+ }, {
+ name: "supporter.city",
+ value: "New York"
+ }, {
+ name: "supporter.region",
+ value: "TX"
+ }, {
+ name: "supporter.postcode",
+ value: "90210"
+ }, {
+ name: "supporter.country",
+ value: "US"
+ }],
+ "cc-paysafe-visa": [{
+ name: "transaction.ccnumber",
+ value: "4530910000012345"
+ }, {
+ name: "transaction.ccexpire",
+ value: "12/27"
+ }, {
+ name: "transaction.ccvv",
+ value: "111"
+ }],
+ "cc-paysafe-visa-invalid": [{
+ name: "transaction.ccnumber",
+ value: "411111"
+ }, {
+ name: "transaction.ccexpire",
+ value: "12/27"
+ }, {
+ name: "transaction.ccvv",
+ value: "111"
+ }],
+ "cc-paysafe-mastercard": [{
+ name: "transaction.ccnumber",
+ value: "5036150000001115"
+ }, {
+ name: "transaction.ccexpire",
+ value: "12/27"
+ }, {
+ name: "transaction.ccvv",
+ value: "111"
+ }],
+ "cc-stripe-visa": [{
+ name: "transaction.ccnumber",
+ value: "4242424242424242"
+ }, {
+ name: "transaction.ccexpire",
+ value: "12/27"
+ }, {
+ name: "transaction.ccvv",
+ value: "111"
+ }],
+ "quick-fill-pi-unique-us-address-senate-rep-cc-stripe-visa": [{
+ name: "supporter.title",
+ value: "Ms"
+ }, {
+ name: "supporter.firstName",
+ value: `4Site ${this.currentTimestamp}`
+ }, {
+ name: "supporter.lastName",
+ value: "Studio"
+ }, {
+ name: "supporter.emailAddress",
+ value: `en-test+${this.currentTimestamp}@4sitestudios.com`
+ }, {
+ name: "supporter.phoneNumber",
+ value: "555-555-5555"
+ }, {
+ name: "supporter.address1",
+ value: "20 W 34th Street"
+ }, {
+ name: "supporter.address2",
+ value: ""
+ }, {
+ name: "supporter.city",
+ value: "New York"
+ }, {
+ name: "supporter.region",
+ value: "NY"
+ }, {
+ name: "supporter.postcode",
+ value: "10001"
+ }, {
+ name: "supporter.country",
+ value: "US"
+ }, {
+ name: "transaction.ccnumber",
+ value: "4242424242424242"
+ }, {
+ name: "transaction.ccexpire",
+ value: "12/27"
+ }, {
+ name: "transaction.ccvv",
+ value: "111"
+ }]
+ };
+ this.logger.log("Adding debug panel and starting a debug session");
+ this.pageLayouts = pageLayouts;
+ this.loadDebugPanel();
+ this.element = document.querySelector(".debug-panel");
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
+ var _a;
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.add("debug-panel--open");
+ });
+ const debugPanelClose = document.querySelector(".debug-panel__close");
+ debugPanelClose === null || debugPanelClose === void 0 ? void 0 : debugPanelClose.addEventListener("click", e => {
+ var _a;
+ e.stopPropagation();
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.remove("debug-panel--open");
+ });
+ if (dist_engrid_ENGrid.getUrlParameter("assets") === "local") {
+ (_b = this.element) === null || _b === void 0 ? void 0 : _b.classList.add("debug-panel--local");
}
- sessionStorage.setItem("mobilePhoneData", JSON.stringify(mobilePhoneData));
+ window.sessionStorage.setItem(debug_panel_DebugPanel.debugSessionStorageKey, "active");
}
-
- //Track ETT, petition, survey and data capture submits
- if (["ADVOCACY", "EMAILTOTARGET", "SURVEY"].includes(App.getPageType())) {
- if (App.getFieldValue("supporter.emailAddress") === "") {
- return;
+ loadDebugPanel() {
+ document.body.insertAdjacentHTML("beforeend", `
+
+
Debug
+
+
+
+
+ Quick-fill
+
+ Choose an option
+ Quick-fill - Unique w/ Senate Address - Stripe Visa
+ Personal Info - General
+ Personal Info - Unique
+ US Address - w/ Senate Rep
+ US Address - w/o Senate Rep
+ US Address - Nonexistent
+ CC - Paysafe - Visa
+ CC - Paysafe - Visa (Invalid)
+ CC - Paysafe - Mastercard
+ CC - Stripe - Visa
+
+
+
+ Layout
+
+
+
+
+
+
+ Embedded layout
+
+
+
+
+
+ Theme
+
+
+
+ Sub-theme
+
+
+
+ Submit form
+
+
+
+
+
+
`);
+ this.setupLayoutSwitcher();
+ this.setupThemeSwitcher();
+ this.setupSubThemeSwitcher();
+ this.setupFormQuickfill();
+ this.createDebugSessionEndHandler();
+ this.setupEmbeddedLayoutSwitcher();
+ this.setupDebugLayoutSwitcher();
+ this.setupBrandingHtmlHandler();
+ this.setupEditBtnHandler();
+ this.setupForceSubmitLinkHandler();
+ this.setupSubmitBtnHandler();
+ }
+ switchENGridLayout(layout) {
+ dist_engrid_ENGrid.setBodyData("layout", layout);
+ }
+ setupLayoutSwitcher() {
+ var _a, _b;
+ const engridLayoutSwitch = document.getElementById("engrid-layout-switch");
+ if (engridLayoutSwitch) {
+ (_a = this.pageLayouts) === null || _a === void 0 ? void 0 : _a.forEach(layout => {
+ engridLayoutSwitch.insertAdjacentHTML("beforeend", `${layout} `);
+ });
+ engridLayoutSwitch.value = (_b = dist_engrid_ENGrid.getBodyData("layout")) !== null && _b !== void 0 ? _b : "";
+ engridLayoutSwitch.addEventListener("change", e => {
+ const target = e.target;
+ this.switchENGridLayout(target.value);
+ });
}
- let utagData = {};
- utagData.form_type = pageJson.pageType;
- utagData.form_name = utag_data.page_name.slice(0, -2);
- utagData.action_id = utag_data.form_name;
- utagData.action_type = pageJson.pageType;
- utagData.zip_code = App.getFieldValue("supporter.postcode");
- utagData.email_signup_location = pageJson.pageType;
-
- // New utag variables fields for Google Ads Enhanced Conversions for ETT & PET
- utagData.const_first = App.getFieldValue("supporter.firstName");
- utagData.const_last = App.getFieldValue("supporter.lastName");
- utagData.const_address = App.getFieldValue("supporter.address1");
- utagData.const_city = App.getFieldValue("supporter.city");
- utagData.customer_state = App.getFieldValue("supporter.region");
- utagData.customer_postal_code = App.getFieldValue("supporter.postcode");
- utagData.customer_country = App.getFieldValue("supporter.country");
- utagData.const_phone = App.getFieldValue("supporter.phoneNumber2");
- const eventName = getSubmitEventName(App);
- if (eventName === "frm_emt_txt_submit" || eventName === "frm_emt_emo_txt_submit") {
- utagData.text_signup_location = pageJson.pageType;
+ }
+ setupThemeSwitcher() {
+ var _a;
+ const engridThemeInput = document.getElementById("engrid-theme");
+ if (engridThemeInput) {
+ engridThemeInput.value = (_a = dist_engrid_ENGrid.getBodyData("theme")) !== null && _a !== void 0 ? _a : "";
+ ["keyup", "blur"].forEach(ev => {
+ engridThemeInput.addEventListener(ev, e => {
+ const target = e.target;
+ this.switchENGridTheme(target.value);
+ });
+ });
}
- trackEvent(eventName, utagData);
}
-}
-function getSubmitEventName(App) {
- const isOptedInToPhone = ["supporter.questions.848528", "supporter.questions.1952175", "supporter.questions.848527", "supporter.questions.891102"].some(field => {
- /** @type {HTMLInputElement} */
- const el = App.getField(field);
- return el && el.checked && App.getFieldValue("supporter.phoneNumber2") !== "" || el && el.checked && field.split(".")[2] === "891102" && App.getFieldValue("supporter.phoneNumber");
- });
- const isOptedInToEmail = ["supporter.questions.848518", "supporter.questions.848520", "supporter.questions.848521", "supporter.questions.848522", "supporter.questions.848523"].some(field => {
- /** @type {HTMLInputElement} */
- const el = App.getField(field);
- return el && el.checked;
- });
- if (isOptedInToEmail && isOptedInToPhone) {
- return "frm_emt_emo_txt_submit";
+ switchENGridTheme(theme) {
+ dist_engrid_ENGrid.setBodyData("theme", theme);
}
- if (isOptedInToPhone) {
- return "frm_emt_txt_submit";
+ setupSubThemeSwitcher() {
+ var _a;
+ const engridSubthemeInput = document.getElementById("engrid-subtheme");
+ if (engridSubthemeInput) {
+ engridSubthemeInput.value = (_a = dist_engrid_ENGrid.getBodyData("subtheme")) !== null && _a !== void 0 ? _a : "";
+ ["keyup", "blur"].forEach(ev => {
+ engridSubthemeInput.addEventListener(ev, e => {
+ const target = e.target;
+ this.switchENGridSubtheme(target.value);
+ });
+ });
+ }
}
- if (isOptedInToEmail) {
- return "frm_emt_emo_submit";
+ switchENGridSubtheme(subtheme) {
+ dist_engrid_ENGrid.setBodyData("subtheme", subtheme);
}
- return "frm_emt_submit";
-}
-function trackFormErrors() {
- setTimeout(() => {
- let invalidFields = "";
- let errors = "";
-
- // Gather invalid fields and error messages
- document.querySelectorAll(".en__field--validationFailed").forEach(el => {
- if (el.querySelector(".en__field__error")) {
- invalidFields += `${el.querySelector(".en__field__input").getAttribute("name")}|`;
- errors += `${el.querySelector(".en__field__error").textContent}|`;
- }
- });
-
- // Fire tracking if errors were found
- if (invalidFields !== "") {
- trackEvent("form_error", {
- form_field_error_field: invalidFields.slice(0, -1),
- form_field_error_value: errors.slice(0, -1),
- form_name: utag_data.page_name.slice(0, -2),
- form_type: pageJson.pageType
+ setupFormQuickfill() {
+ const engridQuickfill = document.getElementById("engrid-form-quickfill");
+ engridQuickfill === null || engridQuickfill === void 0 ? void 0 : engridQuickfill.addEventListener("change", e => {
+ const target = e.target;
+ this.quickFills[target.value].forEach(qf => {
+ this.setFieldValue(qf);
});
+ });
+ }
+ setFieldValue(qf) {
+ if (qf.name === "transaction.ccexpire") {
+ const ccExpireEls = document.getElementsByName("transaction.ccexpire");
+ if (ccExpireEls.length > 0) {
+ const expirationDate = qf.value.split("/");
+ ccExpireEls[0].value = expirationDate[0];
+ ccExpireEls[1].value = expirationDate[1];
+ ccExpireEls[0].dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ ccExpireEls[1].dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ } else {
+ ccExpireEls[0].value = qf.value;
+ ccExpireEls[0].dispatchEvent(new Event("change", {
+ bubbles: true
+ }));
+ }
+ return;
}
- }, 500);
-}
-function trackProcessingErrors(App) {
- const errorList = document.querySelector(".en__errorList");
- if (errorList && errorList.textContent.trim() !== "") {
- trackEvent("form_error", {
- form_field_error_field: "payment error",
- form_field_error_value: "payment error",
- payment_type: App.getPaymentType(),
- form_name: utag_data.page_name.slice(0, -2),
- form_type: pageJson.pageType
+ dist_engrid_ENGrid.setFieldValue(qf.name, qf.value, true, true);
+ }
+ getCurrentTimestamp() {
+ const now = new Date();
+ const year = now.getFullYear();
+ const month = String(now.getMonth() + 1).padStart(2, "0");
+ const day = String(now.getDate()).padStart(2, "0");
+ const hours = String(now.getHours()).padStart(2, "0");
+ const minutes = String(now.getMinutes()).padStart(2, "0");
+ return `${year}${month}${day}-${hours}${minutes}`;
+ }
+ createDebugSessionEndHandler() {
+ const debugSessionEndBtn = document.querySelector(".debug-panel__end-debug-link");
+ debugSessionEndBtn === null || debugSessionEndBtn === void 0 ? void 0 : debugSessionEndBtn.addEventListener("click", () => {
+ var _a;
+ this.logger.log("Removing panel and ending debug session");
+ (_a = this.element) === null || _a === void 0 ? void 0 : _a.remove();
+ window.sessionStorage.removeItem(debug_panel_DebugPanel.debugSessionStorageKey);
});
}
-}
-function trackUrlParams() {
- const params = new URLSearchParams(location.search);
- const trackers = ["src", "vid", "vid2", "en_txn1", "en_txn2", "en_txn3", "en_txn4", "en_txn5", "en_txn7", "en_txn8", "en_txn9", "en_txn10"];
- let visitData = sessionStorage.getItem("visitData") ? JSON.parse(sessionStorage.getItem("visitData")) : {};
- trackers.forEach(tracker => {
- if (params.has(tracker)) {
- visitData[tracker] = params.get(tracker);
+ setupEmbeddedLayoutSwitcher() {
+ const embeddedLayoutSwitch = document.getElementById("engrid-embedded-layout");
+ if (embeddedLayoutSwitch) {
+ embeddedLayoutSwitch.checked = !!dist_engrid_ENGrid.getBodyData("embedded");
+ embeddedLayoutSwitch.addEventListener("change", e => {
+ const target = e.target;
+ dist_engrid_ENGrid.setBodyData("embedded", target.checked);
+ });
}
- });
- sessionStorage.setItem("visitData", JSON.stringify(visitData));
-}
-function trackUserInteractions() {
- // Track clicks on social share buttons
- document.querySelectorAll(".en__socialShare__image").forEach(el => {
- el.addEventListener("click", e => {
- trackEvent("social_share", {
- social_share_id: `preserve.nature.org.share.${e.target.parentElement.dataset.enshare}`,
- social_share_platform: e.target.parentElement.dataset.enshare
+ }
+ setupDebugLayoutSwitcher() {
+ const debugLayoutSwitch = document.getElementById("engrid-debug-layout");
+ if (debugLayoutSwitch) {
+ debugLayoutSwitch.checked = dist_engrid_ENGrid.getBodyData("debug") === "layout";
+ debugLayoutSwitch.addEventListener("change", e => {
+ const target = e.target;
+ if (target.checked) {
+ dist_engrid_ENGrid.setBodyData("debug", "layout");
+ } else {
+ dist_engrid_ENGrid.setBodyData("debug", "");
+ }
});
+ }
+ }
+ setupBrandingHtmlHandler() {
+ const brandingInput = document.getElementById("engrid-branding");
+ brandingInput.checked = dist_engrid_ENGrid.getUrlParameter("development") === "branding";
+ brandingInput.addEventListener("change", e => {
+ if (brandingInput.checked) {
+ this.brandingHtml.show();
+ } else {
+ this.brandingHtml.hide();
+ }
});
- });
+ }
+ setupEditBtnHandler() {
+ const editBtn = document.querySelector(".debug-panel__edit-link");
+ editBtn === null || editBtn === void 0 ? void 0 : editBtn.addEventListener("click", () => {
+ window.open(`https://${dist_engrid_ENGrid.getDataCenter()}.engagingnetworks.app/index.html#pages/${dist_engrid_ENGrid.getPageID()}/edit`, "_blank");
+ });
+ }
+ setupForceSubmitLinkHandler() {
+ const submitBtn = document.querySelector(".debug-panel__force-submit-link");
+ submitBtn === null || submitBtn === void 0 ? void 0 : submitBtn.addEventListener("click", () => {
+ const enForm = document.querySelector("form.en__component");
+ enForm === null || enForm === void 0 ? void 0 : enForm.submit();
+ });
+ }
+ setupSubmitBtnHandler() {
+ const submitBtn = document.querySelector(".debug-panel__btn--submit");
+ submitBtn === null || submitBtn === void 0 ? void 0 : submitBtn.addEventListener("click", () => {
+ const enForm = document.querySelector(".en__submit button");
+ enForm === null || enForm === void 0 ? void 0 : enForm.click();
+ });
+ }
+}
+debug_panel_DebugPanel.debugSessionStorageKey = "engrid_debug_panel";
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/debug-hidden-fields.js
+// Switches hidden fields to be type text when debug mode is enabled.
- // Track clicks on footer links
- document.querySelectorAll(".main-page-footer a").forEach(el => {
- el.addEventListener("click", e => {
- trackEvent("footer_nav_click", {
- nav_click_location: `preserve.nature.org.fnav.${e.target.textContent.toLowerCase()}`
+class debug_hidden_fields_DebugHiddenFields {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Debug hidden fields", "#f0f0f0", "#ff0000", "π«£");
+ this.ignoreFields = ["transaction.paycurrency"];
+ // Query all hidden input elements within the specified selectors
+ const fields = document.querySelectorAll(".en__component--row [type='hidden'][class*='en_'], .engrid-added-input[type='hidden']");
+ // Check if there are any hidden fields
+ if (fields.length > 0) {
+ // Log the names of the hidden fields being changed to type 'text'
+ this.logger.log(`Switching the following type 'hidden' fields to type 'text': ${[...fields].map(f => f.name).join(", ")}`);
+ // Iterate through each hidden input element
+ fields.forEach(el => {
+ // Check if the field name is in the ignore list
+ if (this.ignoreFields.includes(el.name)) {
+ this.logger.log(`Ignoring field: ${el.name} because it is in the ignore list`);
+ return;
+ }
+ // Change the input type to 'text' and add the required classes
+ el.type = "text";
+ el.classList.add("en__field__input", "en__field__input--text");
+ // Create a new label element and set its text and classes
+ const label = document.createElement("label");
+ label.textContent = "Hidden field: " + el.name;
+ label.classList.add("en__field__label");
+ // Create a new 'div' element for the input field and add the required classes
+ const fieldElement = document.createElement("div");
+ fieldElement.classList.add("en__field__element", "en__field__element--text");
+ // Create a new 'div' container for the label and input field, and add the required classes and attribute
+ const fieldContainer = document.createElement("div");
+ fieldContainer.classList.add("en__field", "en__field--text", "hide");
+ fieldContainer.dataset.unhidden = "";
+ fieldContainer.appendChild(label);
+ fieldContainer.appendChild(fieldElement);
+ // Insert the new field container before the original input element and move the input element into the field element div
+ if (el.parentNode) {
+ el.parentNode.insertBefore(fieldContainer, el);
+ fieldElement.appendChild(el);
+ }
});
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/branding-html.js
+var dist_branding_html_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function (resolve) {
+ resolve(value);
});
+ }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
+ }
+ }
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
+ }
+ }
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
});
+};
+/**
+ * Inserts all of the branding HTML from https://github.com/4site-interactive-studios/engrid/tree/main/reference-materials/html/brand-guide-markup
+ * into the body-main section of the page.
+ */
+class branding_html_BrandingHtml {
+ constructor() {
+ this.assetBaseUrl = "https://cdn.jsdelivr.net/gh/4site-interactive-studios/engrid@main/reference-materials/html/brand-guide-markup/";
+ this.brandingHtmlFiles = ["html5-tags.html", "en-common-fields.html", "survey.html",
+ // "en-common-fields-with-errors.html",
+ // "en-common-fields-with-fancy-errors.html",
+ "donation-page.html", "premium-donation.html", "ecards.html", "email-to-target.html", "tweet-to-target.html",
+ // "click-to-call.html",
+ "petition.html", "event.html",
+ // "ecommerce.html",
+ // "membership.html",
+ "styles.html"];
+ this.bodyMain = document.querySelector(".body-main");
+ this.htmlFetched = false;
+ }
+ fetchHtml() {
+ return dist_branding_html_awaiter(this, void 0, void 0, function* () {
+ const htmlRequests = this.brandingHtmlFiles.map(file => dist_branding_html_awaiter(this, void 0, void 0, function* () {
+ const res = yield fetch(this.assetBaseUrl + file);
+ return res.text();
+ }));
+ const brandingHtmls = yield Promise.all(htmlRequests);
+ return brandingHtmls;
+ });
+ }
+ appendHtml() {
+ this.fetchHtml().then(html => html.forEach(h => {
+ var _a;
+ const brandingSection = document.createElement("div");
+ brandingSection.classList.add("brand-guide-section");
+ brandingSection.innerHTML = h;
+ (_a = this.bodyMain) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement("beforeend", brandingSection);
+ }));
+ this.htmlFetched = true;
+ }
+ show() {
+ if (!this.htmlFetched) {
+ this.appendHtml();
+ return;
+ }
+ const guides = document.querySelectorAll(".brand-guide-section");
+ guides === null || guides === void 0 ? void 0 : guides.forEach(g => g.style.display = "block");
+ }
+ hide() {
+ const guides = document.querySelectorAll(".brand-guide-section");
+ guides === null || guides === void 0 ? void 0 : guides.forEach(g => g.style.display = "none");
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/country-disable.js
+// This class allows you to disable some countries from the country dropdown list.
- // Track en upsell modal opening
- const observer = new MutationObserver((mutationsList, observer) => {
- for (const mutation of mutationsList) {
- if (mutation.addedNodes) {
- mutation.addedNodes.forEach(node => {
- if (node.firstChild && node.firstChild.id === "en__upsellModal") {
- //Track lightbox opened
- trackEvent("lightbox_impression", {
- lightbox_name: "sustainer upsell"
- });
- //Track if 'yes' is clicked on lightbox
- document.getElementById("en__upsellModal__yes").addEventListener("click", () => {
- trackEvent("lightbox_click", {
- lightbox_name: "sustainer upsell"
- });
- });
- observer.disconnect();
+class country_disable_CountryDisable {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("CountryDisable", "#f0f0f0", "#333333", "π");
+ const countries = document.querySelectorAll('select[name="supporter.country"], select[name="transaction.shipcountry"], select[name="supporter.billingCountry"], select[name="transaction.infcountry"]');
+ const CountryDisable = dist_engrid_ENGrid.getOption("CountryDisable");
+ // Remove the countries from the dropdown list
+ if (countries.length > 0 && CountryDisable.length > 0) {
+ const countriesLower = CountryDisable.map(country => country.toLowerCase());
+ countries.forEach(country => {
+ country.querySelectorAll("option").forEach(option => {
+ if (countriesLower.includes(option.value.toLowerCase()) || countriesLower.includes(option.text.toLowerCase())) {
+ this.logger.log(`Removing ${option.text} from ${country.getAttribute("name")}`);
+ option.remove();
}
});
- }
+ });
}
- });
- observer.observe(document, {
- childList: true,
- subtree: true
- });
+ }
}
-;// CONCATENATED MODULE: ./src/scripts/main.js
-
-const main_tippy = (__webpack_require__(9244)/* ["default"] */ .Ay);
-const customScript = function (App, DonationFrequency, DonationAmount) {
- const freq = DonationFrequency.getInstance();
- const amt = DonationAmount.getInstance();
- console.log("ENGrid client scripts are executing");
- // Add your client scripts here
- var checkForServerError = document.querySelector(".en__errorList *");
- if (checkForServerError) {
- console.log("Has server error!");
- } else {
- console.log("Does not have a server error!");
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/premium-gift.js
+// Component to handle premium gift features
+// 1 - Add a class to body to indicate which premium gift is selected (data-engrid-premium-gift-name="item-name-slugged")
+// 2 - Add a class to body to indicate if the "maximize my impact" is selected (data-engrid-premium-gift-maximize="true|false")
+// 3 - Check the premium gift when click on the title or description
+// 4 - Create new {$PREMIUMTITLE} merge tag that's replaced with the premium gift name
+// 5 - Add aria-label to the radio inputs and alt tags to the images
- // Check if the first field is in the viewport
- let firstElement = document.querySelector(".en__component--formblock");
- if (firstElement) {
- firstElement.id = "firstElement";
- let bounding = firstElement.getBoundingClientRect();
- if (bounding.top >= 0 && bounding.left >= 0 && bounding.right <= window.innerWidth && bounding.bottom <= window.innerHeight) {
- console.log("First field is in the viewport!");
- } else {
- console.log("First field is NOT in the viewport! Add hover button");
- const floatingButton = document.createElement("div");
- const floatingButtonLabelElement = document.querySelector(".floating-button-label");
- const floatingButtonLabel = floatingButtonLabelElement?.innerText ?? "Take Action";
- floatingButton.id = "floating-button";
- floatingButton.className = "arrow";
- floatingButton.innerHTML = ``;
- const advRow = document.querySelector(".en__component--advrow");
- if (advRow) {
- advRow.append(floatingButton);
- }
- floatingButton.querySelector(".pseduo__en__submit_button").addEventListener("click", function (e) {
- e.preventDefault();
- document.querySelector("#firstElement").scrollIntoView({
- behavior: "smooth",
- block: "center"
- });
- });
- document.addEventListener("scroll", function (e) {
- const button = document.querySelector("#floating-button");
- if (window.scrollY < 100) {
- button.classList.add("show");
- } else {
- button.classList.remove("show");
+class premium_gift_PremiumGift {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("PremiumGift", "#232323", "#f7b500", "π");
+ this.enElements = new Array();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._amount = donation_amount_DonationAmount.getInstance();
+ if (!this.shoudRun()) return;
+ this.searchElements();
+ this.addEventListeners();
+ this.checkPremiumGift();
+ window.setTimeout(() => {
+ this.altsAndArias();
+ this.maxDonationAria();
+ }, 1000);
+ }
+ shoudRun() {
+ return "pageJson" in window && "pageType" in window.pageJson && window.pageJson.pageType === "premiumgift";
+ }
+ addEventListeners() {
+ ["click", "change"].forEach(event => {
+ document.addEventListener(event, e => {
+ const element = e.target;
+ const premiumGift = element.closest(".en__pg__body");
+ if (premiumGift) {
+ const premiumGiftInput = premiumGift.querySelector('[name="en__pg"]');
+ if ("type" in element === false) {
+ const premiumGiftValue = premiumGiftInput.value;
+ window.setTimeout(() => {
+ const newPremiumGift = document.querySelector('[name="en__pg"][value="' + premiumGiftValue + '"]');
+ if (newPremiumGift) {
+ newPremiumGift.checked = true;
+ newPremiumGift.dispatchEvent(new Event("change"));
+ }
+ }, 100);
}
- });
- window.setTimeout(() => {
- if (window.scrollY < 100) {
- floatingButton.classList.add("show");
+ window.setTimeout(() => {
+ this.checkPremiumGift();
+ }, 110);
+ }
+ });
+ });
+ // Check when visibility of the Premium Gift Block changes.
+ // EN will add "display: none" to this element when the supporter does not qualify for a premium
+ const premiumGiftsBlock = document.querySelector(".en__component--premiumgiftblock");
+ if (premiumGiftsBlock) {
+ const observer = new MutationObserver(mutationsList => {
+ for (const mutation of mutationsList) {
+ if (mutation.type === "attributes" && mutation.attributeName === "style") {
+ if (premiumGiftsBlock.style.display === "none") {
+ this.logger.log("Premium Gift Section hidden - removing premium gift body data attributes and premium title.");
+ dist_engrid_ENGrid.setBodyData("premium-gift-maximize", false);
+ dist_engrid_ENGrid.setBodyData("premium-gift-name", false);
+ this.setPremiumTitle("");
+ }
}
- }, 200);
+ }
+ });
+ observer.observe(premiumGiftsBlock, {
+ attributes: true
+ });
+ }
+ this._frequency.onFrequencyChange.subscribe(() => {
+ window.setTimeout(() => {
+ this.altsAndArias();
+ }, 1000);
+ });
+ this._amount.onAmountChange.subscribe(() => {
+ window.setTimeout(() => {
+ this.altsAndArias();
+ }, 1000);
+ });
+ }
+ checkPremiumGift() {
+ const premiumGift = document.querySelector('[name="en__pg"]:checked');
+ if (premiumGift) {
+ const premiumGiftValue = premiumGift.value;
+ this.logger.log("Premium Gift Value: " + premiumGiftValue);
+ const premiumGiftContainer = premiumGift.closest(".en__pg");
+ if (premiumGiftValue !== "0") {
+ const premiumGiftName = premiumGiftContainer.querySelector(".en__pg__name");
+ dist_engrid_ENGrid.setBodyData("premium-gift-maximize", "false");
+ dist_engrid_ENGrid.setBodyData("premium-gift-name", dist_engrid_ENGrid.slugify(premiumGiftName.innerText));
+ this.setPremiumTitle(premiumGiftName.innerText);
+ } else {
+ dist_engrid_ENGrid.setBodyData("premium-gift-maximize", "true");
+ dist_engrid_ENGrid.setBodyData("premium-gift-name", false);
+ this.setPremiumTitle("");
+ }
+ if (!premiumGiftContainer.classList.contains("en__pg--selected")) {
+ const checkedPremiumGift = document.querySelector(".en__pg--selected");
+ if (checkedPremiumGift) {
+ checkedPremiumGift.classList.remove("en__pg--selected");
+ }
+ premiumGiftContainer.classList.add("en__pg--selected");
}
}
}
-
- ////////////////////////////////////////////
- // START ENGRID TRANSITION SCRIPTS
- ////////////////////////////////////////////
- const texts = {
- en: {
- emailFieldNotice: "You'll receive email updates from The Nature Conservancy. You can unsubscribe at any time.",
- phoneNumberNotice: "By sharing your phone number, you give The Nature Conservancy permission to contact you with updates via phone and text.",
- cvvTooltipLabel: "What is a CVV number?",
- cvvTooltip: "The CVV is a 3- or 4-digit code printed on your credit card. It's a fraud-prevention measure designed to make it harder to use info stolen in a data breach.",
- bankNumberTooltipLabel: "What is this?",
- bankNumberTooltip: "Your routing number is the 9-digit number at the bottom left of your check."
- },
- es: {
- emailFieldNotice: "RecibirΓ‘s noticias de TNC periΓ³dicamente. Puedes cancelar tu suscripciΓ³n en cualquier momento.",
- phoneNumberNotice: "Al compartir tu nΓΊmero telefΓ³nico, autorizas a TNC a contactarte y enviarte noticias por telΓ©fono o por mensaje de texto.",
- cvvTooltipLabel: "ΒΏQuΓ© es un CVV?",
- cvvTooltip: "El CVV es un cΓ³digo de 3 Γ³ 4 dΓgitos impreso en su tarjeta de crΓ©dito. Es una medida de prevenciΓ³n de fraude diseΓ±ada para dificultar el uso de informaciΓ³n robada en filtraciones de datos.",
- bankNumberTooltipLabel: "ΒΏQuΓ© es esto?",
- bankNumberTooltip: "Su nΓΊmero de ruta es el nΓΊmero de 9 dΓgitos que aparece en la parte inferior izquierda de su cheque."
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field
+ `);
+ if (enElements.length > 0) {
+ enElements.forEach(item => {
+ if (item instanceof HTMLElement && item.innerHTML.includes("{$PREMIUMTITLE}")) {
+ item.innerHTML = item.innerHTML.replace("{$PREMIUMTITLE}", ` `);
+ this.enElements.push(item);
+ }
+ });
}
- };
- const text = texts[window.pageJson.locale.slice(0, 2)] ?? texts.en;
-
- // Position monthly upsell after the recurring frequency field
- let inlineMonthlyUpsell = document.querySelector(".move-after--transaction-recurrfreq");
- let recurrFrequencyField = document.querySelector(".en__field--recurrfreq");
- if (inlineMonthlyUpsell && recurrFrequencyField) {
- recurrFrequencyField.insertAdjacentElement("beforeend", inlineMonthlyUpsell);
}
- const emailField = document.querySelector('[name="supporter.emailAddress"]');
- if (emailField && emailField.type !== "hidden") {
- // Add a notice to the email field
- App.addHtml(`${text.emailFieldNotice}
`, '[name="supporter.emailAddress"]', "after");
+ setPremiumTitle(title) {
+ this.enElements.forEach(item => {
+ const premiumTitle = item.querySelector(".engrid_premium_title");
+ if (premiumTitle) {
+ premiumTitle.innerHTML = title;
+ }
+ });
}
+ // Sets alt tags for premium gift images and aria tags for premium gift radio inputs
+ altsAndArias() {
+ const premiumTitle = document.querySelectorAll(".en__pg__detail h2.en__pg__name");
+ const multistepBackButton = document.querySelectorAll(".multistep-button-container button.btn-back");
+ premiumTitle.forEach(item => {
+ if (item) {
+ const titleText = item.innerHTML;
+ const parent = item.parentElement;
+ const prevSibling = parent === null || parent === void 0 ? void 0 : parent.previousElementSibling;
+ const radioInputSibling = prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.previousElementSibling;
+ if (prevSibling) {
+ const imageDiv = prevSibling.querySelector(".en__pg__images");
+ if (imageDiv) {
+ const img = imageDiv.querySelector("img");
+ if (img) {
+ img.setAttribute("alt", titleText);
+ img.style.width = "125px";
+ img.style.height = "100px";
+ }
+ }
+ }
+ if (radioInputSibling) {
+ const radioInput = radioInputSibling.querySelector('input[type="radio"]');
+ if (radioInput) {
+ radioInput.setAttribute("aria-label", titleText);
+ }
+ }
+ }
+ multistepBackButton.forEach(item => {
+ item.setAttribute("aria-label", "Back");
+ });
+ });
+ }
+ // This is for the Maximize My Donation aria-label - the tree structure for it is slightly different.
+ maxDonationAria() {
+ const maxDonationTitle = Array.from(document.querySelectorAll(".en__pg__detail")).filter(el => !el.querySelector("h2"));
+ maxDonationTitle.forEach(item => {
+ var _a;
+ if (item) {
+ const titleText = ((_a = item.querySelector(".en__pg__description")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "";
+ const prevSibling = item.previousElementSibling;
+ const radioInputSibling = prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.previousElementSibling;
+ if (radioInputSibling) {
+ const radioInput = radioInputSibling.querySelector('input[type="radio"]');
+ if (radioInput) {
+ radioInput.setAttribute("aria-label", titleText);
+ }
+ }
+ }
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/custom-premium.js
+// ENgrid component: CustomPremium
+// Filters premium gifts based on window.EngridPageOptions.CustomPremium configuration
+// Rules:
+// - Config shape: window.EngridPageOptions.CustomPremium[frequency][productId] = minimumAmount
+// - On frequency or amount change, wait 500ms (allow EN to re-render), then:
+// - Show only gifts whose minimumAmount <= current amount; hide others
+// - If none visible, hide entire .en__component--premiumgiftblock
+// - If current selection becomes invalid, select default; if default not visible, select "No Premium" and clear transaction.selprodvariantid
+// - Run once 500ms after page load
+// - Add EnForm onSubmit hook to clear transaction.selprodvariantid when no visible premium items
- // Add a notice to the phone number field
- App.addHtml(`${text.phoneNumberNotice}
`, '[name="supporter.phoneNumber2"]', "after");
-
- /**
- * Add a Tippy tooltip to a field
- * @param {HTMLElement} labelElement
- * @param {string} fieldName
- * @param {string} labelText
- * @param {string} tooltipText
- */
- function addTooltip(labelElement, fieldName, labelText, tooltipText) {
- if (!labelElement) {
+class custom_premium_CustomPremium {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("CustomPremium", "teal", "white", "π§©");
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._enForm = events_en_form_EnForm.getInstance();
+ this.stylesInjected = false;
+ this.pendingFrequencyChange = false;
+ if (!this.shouldRun()) return;
+ this.injectStyles();
+ // Initial run: execute once after 500ms
+ window.setTimeout(() => this.run(), 500);
+ // On changes, schedule processing and fade out immediately
+ this._amount.onAmountChange.subscribe(() => this.scheduleRun());
+ this._frequency.onFrequencyChange.subscribe(() => {
+ this.pendingFrequencyChange = true;
+ this.scheduleRun();
+ });
+ // Clear hidden variant field on submit if there are no visible premium items
+ this._enForm.onSubmit.subscribe(() => {
+ if (!this.hasVisiblePremiumItems()) {
+ this.clearVariantField();
+ }
+ });
+ }
+ shouldRun() {
+ const isPremiumPage = "pageJson" in window && "pageType" in window.pageJson && window.pageJson.pageType === "premiumgift";
+ const hasConfig = !!dist_engrid_ENGrid.getOption("CustomPremium");
+ return isPremiumPage && hasConfig;
+ }
+ get config() {
+ const cfg = dist_engrid_ENGrid.getOption("CustomPremium");
+ return cfg || null;
+ }
+ get premiumContainer() {
+ return document.querySelector(".en__component--premiumgiftblock");
+ }
+ get giftItems() {
+ return Array.from(document.querySelectorAll(".en__pg"));
+ }
+ getFrequencyConfig(frequency) {
+ const customPremiumConfig = this.config;
+ if (!customPremiumConfig) return null;
+ const frequencyConfig = customPremiumConfig[frequency];
+ if (frequencyConfig && typeof frequencyConfig === "object") return frequencyConfig;
+ return null;
+ }
+ getProductsMap(frequency) {
+ const frequencyConfig = this.getFrequencyConfig(frequency);
+ const productsMap = {};
+ if (!frequencyConfig) return productsMap;
+ // If explicit products object exists, use it
+ if (frequencyConfig.products && typeof frequencyConfig.products === "object") {
+ Object.entries(frequencyConfig.products).forEach(([productId, min]) => {
+ const id = String(productId);
+ const minAmount = Number(min);
+ if (!isNaN(minAmount)) productsMap[id] = minAmount;
+ });
+ return productsMap;
+ }
+ // Otherwise, treat own numeric-value keys as products, ignore 'default'
+ Object.entries(frequencyConfig).forEach(([key, value]) => {
+ if (key === "default") return;
+ const minAmount = Number(value);
+ if (!isNaN(minAmount)) productsMap[String(key)] = minAmount;
+ });
+ return productsMap;
+ }
+ getConfiguredDefaultPid(frequency) {
+ const frequencyConfig = this.getFrequencyConfig(frequency);
+ if (!frequencyConfig) return null;
+ const defaultValue = frequencyConfig.default;
+ if (defaultValue === undefined || defaultValue === null) return "0"; // not set => No Premium by spec
+ const id = String(defaultValue);
+ return id;
+ }
+ injectStyles() {
+ if (this.stylesInjected) return;
+ const id = "engrid-custom-premium-style";
+ if (document.getElementById(id)) {
+ this.stylesInjected = true;
return;
}
- let link = document.createElement("a");
- link.href = "#";
- link.id = fieldName + "-tooltip";
- link.className = fieldName + "-tooltip tippy-label";
- link.tabIndex = -1;
- link.innerText = labelText;
- link.addEventListener("click", e => e.preventDefault());
- labelElement.insertAdjacentElement("afterend", link);
- let wrapper = document.createElement("span");
- wrapper.className = "label-wrapper";
- labelElement.parentNode.insertBefore(wrapper, labelElement);
- wrapper.appendChild(labelElement);
- wrapper.appendChild(link);
- main_tippy("#" + fieldName + "-tooltip", {
- content: tooltipText,
- theme: "light-border"
+ const style = document.createElement("style");
+ style.id = id;
+ style.innerHTML = `
+ .en__component--premiumgiftblock { transition: opacity 200ms ease-in-out; }
+ .en__component--premiumgiftblock.engrid-premium-processing { opacity: 0; pointer-events: none; }
+ .en__component--premiumgiftblock.engrid-premium-hidden { display: none !important; }
+ .en__component--premiumgiftblock.engrid-premium-ready { opacity: 1; }
+ `;
+ document.head.appendChild(style);
+ this.stylesInjected = true;
+ }
+ startProcessingVisual() {
+ const container = this.premiumContainer;
+ if (container) {
+ container.classList.add("engrid-premium-processing");
+ container.classList.remove("engrid-premium-ready");
+ }
+ }
+ endProcessingVisual(hasVisible) {
+ const container = this.premiumContainer;
+ if (!container) return;
+ container.classList.remove("engrid-premium-processing");
+ if (hasVisible) {
+ container.classList.remove("engrid-premium-hidden");
+ container.classList.add("engrid-premium-ready");
+ } else {
+ container.classList.add("engrid-premium-hidden");
+ container.classList.remove("engrid-premium-ready");
+ }
+ }
+ scheduleRun() {
+ // Immediately fade out while we wait for EN to re-render
+ this.startProcessingVisual();
+ if (this.debounceTimer) window.clearTimeout(this.debounceTimer);
+ this.debounceTimer = window.setTimeout(() => this.run(), 500);
+ }
+ getCurrentFreq() {
+ return (this._frequency.frequency || "onetime").toLowerCase();
+ }
+ getCurrentAmount() {
+ return this._amount.amount || 0;
+ }
+ getAllowedProductIds(freq, amount) {
+ const cfg = this.config;
+ const allowed = new Set();
+ if (!cfg) return allowed;
+ const products = this.getProductsMap(freq);
+ Object.keys(products).forEach(pid => {
+ const min = Number(products[pid]);
+ if (!isNaN(min) && amount >= min) allowed.add(String(pid));
+ });
+ return allowed;
+ }
+ getProductId(item) {
+ const input = item.querySelector('input[name="en__pg"]');
+ return input ? input.value : null;
+ }
+ showItem(item, show) {
+ item.style.display = show ? "" : "none";
+ }
+ selectByProductId(productId) {
+ const radio = document.querySelector('input[name="en__pg"][value="' + productId + '"]');
+ if (radio) {
+ radio.checked = true;
+ radio.dispatchEvent(new Event("change", {
+ bubbles: true,
+ cancelable: true
+ }));
+ // Update EN's selected class if necessary
+ const prev = document.querySelector(".en__pg--selected");
+ const pg = radio.closest(".en__pg");
+ if (prev && prev !== pg) prev.classList.remove("en__pg--selected");
+ if (pg) pg.classList.add("en__pg--selected");
+ }
+ }
+ clearVariantField() {
+ dist_engrid_ENGrid.setFieldValue("transaction.selprodvariantid", "");
+ }
+ hasVisiblePremiumItems() {
+ // Exclude the "No Premium" (value 0) from count
+ return this.giftItems.some(item => {
+ const pid = this.getProductId(item);
+ const visible = dist_engrid_ENGrid.isVisible(item);
+ return visible && pid !== "0";
});
}
+ run() {
+ const container = this.premiumContainer;
+ if (!container) return this.logger.log("No premium container found.");
+ const frequency = this.getCurrentFreq();
+ const amount = this.getCurrentAmount();
+ const allowedProductIds = this.getAllowedProductIds(frequency, amount);
+ // Iterate items and toggle visibility
+ let anyVisible = false;
+ const items = this.giftItems;
+ const noPremiumItems = [];
+ items.forEach(item => {
+ const productId = this.getProductId(item);
+ if (!productId) return;
+ if (productId === "0") {
+ // track no-premium items but don't decide visibility here β it's always available
+ noPremiumItems.push(item);
+ this.showItem(item, true);
+ return;
+ }
+ const visible = allowedProductIds.has(productId);
+ this.showItem(item, visible);
+ if (visible) anyVisible = true;
+ });
+ // If nothing visible (besides no-premium), hide whole container
+ const hasVisibleGifts = anyVisible;
+ this.endProcessingVisual(hasVisibleGifts);
+ // Selection handling
+ const current = document.querySelector('input[name="en__pg"]:checked');
+ const currentProductId = (current === null || current === void 0 ? void 0 : current.value) || null;
+ const defaultProductId = this.getConfiguredDefaultPid(frequency); // may be "0"
+ // If current selection is invalid after filtering, apply default logic
+ const currentIsValid = currentProductId === "0" || (currentProductId ? allowedProductIds.has(currentProductId) : false);
+ if (!currentIsValid) {
+ if (defaultProductId && defaultProductId !== "0" && allowedProductIds.has(defaultProductId)) {
+ this.selectByProductId(defaultProductId);
+ } else {
+ this.selectByProductId("0");
+ this.clearVariantField();
+ }
+ } else {
+ // Current selection is valid; only force No Premium if frequency changed and default is 0/missing
+ if (this.pendingFrequencyChange && (!defaultProductId || defaultProductId === "0")) {
+ if (currentProductId !== "0") {
+ this.selectByProductId("0");
+ this.clearVariantField();
+ }
+ }
+ }
+ // If container hidden (no visible gifts), select No Premium and clear hidden
+ if (!hasVisibleGifts) {
+ this.selectByProductId("0");
+ this.clearVariantField();
+ }
+ this.logger.log(`Processed gifts for freq=${frequency}, amount=${amount}. Visible gifts: ${hasVisibleGifts ? "yes" : "no"}`);
+ // Reset frequency-change flag after processing
+ this.pendingFrequencyChange = false;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/digital-wallets.js
- // Add a tooltip for the CVV number
- addTooltip(document.querySelector(".en__field--ccvv > label"), "cvv", text.cvvTooltipLabel, text.cvvTooltip);
-
- // Add a tooltip for the bank routing number
- addTooltip(document.querySelector(".en__field--bankRoutingNumber > label"), "bankNumber", text.bankNumberTooltipLabel, text.bankNumberTooltip);
- // Add a tooltip for Title
- addTooltip(document.querySelector(".en__field--title > label"), "title", "Why do you ask for this?", "Many of our online actions link up with public officials' web mail forms in order to deliver your message on your behalf. Many of these public officials' forms require the Mr./Mrs./Miss field and, unfortunately, we do not have control over which of these titles are presented as options. We must adhere to what the officials are using in order for your message to be delivered.");
- /**
- * Set the visibility of the premium field based on the donation frequency and amount
- * Visibility is set by adding/removing the "engrid-premium-donation" data attr on the body
- * @param {string} frequency
- * @param {number} amount
- */
- function setPremiumVisibility(frequency, amount) {
- const monthlyPremiumMinimum = window?.donationSettings?.monthlyPremiumMinimum;
- const onetimePremiumMinimum = window?.donationSettings?.onetimePremiumMinimum;
- if (!monthlyPremiumMinimum || !onetimePremiumMinimum) {
+class digital_wallets_DigitalWallets {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("DigitalWallets", "#fff", "#333", "π");
+ this._form = events_en_form_EnForm.getInstance();
+ //digital wallets not enabled.
+ if (!document.getElementById("en__digitalWallet")) {
+ dist_engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-google-pay", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-venmo", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-daf", "false");
+ this.logger.log("No digital wallet container found, skipping digital wallet setup.");
return;
}
- const monthlyPremiumField = App.getField("supporter.questions.1362488");
- const premiumVisibleField = App.getField("supporter.questions.1366068");
- if (!monthlyPremiumField || !premiumVisibleField) {
- return;
+ // Add giveBySelect classes to the separate wallet containers
+ // and hide them on load.
+ const stripeButtons = document.getElementById("en__digitalWallet__stripeButtons__container");
+ if (stripeButtons) {
+ stripeButtons.classList.add("giveBySelect-stripedigitalwallet");
+ stripeButtons.classList.add("showif-stripedigitalwallet-selected");
+ // stripeButtons.style.display = "none";
+ }
+ const paypalTouchButtons = document.getElementById("en__digitalWallet__paypalTouch__container");
+ if (paypalTouchButtons) {
+ paypalTouchButtons.classList.add("giveBySelect-paypaltouch");
+ paypalTouchButtons.classList.add("showif-paypaltouch-selected");
+ // paypalTouchButtons.style.display = "none";
+ }
+ const donorAdvisedFundButtonContainer = document.getElementById("en__digitalWallet__chariot__container");
+ if (donorAdvisedFundButtonContainer) {
+ donorAdvisedFundButtonContainer.classList.add("giveBySelect-daf");
+ donorAdvisedFundButtonContainer.classList.add("showif-daf-selected");
}
- if (frequency === "monthly" && amount >= monthlyPremiumMinimum) {
- App.setBodyData("premium-donation", "active");
- monthlyPremiumField.checked = true;
- premiumVisibleField.checked = true;
- App.enParseDependencies();
- } else if ((frequency === "onetime" || frequency === "annual") && amount >= onetimePremiumMinimum) {
- App.setBodyData("premium-donation", "active");
- monthlyPremiumField.checked = false;
- premiumVisibleField.checked = true;
- App.enParseDependencies();
+ /**
+ * Check for presence of elements that indicated Stripe digital wallets
+ * (Google Pay, Apple Pay) have loaded, and add functionality for them.
+ * If they haven't yet loaded, set up a Mutation Observer to check for
+ * when they do.
+ */
+ if (document.querySelector("#en__digitalWallet__stripeButtons__container > *")) {
+ this.addStripeDigitalWallets();
} else {
- App.setBodyData("premium-donation", "inactive");
- monthlyPremiumField.checked = false;
- premiumVisibleField.checked = false;
- App.enParseDependencies();
+ dist_engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-google-pay", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
+ const stripeContainer = document.getElementById("en__digitalWallet__stripeButtons__container");
+ if (stripeContainer) {
+ this.checkForWalletsBeingAdded(stripeContainer, "stripe");
+ }
+ // If the default payment type is Stripe Digital Wallet and the page doesnt support it, set the payment type to Card
+ const paymentType = dist_engrid_ENGrid.getPaymentType();
+ if (paymentType.toLowerCase() === "stripedigitalwallet") {
+ dist_engrid_ENGrid.setPaymentType("card");
+ }
+ }
+ /**
+ * Check for presence of elements that indicated Paypal digital wallets
+ * (Paypal One Touch, Venmo, Etc) have loaded, and add functionality for them.
+ * If they haven't yet loaded, set up a Mutation Observer to check for
+ * when they do.
+ */
+ if (document.querySelector("#en__digitalWallet__paypalTouch__container > *")) {
+ this.addPaypalTouchDigitalWallets();
+ } else {
+ dist_engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-venmo", "false");
+ const paypalContainer = document.getElementById("en__digitalWallet__paypalTouch__container");
+ if (paypalContainer) {
+ this.checkForWalletsBeingAdded(paypalContainer, "paypalTouch");
+ }
+ }
+ /**
+ * Check for presence of elements that indicate DAF is present, and add functionality for it.
+ * If it hasn't loaded yet, set up a Mutation Observer to check for when it does.
+ */
+ if (document.querySelector("#en__digitalWallet__chariot__container > *")) {
+ this.addDAF();
+ } else {
+ dist_engrid_ENGrid.setBodyData("payment-type-option-daf", "false");
+ const donorAdvisedFundButtonContainer = document.getElementById("en__digitalWallet__chariot__container");
+ if (donorAdvisedFundButtonContainer) {
+ this.checkForWalletsBeingAdded(donorAdvisedFundButtonContainer, "daf");
+ }
}
}
- function keepScrollPosition(elementBlock, direction = "up") {
- if (!elementBlock) return;
- const scrollY = window.scrollY;
- const elementStyle = window.getComputedStyle(elementBlock);
- const elementSize = parseInt(elementStyle.height, 10) + parseInt(elementStyle.marginTop.replace("px", "")) + parseInt(elementStyle.marginBottom.replace("px", ""));
- window.setTimeout(() => {
- window.scrollTo(0, direction === "up" ? scrollY - elementSize : scrollY + elementSize);
- }, 100);
- console.log(elementSize);
+ addStripeDigitalWallets() {
+ this.logger.log("Stripe Digital Wallets detected");
+ this.addOptionToPaymentTypeField("stripedigitalwallet", "GooglePay / ApplePay");
+ // ENGrid.setBodyData(
+ // "payment-type-option-apple-pay",
+ // DigitalWallets.isApplePayAvailable.toString()
+ // );
+ // ENGrid.setBodyData(
+ // "payment-type-option-google-pay",
+ // !DigitalWallets.isApplePayAvailable.toString()
+ // );
+ // TODO: Change to trustworthy detection of Google Pay & Apple Pay availability
+ dist_engrid_ENGrid.setBodyData("payment-type-option-apple-pay", "true");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-google-pay", "true");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "true");
+ this.addStripeDigitalWalletListener() ? this.logger.log("Stripe Digital Wallet listener added successfully") : this.logger.log("Failed to add Stripe Digital Wallet listener");
+ }
+ addPaypalTouchDigitalWallets() {
+ this.logger.log("Paypal Touch Digital Wallets detected");
+ this.addOptionToPaymentTypeField("paypaltouch", "Paypal / Venmo");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-paypal-one-touch", "true");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-venmo", "true");
+ this.addPaypalOneTouchListener() ? this.logger.log("Paypal Touch listener added successfully") : this.logger.log("Failed to add Paypal Touch listener");
+ }
+ addDAF() {
+ this.logger.log("DAF Digital Wallet detected");
+ this.addOptionToPaymentTypeField("daf", "Donor Advised Fund");
+ dist_engrid_ENGrid.setBodyData("payment-type-option-daf", "true");
+ this.addDAFListener() ? this.logger.log("DAF listener added successfully") : this.logger.log("Failed to add DAF listener");
+ }
+ addOptionToPaymentTypeField(value, label) {
+ const paymentTypeField = document.querySelector('[name="transaction.paymenttype"]');
+ if (paymentTypeField && !paymentTypeField.querySelector(`[value=${value}]`)) {
+ const walletOption = document.createElement("option");
+ walletOption.value = value;
+ walletOption.innerText = label;
+ paymentTypeField.appendChild(walletOption);
+ }
+ // If this payment type is set as the default on GiveBySelect, set the payment type to this value
+ // We need to do this here because the digital wallets are sometimes slow to load
+ const giveBySelect = document.querySelector('input[name="transaction.giveBySelect"][value="' + value + '"]');
+ if (giveBySelect && giveBySelect.dataset.default === "true") {
+ giveBySelect.checked = true;
+ const event = new Event("change", {
+ bubbles: true,
+ cancelable: true
+ });
+ giveBySelect.dispatchEvent(event);
+ }
}
-
- // If the frequency is annual, move the premium container content below the #en__field_auto_renew container
- // If frequency is not annual, move the premium container content back to premium container
- function movePremiumContainerContent(direction = "up") {
- const premiumContainerContent = document.querySelector(".premium-container-content");
- if (!premiumContainerContent) return;
- const autoRenewField = document.getElementById("en__field_auto_renew");
- const autoRenewContainer = autoRenewField?.closest(".en__component");
- if (direction === "down") {
- if (autoRenewContainer) {
- autoRenewContainer.insertAdjacentElement("afterend", premiumContainerContent);
- const multistepStep = autoRenewContainer.getAttribute("data-multistep-step");
- if (multistepStep) {
- premiumContainerContent.setAttribute("data-multistep-step", multistepStep);
+ checkForWalletsBeingAdded(node, walletType) {
+ const callback = (mutationList, observer) => {
+ for (const mutation of mutationList) {
+ //Once a child node has been added, set up the appropriate digital wallet
+ if (mutation.type === "childList" && mutation.addedNodes.length) {
+ if (walletType === "stripe") {
+ this.addStripeDigitalWallets();
+ } else if (walletType === "paypalTouch") {
+ this.addPaypalTouchDigitalWallets();
+ } else if (walletType === "daf") {
+ this.addDAF();
+ }
+ //Disconnect observer and break loop to prevent multiple additions
+ observer.disconnect();
+ break;
}
}
- } else {
- const premiumContainer = document.querySelector(".premium-container");
- // If the premium container is not found, or the premium container already contains the premium container content, return
- if (!premiumContainer || premiumContainer.querySelector(".en__component--premiumgiftblock")) return;
- premiumContainer.appendChild(premiumContainerContent);
- premiumContainerContent.removeAttribute("data-multistep-step");
+ };
+ const observer = new MutationObserver(callback);
+ observer.observe(node, {
+ childList: true,
+ subtree: true
+ });
+ }
+ addPaypalOneTouchListener() {
+ var _a, _b, _c, _d, _e;
+ const paypalTouch = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enPaypalTouch) === null || _d === void 0 ? void 0 : _d.paypalTouch;
+ if (!((_e = paypalTouch === null || paypalTouch === void 0 ? void 0 : paypalTouch.library) === null || _e === void 0 ? void 0 : _e.Buttons)) {
+ this.logger.log("Paypal Touch library not found, cannot add listener");
+ return false;
}
+ const buttons = paypalTouch.library.Buttons.bind(paypalTouch.library);
+ paypalTouch.library.Buttons = o => buttons(Object.assign(Object.assign({}, o), {
+ onClick: (d, a) => (this._form.dispatchIntentSubmit(), o.onClick && o.onClick(d, a))
+ }));
+ paypalTouch.unloadButton && paypalTouch.unloadButton();
+ paypalTouch.loadButton && paypalTouch.loadButton();
+ return true;
}
+ addStripeDigitalWalletListener() {
+ var _a, _b, _c, _d, _e, _f;
+ return !!((_f = (_e = (_d = (_c = (_b = (_a = window.EngagingNetworks) === null || _a === void 0 ? void 0 : _a.require) === null || _b === void 0 ? void 0 : _b._defined) === null || _c === void 0 ? void 0 : _c.enStripeButtons) === null || _d === void 0 ? void 0 : _d.stripeButtons) === null || _e === void 0 ? void 0 : _e.paymentRequest) === null || _f === void 0 ? void 0 : _f.on("paymentmethod", this._form.dispatchIntentSubmit.bind(this._form)));
+ }
+ addDAFListener() {
+ const chariotButton = document.getElementById("chariot-button");
+ chariotButton === null || chariotButton === void 0 ? void 0 : chariotButton.addEventListener("click", this._form.dispatchIntentSubmit.bind(this._form));
+ return !!chariotButton;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/mobile-cta.js
+// This component adds a floating CTA button to the page, which can be used to scroll to the top of the form
- // Listen for changes to the donation frequency and amount
- freq.onFrequencyChange.subscribe(frequency => {
- setPremiumVisibility(frequency, amt.amount);
- if (frequency !== "annual") {
- window.setTimeout(() => {
- movePremiumContainerContent("up");
- }, 100);
+class mobile_cta_MobileCTA {
+ constructor() {
+ var _a;
+ // Initialize options with the MobileCTA value or false
+ this.options = (_a = dist_engrid_ENGrid.getOption("MobileCTA")) !== null && _a !== void 0 ? _a : false;
+ this.buttonLabel = "";
+ // Return early if the options object is falsy or the current page type is not in the options.pages array
+ if (!this.options || dist_engrid_ENGrid.getPageNumber() !== 1) {
+ return;
}
- });
- amt.onAmountChange.subscribe(amount => {
- setPremiumVisibility(freq.frequency, amount);
- });
+ const labelForPageType = this.options.find(option => option.pageType === dist_engrid_ENGrid.getPageType());
+ if (!labelForPageType) return;
+ // Set the button label to the window.mobileCTAButtonLabel value or the label for the current page type
+ this.buttonLabel = window.mobileCTAButtonLabel || labelForPageType.label;
+ this.renderButton();
+ this.addEventListeners();
+ }
+ renderButton() {
+ const engridDiv = document.querySelector("#engrid");
+ const formBlock = document.querySelector(".body-main .en__component--widgetblock:first-child, .en__component--formblock");
+ // Return early if engridDiv or formBlock are not found
+ if (!engridDiv || !formBlock) return;
+ const buttonContainer = document.createElement("div");
+ const button = document.createElement("button");
+ // Add necessary classes and set the initial display style for the button container
+ buttonContainer.classList.add("engrid-mobile-cta-container", "hide-cta");
+ button.classList.add("primary");
+ // Set the button's innerHTML and add a click event listener
+ button.innerHTML = this.buttonLabel + ' ';
+ button.addEventListener("click", () => {
+ formBlock.scrollIntoView({
+ behavior: "smooth"
+ });
+ });
+ // Append the button to the button container and the container to engridDiv
+ buttonContainer.appendChild(button);
+ engridDiv.appendChild(buttonContainer);
+ }
+ addEventListeners() {
+ const bodyMain = document.querySelector(".body-main");
+ // Return early if formBlock is not found
+ if (!bodyMain) return;
+ // Define a function to toggle the button visibility based on the bodyMain position
+ const toggleButton = () => {
+ if (bodyMain.getBoundingClientRect().top <= window.innerHeight - 100) {
+ this.hideButton();
+ } else {
+ this.showButton();
+ }
+ };
+ toggleButton();
+ // Add event listeners for load, resize, and scroll events to toggle the button visibility
+ window.addEventListener("load", toggleButton);
+ window.addEventListener("resize", toggleButton);
+ window.addEventListener("scroll", toggleButton);
+ }
+ // Hide the button by setting the container's display style to "none"
+ hideButton() {
+ const buttonContainer = document.querySelector(".engrid-mobile-cta-container");
+ if (buttonContainer) buttonContainer.classList.add("hide-cta");
+ }
+ // Show the button by setting the container's display style to "block"
+ showButton() {
+ const buttonContainer = document.querySelector(".engrid-mobile-cta-container");
+ if (buttonContainer) buttonContainer.classList.remove("hide-cta");
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/live-frequency.js
+// This script creates merge tags: [[frequency]], [[Frequency]], or [[FREQUENCY]]
+// that gets replaced with the donation frequency
+// and can be used on any Code Block, Text Block, or Form Block
- // Move Premium donation elements into their container
- let premiumDonationEls = document.querySelectorAll(".move-into--engrid-premium-container");
- let premiumDonationContainer = document.querySelector(".engrid-premium-container");
- if (premiumDonationEls.length > 0 && premiumDonationContainer) {
- premiumDonationEls.forEach(el => {
- premiumDonationContainer.appendChild(el);
+class live_frequency_LiveFrequency {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("LiveFrequency", "#00ff00", "#000000", "π§Ύ");
+ this.elementsFound = false;
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this.searchElements();
+ if (!this.shouldRun()) return;
+ this.updateFrequency();
+ this.addEventListeners();
+ }
+ searchElements() {
+ const enElements = document.querySelectorAll(`
+ .en__component--copyblock,
+ .en__component--codeblock,
+ .en__field label,
+ .en__submit
+ `);
+ if (enElements.length > 0) {
+ const pattern = /\[\[(frequency)\]\]/gi;
+ let totalFound = 0;
+ enElements.forEach(item => {
+ const match = item.innerHTML.match(pattern);
+ if (item instanceof HTMLElement && match) {
+ this.elementsFound = true;
+ match.forEach(matchedSubstring => {
+ totalFound++;
+ this.replaceMergeTags(matchedSubstring, item);
+ });
+ }
+ });
+ if (totalFound > 0) {
+ this.logger.log(`Found ${totalFound} merge tag${totalFound > 1 ? "s" : ""} in the page.`);
+ }
+ }
+ }
+ shouldRun() {
+ if (!this.elementsFound) {
+ this.logger.log("No merge tags found. Skipping.");
+ return false;
+ }
+ return true;
+ }
+ addEventListeners() {
+ this._amount.onAmountChange.subscribe(() => {
+ setTimeout(() => {
+ this.updateFrequency();
+ }, 10);
+ });
+ this._frequency.onFrequencyChange.subscribe(() => {
+ setTimeout(() => {
+ this.searchElements();
+ this.updateFrequency();
+ }, 10);
+ });
+ }
+ updateFrequency() {
+ const frequency = this._frequency.frequency === "onetime" ? "one-time" : this._frequency.frequency;
+ const elemenst = document.querySelectorAll(".engrid-frequency");
+ elemenst.forEach(item => {
+ if (item.classList.contains("engrid-frequency--lowercase")) {
+ item.innerHTML = frequency.toLowerCase();
+ } else if (item.classList.contains("engrid-frequency--capitalized")) {
+ item.innerHTML = frequency.charAt(0).toUpperCase() + frequency.slice(1);
+ } else if (item.classList.contains("engrid-frequency--uppercase")) {
+ item.innerHTML = frequency.toUpperCase();
+ } else {
+ item.innerHTML = frequency;
+ }
});
}
+ replaceMergeTags(tag, element) {
+ const frequency = this._frequency.frequency === "onetime" ? "one-time" : this._frequency.frequency;
+ const frequencyElement = document.createElement("span");
+ frequencyElement.classList.add("engrid-frequency");
+ frequencyElement.innerHTML = frequency;
+ switch (tag) {
+ case "[[frequency]]":
+ frequencyElement.classList.add("engrid-frequency--lowercase");
+ frequencyElement.innerHTML = frequencyElement.innerHTML.toLowerCase();
+ element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
+ break;
+ case "[[Frequency]]":
+ frequencyElement.classList.add("engrid-frequency--capitalized");
+ frequencyElement.innerHTML = frequencyElement.innerHTML.charAt(0).toUpperCase() + frequencyElement.innerHTML.slice(1);
+ element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
+ break;
+ case "[[FREQUENCY]]":
+ frequencyElement.classList.add("engrid-frequency--uppercase");
+ frequencyElement.innerHTML = frequencyElement.innerHTML.toUpperCase();
+ element.innerHTML = element.innerHTML.replace(tag, frequencyElement.outerHTML);
+ break;
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/universal-opt-in.js
+/**
+ * This class will add event listeners to every yes/no radio button or checkbox
+ * inside a universal opt-in element (any form block with the CSS class universal-opt-in). When the user clicks on a radio/checkbox
+ * button, we will search for every other radio/checkbox button inside the same
+ * universal opt-in element and mirror the user's selection.
+ * If instead of universal-opt-in you use universal-opt-in_null, the class will
+ * not mirror the user's selection when a radio "No" option is selected. Instead,
+ * it will unset all other radio buttons.
+ */
- // Make body-banner and images with attribution attribution clickable
- const bbTippy = document.querySelectorAll(".body-banner figattribution, img.img-with-attribution[alt] + figattribution");
- if (bbTippy) {
- bbTippy.forEach(el => {
- const tippyInstance = el?._tippy;
- if (tippyInstance) {
- tippyInstance.setProps({
- arrow: false,
- trigger: "click"
+class universal_opt_in_UniversalOptIn {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("UniversalOptIn", "#f0f0f0", "#d2691e", "πͺ");
+ this._elements = document.querySelectorAll(".universal-opt-in, .universal-opt-in_null");
+ if (!this.shouldRun()) return;
+ this.addEventListeners();
+ }
+ shouldRun() {
+ if (this._elements.length === 0) {
+ this.logger.log("No universal opt-in elements found. Skipping.");
+ return false;
+ }
+ this.logger.log(`Found ${this._elements.length} universal opt-in elements.`);
+ return true;
+ }
+ addEventListeners() {
+ this._elements.forEach(element => {
+ const yesNoElements = element.querySelectorAll(".en__field__input--radio, .en__field__input--checkbox");
+ if (yesNoElements.length > 0) {
+ yesNoElements.forEach(yesNoElement => {
+ yesNoElement.addEventListener("click", () => {
+ if (yesNoElement instanceof HTMLInputElement && yesNoElement.getAttribute("type") === "checkbox") {
+ const yesNoValue = yesNoElement.checked;
+ if (yesNoValue) {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is checked");
+ yesNoElements.forEach(yesNoElement2 => {
+ if (yesNoElement === yesNoElement2) return;
+ if (yesNoElement2 instanceof HTMLInputElement && yesNoElement2.getAttribute("type") === "checkbox") yesNoElement2.checked = true;
+ });
+ } else {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is unchecked");
+ yesNoElements.forEach(yesNoElement2 => {
+ if (yesNoElement === yesNoElement2) return;
+ if (yesNoElement2 instanceof HTMLInputElement && yesNoElement2.getAttribute("type") === "checkbox") yesNoElement2.checked = false;
+ });
+ }
+ return;
+ }
+ const yesNoValue = yesNoElement.getAttribute("value");
+ if (yesNoValue === "Y") {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is checked");
+ yesNoElements.forEach(yesNoElement2 => {
+ const fieldName = yesNoElement2.getAttribute("name");
+ const clickedFieldName = yesNoElement.getAttribute("name");
+ if (!fieldName || fieldName === clickedFieldName) return;
+ dist_engrid_ENGrid.setFieldValue(fieldName, "Y");
+ });
+ } else {
+ this.logger.log("Yes/No " + yesNoElement.getAttribute("type") + " is unchecked");
+ yesNoElements.forEach(yesNoElement2 => {
+ const fieldName = yesNoElement2.getAttribute("name");
+ const clickedFieldName = yesNoElement.getAttribute("name");
+ if (!fieldName || fieldName === clickedFieldName) return;
+ if (element.classList.contains("universal-opt-in")) {
+ dist_engrid_ENGrid.setFieldValue(fieldName, "N");
+ } else {
+ yesNoElement2.checked = false;
+ }
+ });
+ }
+ });
});
}
});
}
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/stripe-financial-connections.js
+/**
+ * This component improves EN's implementation of Stripe Financial Connections.
+ * Enhancements:
+ * - When the modal is closed, it re-enables the submit button.
+ */
- // Add data-thank-you attribute to body of final page
- if (pageJson && pageJson.pageNumber === pageJson.pageCount && pageJson.pageCount > 1) {
- App.setBodyData("thank-you", "true");
- } else {
- App.setBodyData("thank-you", "false");
+class stripe_financial_connections_StripeFinancialConnections {
+ constructor() {
+ this.stripeModalOpen = false;
+ this.logger = new dist_logger_EngridLogger("Stripe Financial Connections", "black", "pink", "ποΈ");
+ const observer = new MutationObserver(mutations => {
+ mutations.forEach(mutation => {
+ mutation.addedNodes.forEach(node => {
+ if (!this.stripeModalOpen && this.isStripeModalNodeWIthIframe(node)) {
+ this.logger.log("Stripe Financial Connections modal opened.");
+ this.onStripeModalOpen();
+ }
+ });
+ mutation.removedNodes.forEach(node => {
+ if (this.stripeModalOpen && this.isStripeModalNode(node)) {
+ this.logger.log("Stripe Financial Connections modal closed.");
+ this.onStripeModalClose();
+ }
+ });
+ });
+ });
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true
+ });
}
+ isStripeModalNode(node) {
+ return node instanceof HTMLElement && node.hasAttribute("data-react-aria-top-layer");
+ }
+ isStripeModalNodeWIthIframe(node) {
+ return !!(this.isStripeModalNode(node) && node instanceof HTMLElement && node.querySelector('iframe[src*="js.stripe.com"]'));
+ }
+ onStripeModalOpen() {
+ this.stripeModalOpen = true;
+ }
+ onStripeModalClose() {
+ this.stripeModalOpen = false;
+ dist_engrid_ENGrid.enableSubmit();
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/give-by-select.js
- // Auto renew
- const autoRenew = document.getElementById("en__field_auto_renew");
- if (autoRenew) {
- const annualFrequencyOption = document.querySelector('input[name="transaction.recurrfreq"][value="ANNUAL"]');
- const extRef2Input = document.querySelector('[name="en_txn2"]');
- if (!annualFrequencyOption || !extRef2Input) {
- // if recurring frequency option for annual is not found, we remove the auto renew checkbox and stop here
- console.error("ENgrid: Annual frequency option or external reference field not found. Removing Auto Renew checkbox to prevent failed donations.");
- autoRenew.closest(".en__field--auto-renew").remove();
- } else {
- annualFrequencyOption.parentElement.classList.add("hide");
- App.setBodyData("auto-renew-on-page", "true");
- App.setBodyData("auto-renew-active", autoRenew.checked.toString());
- extRef2Input.value = autoRenew.checked ? "auto_renew" : "";
- autoRenew.addEventListener("change", () => {
- const autoRenewActive = autoRenew.checked;
- if (autoRenewActive) {
- movePremiumContainerContent("down");
- }
+class give_by_select_GiveBySelect {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("GiveBySelect", "#FFF", "#333", "π");
+ this.transactionGiveBySelect = document.getElementsByName("transaction.giveBySelect");
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ if (!this.transactionGiveBySelect) return;
+ this._frequency.onFrequencyChange.subscribe(() => this.checkPaymentTypeVisibility());
+ this.transactionGiveBySelect.forEach(giveBySelect => {
+ giveBySelect.addEventListener("change", () => {
+ this.logger.log("Changed to " + giveBySelect.value);
+ dist_engrid_ENGrid.setPaymentType(giveBySelect.value);
});
- freq.onFrequencyChange.subscribe(frequency => {
- if (frequency === "annual") {
- App.setBodyData("auto-renew-active", "true");
- extRef2Input.value = "auto_renew";
- } else {
- App.setBodyData("auto-renew-active", "false");
- extRef2Input.value = "";
+ });
+ // Set the initial value of giveBySelect to the transaction.paymenttype field
+ const paymentType = dist_engrid_ENGrid.getPaymentType();
+ if (paymentType) {
+ this.logger.log("Setting giveBySelect to " + paymentType);
+ const isCard = ["card", "visa", "mastercard", "amex", "discover", "diners", "jcb", "vi", "mc", "ax", "dc", "di", "jc"].includes(paymentType.toLowerCase());
+ this.transactionGiveBySelect.forEach(giveBySelect => {
+ if (isCard && giveBySelect.value.toLowerCase() === "card") {
+ giveBySelect.checked = true;
+ } else if (giveBySelect.value.toLowerCase() === paymentType.toLowerCase()) {
+ giveBySelect.checked = true;
}
});
}
}
-
- ////////////////////////////////////////////
- // Spanish translation tweaks
-
- // Translate recurring status
- const recurringStatus = document.querySelector(".js-recurring-status");
- if (recurringStatus) {
- if (window.navigator.language === "es-MX" || window.location.href.indexOf("locale=es-MX") > -1 || pageJson.locale === "es-MX") {
- console.log(recurringStatus.textContent);
- switch (recurringStatus.textContent) {
- case "MONTHLY":
- recurringStatus.textContent = "Mensual";
- break;
- case "ANNUAL":
- recurringStatus.textContent = "Anual";
- break;
- default:
- recurringStatus.textContent = "Una vez";
- }
- } else {
- switch (recurringStatus.textContent) {
- case "MONTHLY":
- recurringStatus.textContent = "Monthly";
- break;
- case "ANNUAL":
- recurringStatus.textContent = "Annual";
- break;
- default:
- recurringStatus.textContent = "One-time";
+ // Returns true if the selected payment type is visible
+ // Returns false if the selected payment type is not visible
+ isSelectedPaymentVisible() {
+ let visible = true;
+ this.transactionGiveBySelect.forEach(giveBySelect => {
+ const container = giveBySelect.parentElement;
+ if (giveBySelect.checked && !dist_engrid_ENGrid.isVisible(container)) {
+ this.logger.log(`Selected Payment Type is not visible: ${giveBySelect.value}`);
+ visible = false;
}
- }
+ });
+ return visible;
}
- if (window?.pageJson?.locale === "es-MX") {
- const donationAmountField = document.querySelector(".en__field--donationAmt");
- if (donationAmountField) {
- donationAmountField.style.setProperty("--give-monthly-donation-amount-appended-label", '"/MES"');
- }
+ // Checks if the selected payment type is visible
+ // If the selected payment type is not visible, it sets the payment type to the first visible option
+ checkPaymentTypeVisibility() {
+ window.setTimeout(() => {
+ var _a;
+ if (!this.isSelectedPaymentVisible()) {
+ this.logger.log("Setting payment type to first visible option");
+ const firstVisible = Array.from(this.transactionGiveBySelect).find(giveBySelect => {
+ const container = giveBySelect.parentElement;
+ return dist_engrid_ENGrid.isVisible(container);
+ });
+ if (firstVisible) {
+ this.logger.log("Setting payment type to ", firstVisible.value);
+ const container = firstVisible.parentElement;
+ (_a = container.querySelector("label")) === null || _a === void 0 ? void 0 : _a.click();
+ dist_engrid_ENGrid.setPaymentType(firstVisible.value);
+ }
+ } else {
+ this.logger.log("Selected Payment Type is visible");
+ }
+ }, 300);
}
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/url-params-to-body-attrs.js
+//This component adds any url parameters that begin with "data-engrid-" to the body as attributes.
- // END Spanish translation tweaks
+class url_params_to_body_attrs_UrlParamsToBodyAttrs {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("UrlParamsToBodyAttrs", "white", "magenta", "π");
+ this.urlParams = new URLSearchParams(document.location.search);
+ this.urlParams.forEach((value, key) => {
+ if (key.startsWith("data-engrid-")) {
+ dist_engrid_ENGrid.setBodyData(key.split("data-engrid-")[1], value);
+ this.logger.log(`Set "${key}" on body to "${value}" from URL params`);
+ }
+ });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/exit-intent-lightbox.js
- ////////////////////////////////////////////
- // END ENGRID TRANSITION SCRIPTS
- ////////////////////////////////////////////
- /*
- * Conditional content via URL parameters
- * js-zcc--param--value
- * ?crid=1234
- * Will reveal all elements with class js-zcc--crid--1234
- */
- const urlParams = new URLSearchParams(window.location.search);
- urlParams.forEach((value, param) => {
- value = value.replace(/[^_a-zA-Z0-9-]/g, "_").toLowerCase();
- param = param.replace(/[^_a-zA-Z0-9-]/g, "_").toLowerCase();
- const conditionalElements = document.querySelectorAll(`.js-zcc--${param}--${value}`);
- if (conditionalElements.length > 0) {
- conditionalElements.forEach(el => {
- el.classList.remove(`js-zcc--${param}--${value}`);
- });
- } else {
- // If there no elements with the specified value, reveal all default elements for that parameter.
- const defaultElements = document.querySelectorAll(`[class="js-zcc--${param}--default"]`);
- defaultElements.forEach(el => {
- el.classList.remove(`js-zcc--${param}--default`);
- });
+class exit_intent_lightbox_ExitIntentLightbox {
+ constructor() {
+ this.opened = false;
+ this.dataLayer = window.dataLayer || [];
+ this.logger = new dist_logger_EngridLogger("ExitIntentLightbox", "yellow", "black", "πͺ");
+ this.triggerDelay = 1000; // Don't run the exit intent lightbox until at least 1 second has passed after page load
+ this.triggerTimeout = null;
+ let options = "EngridExitIntent" in window ? window.EngridExitIntent : {};
+ this.options = Object.assign(Object.assign({}, exit_intent_options_ExitIntentOptionsDefaults), options);
+ if (!this.options.enabled) {
+ this.logger.log("Not enabled");
+ return;
}
- });
- // If there is no URL parameter, reveal all elements with class js-zcc--paramName--default class
- const conditionalElements = document.querySelectorAll(`[class*="js-zcc--"]`);
- conditionalElements.forEach(el => {
- const className = [...el.classList].find(className => className.startsWith("js-zcc--") && className.endsWith("--default"));
- if (!className) return;
- const paramName = className.split("--")[1];
- if (!urlParams.has(paramName)) {
- el.classList.remove(className);
+ if (cookie_get(this.options.cookieName)) {
+ this.logger.log("Not showing - cookie found.");
+ return;
}
- });
- // If there are any extra banner image elements being controlled by the URL parameters,
- // we will remove them from the page (extra banner images inside body-banner will prevent the image showing)
- const extraBannerImages = document.querySelectorAll(".body-banner img[class*='js-zcc--']");
- extraBannerImages.forEach(img => {
- img?.closest(".en__component--imageblock")?.remove();
- });
-
- /*
- * Lock gift designation field when a specific value is passed in the URL
- * and we are using the gift designation form block
- */
- const giftDesignationField = document.querySelector(".engrid-gift-designation #en__field_supporter_appealCode");
- const appealCode = urlParams.get("supporter.appealCode");
- if (giftDesignationField && appealCode) {
- const giftDesignationNeededMostCheckbox = document.querySelector("#en__field_supporter_questions_8785940");
- const giftDesignationChooseCheckbox = document.querySelector("#en__field_supporter_questions_8785941");
- if (giftDesignationNeededMostCheckbox && giftDesignationChooseCheckbox) {
- giftDesignationChooseCheckbox.addEventListener("change", () => {
- if (giftDesignationChooseCheckbox.checked) {
- giftDesignationField.value = appealCode;
+ const activeTriggers = Object.keys(this.options.triggers).filter(t => this.options.triggers[t]).join(", ");
+ this.logger.log("Enabled, waiting for trigger. Active triggers: " + activeTriggers);
+ this.watchForTriggers();
+ }
+ watchForTriggers() {
+ window.addEventListener("load", () => {
+ setTimeout(() => {
+ if (this.options.triggers.mousePosition) {
+ this.watchMouse();
}
- });
- }
- // if the gift designation field is a select field,
- // and it doesnt have the url param value in its options, make that option and select it
- if (giftDesignationField.tagName === "SELECT") {
- let option = giftDesignationField.querySelector(`option[value="${appealCode}"]`);
- if (!option) {
- option = document.createElement("option");
- option.value = appealCode;
- option.text = appealCode;
- giftDesignationField.appendChild(option);
- giftDesignationField.value = appealCode;
- giftDesignationChooseCheckbox.checked = true;
+ if (this.options.triggers.visibilityState) {
+ this.watchDocumentVisibility();
+ }
+ }, this.triggerDelay); // Delay activation of triggers
+ });
+ }
+ watchMouse() {
+ document.addEventListener("mouseout", e => {
+ // If this is an autocomplete element.
+ if (e.target.tagName.toLowerCase() == "input") return;
+ // Get the current viewport width.
+ const vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
+ // If the current mouse X position is within 50px of the right edge
+ // of the viewport, return.
+ if (e.clientX >= vpWidth - 50) return;
+ // If the current mouse Y position is not within 50px of the top
+ // edge of the viewport, return.
+ if (e.clientY >= 50) return;
+ // Reliable, works on mouse exiting window and
+ // user switching active program
+ const from = e.relatedTarget;
+ if (!from) {
+ this.logger.log("Triggered by mouse position");
+ this.open();
}
- giftDesignationField.closest(".en__field")?.classList.add("hide");
- const label = document.querySelector("[for='en__field_supporter_questions_8785941']");
- if (label) {
- label.innerHTML = `I would like to designate my gift to ${option.innerText}.`;
+ if (!this.triggerTimeout) {
+ this.triggerTimeout = window.setTimeout(() => {
+ if (!from) {
+ this.logger.log("Triggered by mouse position");
+ this.open();
+ }
+ this.triggerTimeout = null;
+ }, this.triggerDelay);
}
- }
+ });
}
-
- /*
- * Make image selects on surveys into checkboxes
- * "engrid-checkboxes" needs to be somewhere inside the "reference name" field of the question
- */
- const imageSelectQuestions = document.querySelectorAll(".en__field--imgselect[class*='engrid-checkboxes']");
- imageSelectQuestions.forEach((question, i) => {
- const inputs = question.querySelectorAll("input[type='radio']");
- if (inputs.length === 0) return;
- question.className.split(" ").forEach(className => {
- // Remove the en__field--numbers class to prevent validation
- if (className.match(/en__field--\d+/)) {
- question.classList.remove(className);
+ watchDocumentVisibility() {
+ const visibilityListener = () => {
+ if (document.visibilityState === "hidden") {
+ if (!this.triggerTimeout) {
+ this.triggerTimeout = window.setTimeout(() => {
+ this.logger.log("Triggered by visibilityState is hidden");
+ this.open();
+ document.removeEventListener("visibilitychange", visibilityListener);
+ this.triggerTimeout = null;
+ }, this.triggerDelay);
+ }
}
+ };
+ document.addEventListener("visibilitychange", visibilityListener);
+ }
+ open() {
+ var _a, _b, _c;
+ if (this.opened) return;
+ dist_engrid_ENGrid.setBodyData("exit-intent-lightbox", "open");
+ cookie_set(this.options.cookieName, "1", {
+ expires: this.options.cookieDuration
});
- const hiddenInput = App.createHiddenInput(inputs[0].name);
- question.appendChild(hiddenInput);
- inputs.forEach(input => {
- input.type = "checkbox";
- input.name = `${input.name}-${i}`;
- input.addEventListener("change", () => {
- const checkedValues = [];
- inputs.forEach(input => {
- if (input.checked) {
- checkedValues.push(input.value);
- }
- hiddenInput.value = checkedValues.join(",");
+ document.body.insertAdjacentHTML("beforeend", `
+
+
+
+
X
+
+
${this.options.title}
+
${this.options.text}
+
+ ${this.options.buttonText}
+
+
+
+
+
+ `);
+ this.opened = true;
+ this.dataLayer.push({
+ event: "exit_intent_lightbox_shown"
+ });
+ (_a = document.querySelector(".ExitIntent__close")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
+ this.dataLayer.push({
+ event: "exit_intent_lightbox_closed"
+ });
+ this.close();
+ });
+ (_b = document.querySelector(".ExitIntent__overlay")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", event => {
+ if (event.target === event.currentTarget) {
+ this.dataLayer.push({
+ event: "exit_intent_lightbox_closed"
});
+ this.close();
+ }
+ });
+ (_c = document.querySelector(".ExitIntent__button")) === null || _c === void 0 ? void 0 : _c.addEventListener("click", () => {
+ this.dataLayer.push({
+ event: "exit_intent_lightbox_cta_clicked"
});
+ this.close();
+ const target = this.options.buttonLink;
+ if (target.startsWith(".") || target.startsWith("#")) {
+ const targetEl = document.querySelector(target);
+ if (targetEl) {
+ targetEl.scrollIntoView({
+ behavior: "smooth"
+ });
+ }
+ } else {
+ window.open(target, "_blank");
+ }
});
- });
-
- // Select donation amount based on URL parameter
- const donationIndex = new URLSearchParams(window.location.search).get("donationIndex");
- if (donationIndex) {
- const donationAmounts = document.querySelectorAll('input[name="transaction.donationAmt"]');
- if (donationAmounts[donationIndex]) {
- amt.setAmount(donationAmounts[donationIndex].value);
- }
- }
- const bannerImageSrc = document.querySelector(".body-banner img")?.src;
- const bodyBanner = document.querySelector(".body-banner");
- if (bodyBanner && bannerImageSrc) {
- bodyBanner.style.setProperty("--banner-image-src", `url(${bannerImageSrc})`);
}
-
- // Set the donation amount in sessionStorage when the mobile wallet iframe is focused
- const mobileWalletContainer = document.getElementById("en__digitalWallet");
- if (mobileWalletContainer) {
- const dataListener = () => {
- const iframe = mobileWalletContainer.getElementsByTagName("iframe");
- if (document.activeElement === iframe[0]) {
- setDonationDataSessionStorage(App, DonationAmount);
- window.removeEventListener("blur", dataListener);
- }
- };
- window.addEventListener("blur", dataListener);
+ close() {
+ var _a;
+ (_a = document.querySelector(".ExitIntent")) === null || _a === void 0 ? void 0 : _a.remove();
+ dist_engrid_ENGrid.setBodyData("exit-intent-lightbox", "closed");
}
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/supporter-hub.js
+// Component that adds 4Site Special Features to the Supporter Hub Page
- // Set the donation amount in sessionStorage when DAF (Chariot) button is clicked
- const chariotButton = document.getElementById("chariot-button");
- if (chariotButton) {
- chariotButton.addEventListener("click", () => {
- setDonationDataSessionStorage(App, DonationAmount);
- });
- } else {
- const chariotObserver = new MutationObserver(mutationsList => {
- for (const mutation of mutationsList) {
- if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+class supporter_hub_SupporterHub {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("SupporterHub", "black", "pink", "π");
+ this._form = events_en_form_EnForm.getInstance();
+ if (!this.shoudRun()) return;
+ this.logger.log("Enabled");
+ this.watch();
+ this.preventDuplicateSubmits();
+ }
+ shoudRun() {
+ return "pageJson" in window && "pageType" in window.pageJson && window.pageJson.pageType === "supporterhub";
+ }
+ watch() {
+ const form = dist_engrid_ENGrid.enForm;
+ // Create a observer to watch the Form for overlays
+ const observer = new MutationObserver(mutations => {
+ mutations.forEach(mutation => {
+ if (mutation.type === "childList") {
mutation.addedNodes.forEach(node => {
- if (node.nodeType === Node.ELEMENT_NODE && node.id && node.id === "chariot-button") {
- node.addEventListener("click", () => {
- setDonationDataSessionStorage(App, DonationAmount);
- });
- chariotObserver.disconnect();
+ if (node.nodeName === "DIV") {
+ const overlay = node;
+ if (overlay.classList.contains("en__hubOverlay") || overlay.classList.contains("en__hubPledge__panels")) {
+ this.logger.log("Overlay found");
+ this.creditCardUpdate(node);
+ this.amountLabelUpdate(node);
+ }
}
});
}
- }
+ });
});
- chariotObserver.observe(document.querySelector(".en__component--page"), {
+ // Start observing the Link ID
+ observer.observe(form, {
childList: true,
subtree: true
});
+ // Run the Credit Card Update function in case the overlay is already present on page load
+ const hubOverlay = document.querySelector(".en__hubOverlay");
+ if (hubOverlay) {
+ this.creditCardUpdate(hubOverlay);
+ this.amountLabelUpdate(hubOverlay);
+ }
+ }
+ creditCardUpdate(overlay) {
+ window.setTimeout(() => {
+ // Check if the overlay has Credit Card field and Update Button
+ const ccField = overlay.querySelector("#en__hubPledge__field--ccnumber"),
+ updateButton = overlay.querySelector(".en__hubUpdateCC__toggle");
+ if (ccField && updateButton) {
+ // When field gets focus, click the update button
+ ccField.addEventListener("focus", () => {
+ this.logger.log("Credit Card field focused");
+ updateButton.click();
+ });
+ }
+ }, 300);
+ }
+ amountLabelUpdate(overlay) {
+ window.setTimeout(() => {
+ // Check if the overlay has Amounts, and set the currency symbol updated attribute
+ const amountContainer = overlay.querySelector(".en__field--donationAmt");
+ if (amountContainer) {
+ amountContainer.querySelectorAll(".en__field__element--radio .en__field__item").forEach(node => {
+ node.setAttribute("data-engrid-currency-symbol-updated", "true");
+ });
+ }
+ }, 300);
+ }
+ // The supporter hub does not properly handle or prevent duplicate submits, so we add a listener to prevent this.
+ preventDuplicateSubmits() {
+ document.addEventListener("click", e => {
+ const btn = e.target.closest(".en__submit button");
+ if (!btn) return;
+ if (btn.dataset.busy) {
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ return;
+ }
+ btn.dataset.busy = "true";
+ setTimeout(() => delete btn.dataset.busy, 10000);
+ }, true);
}
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/fast-form-fill.js
+/**
+ * This class adds body data attributes if all mandatory inputs, on specific form blocks, are filled.
+ * Related styling (to hide elements) can be found in "fast-form-fill.scss".
+ *
+ * To activate: add the custom class "fast-personal-details" or "fast-address-details"
+ * to the relevant form block.
+ */
- // Accordion functionality
- const accordion = document.querySelectorAll(".accordion-header");
- accordion.forEach(button => {
- button.addEventListener("click", function () {
- const button = this.querySelector(".accordion-button");
- button.classList.toggle("collapsed");
- const panel = this.nextElementSibling;
- panel.classList.toggle("show");
- document.querySelectorAll(".accordion-item").forEach(el => {
- if (el.contains(button)) return;
- el.querySelector(".accordion-button").classList.add("collapsed");
- el.querySelector(".accordion-collapse").classList.remove("show");
+class fast_form_fill_FastFormFill {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("FastFormFill", "white", "magenta", "π");
+ this.rememberMeEvents = remember_me_events_RememberMeEvents.getInstance();
+ if (dist_engrid_ENGrid.getOption("RememberMe")) {
+ this.rememberMeEvents.onLoad.subscribe(hasData => {
+ this.logger.log("Remember me - onLoad", hasData);
+ this.run();
});
- });
- });
- const premiumHeader2 = document.querySelector(".premium-theme-2 .premium-theme-2-header");
- const premiumHeader3 = document.querySelector(".premium-theme-3 .premium-theme-3-header");
- const maxMyGift = () => {
- // If the selectedPremiumId is zero, we will maximize the gift
- const maxRadio = document.querySelector(".en__pg:last-child input[type='radio'][name='en__pg'][value='0']");
- const premiumTheme3Image = document.querySelector(".premium-theme-3 .premium-theme-3-image");
- if (maxRadio) {
- maxRadio.checked = true;
- maxRadio.click();
- setTimeout(() => {
- App.setFieldValue("transaction.selprodvariantid", "");
- }, 150);
+ this.rememberMeEvents.onClear.subscribe(() => {
+ // This is a test for the onClear event
+ this.logger.log("Remember me - onClear");
+ });
+ } else {
+ this.run();
}
- if (premiumTheme3Image) {
- premiumTheme3Image.style.backgroundImage = "var(--premium_image_theme_3)";
+ }
+ run() {
+ const fastPersonalDetailsFormBlocks = document.querySelectorAll(".en__component--formblock.fast-personal-details");
+ if (fastPersonalDetailsFormBlocks.length > 0) {
+ if ([...fastPersonalDetailsFormBlocks].every(formBlock => fast_form_fill_FastFormFill.allMandatoryInputsAreFilled(formBlock))) {
+ this.logger.log("Personal details - All mandatory inputs are filled");
+ dist_engrid_ENGrid.setBodyData("hide-fast-personal-details", "true");
+ } else {
+ this.logger.log("Personal details - Not all mandatory inputs are filled");
+ dist_engrid_ENGrid.setBodyData("hide-fast-personal-details", "false");
+ }
}
- };
- const setDefaultPremium = () => {
- if ("selectedPremiumId" in window) {
- if (window.selectedPremiumId > 0) {
- // We will not maximize the gift if the selectedPremiumId is already set
- const premiumFound = selectPremiumById(window.selectedPremiumId);
- if (!premiumFound) {
- const firstGift = document.querySelector(".en__pg:first-child input[type='radio'][name='en__pg']");
- if (firstGift && firstGift.value) selectPremiumById(firstGift.value);
- }
- return;
+ const fastAddressDetailsFormBlocks = document.querySelectorAll(".en__component--formblock.fast-address-details");
+ if (fastAddressDetailsFormBlocks.length > 0) {
+ if ([...fastAddressDetailsFormBlocks].every(formBlock => fast_form_fill_FastFormFill.allMandatoryInputsAreFilled(formBlock))) {
+ this.logger.log("Address details - All mandatory inputs are filled");
+ dist_engrid_ENGrid.setBodyData("hide-fast-address-details", "true");
} else {
- // If the selectedPremiumId is zero, we will maximize the gift
- maxMyGift();
+ this.logger.log("Address details - Not all mandatory inputs are filled");
+ dist_engrid_ENGrid.setBodyData("hide-fast-address-details", "false");
}
- } else {
- // If the selectedPremiumId is not set, we will select the first gift
- const firstGift = document.querySelector(".en__pg:first-child input[type='radio'][name='en__pg']");
- if (firstGift && firstGift.value) selectPremiumById(firstGift.value);
}
- };
- const selectPremiumById = premiumId => {
- const selectedGift = document.querySelector(`input[type="radio"][name="en__pg"][value="${premiumId}"]`);
- if (selectedGift) {
- window.setTimeout(() => {
- selectedGift.click();
- }, 10);
- const engridPremiumYes = document.querySelector("#engrid_premium_yes");
- const engridPremiumNo = document.querySelector("#engrid_premium_no");
- if (engridPremiumNo) {
- engridPremiumNo.checked = false;
+ }
+ static allMandatoryInputsAreFilled(formBlock) {
+ const fields = formBlock.querySelectorAll(".en__mandatory input, .en__mandatory select, .en__mandatory textarea");
+ return [...fields].every(input => {
+ if (input.type === "radio" || input.type === "checkbox") {
+ const inputs = document.querySelectorAll('[name="' + input.name + '"]');
+ return [...inputs].some(radioOrCheckbox => radioOrCheckbox.checked);
+ } else {
+ return input.value !== null && input.value.trim() !== "";
}
- if (engridPremiumYes) {
- engridPremiumYes.checked = true;
+ });
+ }
+ static someMandatoryInputsAreFilled(formBlock) {
+ const fields = formBlock.querySelectorAll(".en__mandatory input, .en__mandatory select, .en__mandatory textarea");
+ return [...fields].some(input => {
+ if (input.type === "radio" || input.type === "checkbox") {
+ const inputs = document.querySelectorAll('[name="' + input.name + '"]');
+ return [...inputs].some(radioOrCheckbox => radioOrCheckbox.checked);
+ } else {
+ return input.value !== null && input.value.trim() !== "";
}
- return true;
- } else {
- return false;
- }
- };
- const premiumBlock = document.querySelector(".en__component--premiumgiftblock");
- if (premiumBlock) {
- // Create a Premium Container
- const premiumContainer = document.createElement("div");
- premiumContainer.classList.add("premium-container");
- premiumContainer.classList.add("en__component");
- const premiumContainerContent = document.createElement("div");
- premiumContainerContent.classList.add("premium-container-content");
- premiumContainerContent.classList.add("en__component");
- premiumContainer.appendChild(premiumContainerContent);
- // Add the Premium Container after the Premium Block, then move the Premium Block inside the Premium Container
- premiumBlock.insertAdjacentElement("afterend", premiumContainer);
- premiumContainerContent.appendChild(premiumBlock);
-
- //listen for the change event of name "en__pg" using event delegation
- let selectedPremiumId = "selectedPremiumId" in window ? window.selectedPremiumId : null;
- let selectedVariantId = null;
- ["change", "click"].forEach(event => {
- premiumBlock.addEventListener(event, e => {
- setTimeout(() => {
- const selectedGift = document.querySelector('[name="en__pg"]:checked');
- if (selectedGift) {
- const selectedGiftImage = selectedGift.closest(".en__pg").querySelector("img");
- const premiumTheme3Image = document.querySelector(".premium-theme-3 .premium-theme-3-image");
- if (premiumTheme3Image) {
- premiumTheme3Image.dataset.selectedGift = selectedGift.value;
- if (selectedGiftImage) {
- premiumTheme3Image.style.backgroundImage = `url(${selectedGiftImage.src})`;
- } else {
- premiumTheme3Image.style.backgroundImage = "var(--premium_image_theme_3)";
- }
- }
- selectedPremiumId = selectedGift.value;
- selectedVariantId = App.getFieldValue("transaction.selprodvariantid");
- sessionStorage.setItem("selectedPremiumId", selectedPremiumId);
- sessionStorage.setItem("selectedVariantId", selectedVariantId);
- if (parseInt(selectedPremiumId) > 0) window.selectedPremiumId = selectedPremiumId;
- }
- }, 250);
- });
});
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/set-attr.js
+/*+
+ The class is used to set body attributes via click handlers.
+ The format is "setattr--{attribute}--{value}".
+ e.g. setattr--data-engrid-hide-fast-address-details--true
+ */
- // Mutation observer to check if the "Maximized Their Gift" radio button is present. If it is, hide it.
- const observer = new MutationObserver(mutationsList => {
- //loop over the mutations and if we're adding a radio with the "checked" attribute, remove that attribute so nothing gets re-selected
- //when the premiums list is re-rendered
- for (const mutation of mutationsList) {
- if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
- mutation.addedNodes.forEach(node => {
- if (typeof node.querySelector !== "function") return;
- const preSelectedRadio = node.querySelector("input[checked]");
- if (preSelectedRadio) {
- preSelectedRadio.removeAttribute("checked");
+class set_attr_SetAttr {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("SetAttr", "black", "yellow", "π");
+ const enGrid = document.getElementById("engrid");
+ if (enGrid) {
+ enGrid.addEventListener("click", e => {
+ const clickedEl = e.target;
+ if (typeof clickedEl.className !== "string") {
+ return;
+ }
+ const clickedElClassNames = clickedEl.className.split(" ");
+ if (clickedElClassNames.some(className => className.startsWith("setattr--"))) {
+ clickedEl.classList.forEach(className => {
+ //Check element has class with format "setattr--attribute--value"
+ const match = className.match(/^setattr--(.+)--(.+)$/i);
+ if (match && match[1] && match[2]) {
+ this.logger.log(`Clicked element with class "${className}". Setting body attribute "${match[1]}" to "${match[2]}"`);
+ dist_engrid_ENGrid.setBodyData(match[1].replace("data-engrid-", ""), match[2]);
}
});
}
- }
- if (mutationsList.some(mutation => mutation.type === "childList")) {
- // Re-select the previously selected gift when gift list is re-rendered
- // If gift no longer exists, choose maximize my gift
- if (selectedPremiumId && selectedVariantId) {
- const selectedGift = document.querySelector(`input[type="radio"][name="en__pg"][value="${selectedPremiumId}"]`);
- if (selectedGift) {
- selectedGift.click();
- window.setTimeout(() => {
- App.setFieldValue("transaction.selprodvariantid", selectedVariantId);
- }, 100);
- } else {
- setDefaultPremium();
- }
- } else {
- setDefaultPremium();
- }
- }
+ });
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/show-if-present.js
+/**
+ * This class contains the logic for special classes that can be used to hide elements if
+ * certain supporter questions are present or absent.
+ * Typically, this can be used to hide elements when an opt in question is not rendered on the page
+ * because the supporter came from a campaign link and is already opted in, so EN doesn't render
+ * the question on the page.
+ *
+ * The class names are of the format:
+ * engrid__supporterquestions{id}-present -- show this element when the supporter question is present
+ * engrid__supporterquestions{id}-absent -- show this element when the supporter question is absent
+ *
+ * The {id} is the id of the supporter question. This can be found by inspecting the element on the page.
+ *
+ * It's also possible to combine multiple questions using the following format. These examples show 2 questions,
+ * but you can use as many as you like:
+ * engrid__supporterquestions{id1}__supporterquestions{id2}-present -- show this element when EITHER question is present
+ * engrid__supporterquestions{id1}__supporterquestions{id2}-absent -- show this element when EITHER question is absent
+ */
+
+class show_if_present_ShowIfPresent {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("ShowIfPresent", "yellow", "black", "π");
+ this.elements = [];
+ if (this.shouldRun()) {
+ this.run();
+ }
+ }
+ shouldRun() {
+ // Check if we have any elements on the page that match the pattern for this functionality
+ // e.g. engrid__supporterquestions{id}__supporterquestions{id}-present, etc.
+ this.elements = [...document.querySelectorAll('[class*="engrid__supporterquestions"]')].filter(el => {
+ const classNames = el.className.split(" ");
+ return classNames.some(className => /^engrid__supporterquestions\d+(__supporterquestions\d+)*-(present|absent)$/.test(className));
});
- // Start observing the target node for configured mutations
- observer.observe(premiumBlock, {
- attributes: true,
- childList: true,
- subtree: true
+ return this.elements.length > 0;
+ }
+ run() {
+ const actions = [];
+ // Create an array of actions for each element we have
+ this.elements.forEach(el => {
+ // Mapping to an object with the class name, field name(s), and type
+ const classNames = el.className.split(" ");
+ const matchingClass = classNames.find(className => /^engrid__supporterquestions\d+(__supporterquestions\d+)*-(present|absent)$/.test(className));
+ if (!matchingClass) return null;
+ const typeIndex = matchingClass.lastIndexOf("-");
+ const type = matchingClass.substring(typeIndex + 1);
+ // Getting an array of the matching input names
+ // e.g. engrid__supporterquestions12345-present => ['supporter.questions.12345']
+ // e.g. engrid__supporterquestions12345__supporterquestions67890-present => ['supporter.questions.12345', 'supporter.questions.67890']
+ const inputIds = matchingClass.substring(8, typeIndex).split("__").map(id => `supporter.questions.${id.substring(18)}`);
+ actions.push({
+ class: matchingClass,
+ fieldNames: inputIds,
+ type: type
+ });
+ });
+ //Process the actions
+ actions.forEach(action => {
+ const inputElements = action.fieldNames.map(fieldName => document.getElementsByName(fieldName)[0]);
+ const elements = document.querySelectorAll(`.${action.class}`);
+ const areAllInputsPresent = inputElements.every(input => !!input);
+ const areAllInputsAbsent = inputElements.every(input => !input);
+ // Hide the elements based on AND conditions
+ if (action.type === "present" && areAllInputsAbsent || action.type === "absent" && areAllInputsPresent) {
+ this.logger.log(`Conditions not met, hiding elements with class ${action.class}`);
+ elements.forEach(el => {
+ el.style.display = "none";
+ });
+ }
});
}
- // Premium Gifts Theme 2 Script
- if (premiumHeader2) {
- const yesButton = premiumHeader2.querySelector("#engrid_premium_yes");
- const noButton = premiumHeader2.querySelector("#engrid_premium_no");
- if (yesButton && noButton) {
- yesButton.addEventListener("click", function () {
- const yesChecked = yesButton.checked;
- noButton.checked = !yesChecked;
- if (!yesChecked) {
- maxMyGift();
- } else {
- setDefaultPremium();
- }
- });
- noButton.addEventListener("click", function () {
- const noChecked = noButton.checked;
- yesButton.checked = !noChecked;
- if (noChecked) {
- maxMyGift();
- }
- });
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/en-validators.js
+// This component uses EN's Custom Validators on the client side to validate form fields.
+// It's currently behind a feature flag, so it's not enabled by default.
+// To enable it, add the following to your options:
+// ENValidators: true
+
+class en_validators_ENValidators {
+ constructor() {
+ this._form = events_en_form_EnForm.getInstance();
+ this._enElements = null;
+ this.logger = new dist_logger_EngridLogger("ENValidators", "white", "darkolivegreen", "π§");
+ if (!this.loadValidators()) {
+ // This is an error to flag a racing condition. If the script is loaded before the validators are loaded, it will not work.
+ this.logger.error("Not Loaded");
+ return;
}
- const premiumContainerContent = document.querySelector(".premium-container-content");
- if (premiumContainerContent) {
- // Move premiumHeader2 to the start of the premiumContainerContent
- premiumContainerContent.insertBefore(premiumHeader2, premiumContainerContent.firstChild);
+ if (!this.shouldRun()) {
+ // If there's no custom validators, get out
+ this.logger.log("Not Needed");
+ return;
}
+ this._form.onValidate.subscribe(this.enOnValidate.bind(this));
}
- // END Premium Gifts Theme 2 Script
- // Premium Gifts Theme 3 Script
- if (premiumHeader3) {
- const premium3ItemsContainer = document.querySelector(".premium-theme-3 .premium-theme-3-items-container");
- const premiumgiftblock = document.querySelector(".en__component--premiumgiftblock");
- const premiumContainerContent = document.querySelector(".premium-container-content");
- // Move premium gift block to the premium items container
- if (premiumgiftblock && premium3ItemsContainer) {
- premium3ItemsContainer.innerHTML = "";
- premium3ItemsContainer.appendChild(premiumgiftblock);
- if (premiumContainerContent) {
- premiumContainerContent.appendChild(premiumHeader3);
- }
+ loadValidators() {
+ if (!dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enValidation", "validation", "validators")) {
+ return false;
}
- }
- // END Premium Gifts Theme 3 Script
- // Limit premium availability to U.S. addresses only - START
- if ("pageJson" in window && "pageType" in window.pageJson && window.pageJson.pageType === "premiumgift") {
- const country = App.getField("supporter.country");
- const selectPremiumFromSession = () => {
- const selectedPremiumId = window.selectedPremiumId || sessionStorage.getItem("selectedPremiumId") || null;
- const selectedVariantId = sessionStorage.getItem("selectedVariantId");
- if (selectedPremiumId && selectedVariantId) {
- const selectedGift = document.querySelector(`input[type="radio"][name="en__pg"][value="${selectedPremiumId}"]`);
- if (selectedGift) {
- selectedGift.click();
- window.setTimeout(() => {
- App.setFieldValue("transaction.selprodvariantid", selectedVariantId);
- }, 100);
+ // Loop through the array validators and add them to this._enElements
+ const validators = window.EngagingNetworks.require._defined.enValidation.validation.validators;
+ this._enElements = validators.reduce((acc, validator) => {
+ if ("type" in validator && validator.type === "CUST") {
+ const container = document.querySelector(".en__field--" + validator.field);
+ const field = container ? container.querySelector("input, select, textarea") : null;
+ if (field) {
+ field.addEventListener("input", this.liveValidate.bind(this, container, field, validator.regex, validator.message));
+ acc.push({
+ container: container,
+ field: field,
+ regex: validator.regex,
+ message: validator.message
+ });
}
}
- };
- const disablePremiumBlock = (message = "Gifts Disabled") => {
- const premiumBlock = document.querySelector(".premium-theme-3-header, .en__component--premiumgiftblock");
- if (!premiumBlock || premiumBlock.dataset.dataAnnualDisabled === "true") {
+ return acc;
+ }, []);
+ return true;
+ }
+ // Should we run the script?
+ shouldRun() {
+ return dist_engrid_ENGrid.getOption("ENValidators") && this._enElements && this._enElements.length > 0;
+ }
+ // Don't submit the form if any of the fields are invalid
+ enOnValidate() {
+ if (!this._enElements || this._form.validate === false) {
+ return;
+ }
+ this._enElements.forEach(element => {
+ const fieldValidation = this.liveValidate(element.container, element.field, element.regex, element.message);
+ if (!fieldValidation) {
+ this._form.validate = false;
+ element.field.focus();
return;
}
- if (!premiumBlock.hasAttribute("disabled")) {
- // Keep the page scroll position when the premium block is disabled (hidden)
- keepScrollPosition(premiumBlock, "up");
- premiumBlock.setAttribute("disabled", "disabled");
- premiumBlock.setAttribute("aria-disabled", "true");
- premiumBlock.setAttribute("data-disabled-message", message);
- }
+ });
+ this._form.validate = true;
+ }
+ // Validate the field on the fly
+ liveValidate(container, field, regex, message) {
+ const value = dist_engrid_ENGrid.getFieldValue(field.getAttribute("name") || "");
+ // Do not validate empty fields, that's the job of the required validator
+ if (value === "") {
+ return true;
+ }
+ this.logger.log(`Live Validate ${field.getAttribute("name")} with ${regex}`);
+ // compare the value of the field with the regex
+ if (!value.match(regex)) {
+ // If the value is not valid, add the error message
+ dist_engrid_ENGrid.setError(container, message);
+ return false;
+ }
+ // If the value is valid, remove the error message
+ dist_engrid_ENGrid.removeError(container);
+ return true;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/modal.js
+
+class modal_Modal {
+ constructor(options) {
+ this.modal = null;
+ this.defaultOptions = {
+ onClickOutside: "close",
+ addCloseButton: false,
+ closeButtonLabel: "Okay!",
+ customClass: "",
+ showCloseX: true
};
- const enablePremiumBlock = () => {
- const premiumBlock = document.querySelector(".premium-theme-3-header, .en__component--premiumgiftblock");
- if (!premiumBlock || premiumBlock.dataset.dataAnnualDisabled === "true") {
+ this.focusTrapHandler = e => {
+ const modalElement = this.modal;
+ const focusableElements = [...modalElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')];
+ const firstFocusable = focusableElements[0];
+ const lastFocusable = focusableElements[focusableElements.length - 1];
+ const isTabPressed = e.key === "Tab";
+ if (!isTabPressed) {
return;
}
- if (premiumBlock.hasAttribute("disabled")) {
- // Keep the page scroll position when the premium block is enabled (shown)
- const scrollY = window.scrollY;
- const premiumStyle = window.getComputedStyle(premiumBlock);
- premiumBlock.removeAttribute("disabled");
- premiumBlock.removeAttribute("aria-disabled");
- premiumBlock.removeAttribute("data-disabled-message");
- const premiumSize = parseInt(premiumStyle.height, 10) + parseInt(premiumStyle.marginTop.replace("px", "")) + parseInt(premiumStyle.marginBottom.replace("px", ""));
- window.scrollTo(0, scrollY + premiumSize);
- console.log(premiumSize);
- }
- };
- const addCountryNotice = () => {
- if (!document.querySelector(".en__field--country .en__field__notice")) {
- App.addHtml('Note: We are unable to mail thank-you gifts to donors outside the United States and its territories and have selected the "Maximize my gift" option for you.
', ".en__field--country .en__field__element", "after");
+ if (e.shiftKey) {
+ if (document.activeElement === firstFocusable) {
+ e.preventDefault();
+ lastFocusable.focus();
+ }
+ } else {
+ if (document.activeElement === lastFocusable) {
+ e.preventDefault();
+ firstFocusable.focus();
+ }
}
};
- const removeCountryNotice = () => {
- App.removeHtml(".en__field--country .en__field__notice");
- };
- if (!window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed()) {
- setDefaultPremium();
+ this.options = Object.assign(Object.assign({}, this.defaultOptions), options);
+ this.modalContent = this.getModalContent();
+ this.createModal();
+ }
+ createModal() {
+ var _a;
+ this.modal = document.createElement("div");
+ this.modal.classList.add("engrid-modal", "modal--hidden");
+ if (this.options.customClass && this.options.customClass !== "") {
+ this.options.customClass.split(" ").forEach(customClass => {
+ if (!customClass) return;
+ this.modal.classList.add(customClass);
+ });
+ }
+ if (this.options.showCloseX) {
+ this.modal.classList.add("engrid-modal--close-x");
+ }
+ this.modal.setAttribute("aria-hidden", "true");
+ this.modal.setAttribute("role", "dialog");
+ this.modal.setAttribute("aria-modal", "true");
+ this.modal.setAttribute("tabindex", "-1");
+ this.modal.innerHTML = `
+
+ `;
+ (_a = document.getElementById("engrid")) === null || _a === void 0 ? void 0 : _a.appendChild(this.modal);
+ const modalBody = this.modal.querySelector(".engrid-modal__body");
+ if (this.modalContent instanceof NodeList) {
+ this.modalContent.forEach(content => {
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(content);
+ });
+ } else if (typeof this.modalContent === "string") {
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.insertAdjacentHTML("beforeend", this.modalContent);
} else {
- window.setTimeout(() => {
- selectPremiumFromSession();
- }, 1000);
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(this.modalContent);
}
- if (App.getUrlParameter("premium") !== "international" && country) {
- if (country.value !== "US") {
- const countryText = country.options[country.selectedIndex].text;
- setDefaultPremium();
- disablePremiumBlock(`Gifts Disabled in ${countryText}`);
- addCountryNotice();
- }
- country.addEventListener("change", () => {
- if (country.value !== "US") {
- const countryText = country.options[country.selectedIndex].text;
- setDefaultPremium();
- disablePremiumBlock(`Gifts Disabled in ${countryText}`);
- addCountryNotice();
- } else {
- enablePremiumBlock();
- removeCountryNotice();
+ if (this.options.addCloseButton) {
+ const button = document.createElement("button");
+ button.classList.add("engrid-modal__button");
+ button.textContent = this.options.closeButtonLabel;
+ button.addEventListener("click", () => {
+ this.close();
+ });
+ modalBody === null || modalBody === void 0 ? void 0 : modalBody.appendChild(button);
+ }
+ this.addEventListeners();
+ }
+ addEventListeners() {
+ var _a, _b, _c, _d, _e;
+ // Close event on top X
+ (_b = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector(".engrid-modal__close")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", () => {
+ this.close();
+ });
+ // Bounce scale when clicking outside of modal
+ (_d = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector(".engrid-modal__overlay")) === null || _d === void 0 ? void 0 : _d.addEventListener("click", event => {
+ if (event.target === event.currentTarget) {
+ if (this.options.onClickOutside === "close") {
+ this.close();
+ } else if (this.options.onClickOutside === "bounce") {
+ const modal = document.querySelector(".engrid-modal");
+ if (modal) {
+ modal.classList.remove("engrid-modal--scale");
+ void modal.clientWidth;
+ modal.classList.add("engrid-modal--scale");
+ }
}
+ }
+ });
+ // Close on "modal__close" click
+ const closeEls = (_e = this.modal) === null || _e === void 0 ? void 0 : _e.querySelectorAll(".modal__close");
+ closeEls === null || closeEls === void 0 ? void 0 : closeEls.forEach(el => {
+ el.addEventListener("click", () => {
+ this.close();
});
- freq.onFrequencyChange.subscribe(s => {
- if (country.value !== "US") {
- const countryText = country.options[country.selectedIndex].text;
- setDefaultPremium();
- disablePremiumBlock(`Gifts Disabled in ${countryText}`);
- } else {
- enablePremiumBlock();
+ });
+ }
+ open() {
+ var _a, _b, _c, _d;
+ dist_engrid_ENGrid.setBodyData("has-lightbox", "true");
+ (_a = this.modal) === null || _a === void 0 ? void 0 : _a.classList.remove("modal--hidden");
+ (_b = this.modal) === null || _b === void 0 ? void 0 : _b.removeAttribute("aria-hidden");
+ const container = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector(".engrid-modal__container");
+ container === null || container === void 0 ? void 0 : container.focus({
+ preventScroll: true
+ });
+ (_d = this.modal) === null || _d === void 0 ? void 0 : _d.addEventListener("keydown", this.focusTrapHandler);
+ }
+ close() {
+ var _a, _b, _c;
+ dist_engrid_ENGrid.setBodyData("has-lightbox", false);
+ (_a = this.modal) === null || _a === void 0 ? void 0 : _a.classList.add("modal--hidden");
+ (_b = this.modal) === null || _b === void 0 ? void 0 : _b.setAttribute("aria-hidden", "true");
+ (_c = this.modal) === null || _c === void 0 ? void 0 : _c.removeEventListener("keydown", this.focusTrapHandler);
+ }
+ getModalContent() {
+ return "Default Modal Content ";
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/postal-code-validator.js
+
+
+
+// Conditionally validates the postcode field for a US format zip code
+// If US is selected as the country, a country has not been selected yet
+// or if there is no country field
+// Allows blank zip code if zip code is not required.
+class postal_code_validator_PostalCodeValidator {
+ constructor() {
+ var _a, _b;
+ this.postalCodeField = dist_engrid_ENGrid.getField("supporter.postcode");
+ this._form = events_en_form_EnForm.getInstance();
+ this.logger = new dist_logger_EngridLogger("Postal Code Validator", "white", "red", "π¬");
+ this.supportedSeparators = ["+", "-", " "];
+ this.separator = this.getSeparator();
+ this.regexSeparator = this.getRegexSeparator(this.separator);
+ if (this.shouldRun()) {
+ (_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.addEventListener("blur", () => this.validate());
+ (_b = this.postalCodeField) === null || _b === void 0 ? void 0 : _b.addEventListener("input", () => this.liveValidate());
+ this._form.onValidate.subscribe(() => {
+ if (!this._form.validate) return;
+ this.liveValidate();
+ // It seems like we need some delay or EN removes our error message.
+ setTimeout(() => {
+ this.validate();
+ }, 100);
+ // We dont need to validate the zip code, or it is valid
+ const postalCodeValid = !this.shouldValidateUSZipCode() || this.isValidUSZipCode();
+ this._form.validate = postalCodeValid;
+ if (!postalCodeValid) {
+ this.logger.log(`Invalid Zip Code ${this.postalCodeField.value}`);
+ this.postalCodeField.scrollIntoView({
+ behavior: "smooth"
+ });
}
+ return postalCodeValid;
});
}
- // Look for a .no-premium-image image, if found set the --maximize_my_donation_image and delete the .no-premium-image image block (which is the closest .en__component--imageblock)
- const noPremiumImage = document.querySelector(".no-premium-image");
- if (noPremiumImage) {
- const premiumImageContainer = document.querySelector(".en__component--premiumgiftblock, .premium-theme-3-image");
- premiumImageContainer.style.setProperty("--maximize_my_donation_image", `url(${noPremiumImage.src})`);
- premiumImageContainer.style.setProperty("--premium_image_theme_3", `url(${noPremiumImage.src})`);
- noPremiumImage.closest(".en__component--imageblock")?.remove();
+ }
+ shouldRun() {
+ return !!(dist_engrid_ENGrid.getOption("PostalCodeValidator") && this.postalCodeField);
+ }
+ validate() {
+ if (this.shouldValidateUSZipCode() && !this.isValidUSZipCode()) {
+ dist_engrid_ENGrid.setError(".en__field--postcode", `Please enter a valid ZIP Code of ##### or #####${this.separator}####`);
+ } else {
+ dist_engrid_ENGrid.removeError(".en__field--postcode");
}
}
- // Limit premium availability to U.S. addresses only - END
-
- // Premium form shipping block - START
- const shippingCheckbox = document.querySelector("#en__field_supporter_questions_2133569");
- shippingCheckbox?.addEventListener("change", function () {
- const shippingEnabled = document.querySelector("#en__field_transaction_shipenabled");
- if (shippingEnabled) {
- shippingEnabled.checked = !this.checked;
- shippingEnabled.dispatchEvent(new Event("change", {
- bubbles: true
- }));
+ isValidUSZipCode() {
+ var _a, _b;
+ const zipCodeRequired = !!document.querySelector(".en__field--postcode.en__mandatory");
+ // If zip code is not required in EN Form Block and the field is empty, it is valid
+ if (!zipCodeRequired && ((_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.value) === "") {
+ return true;
}
- });
- // Premium form shipping block - END
+ const postalCodeRegex = new RegExp(`^\\d{5}(${this.regexSeparator}\\d{4})?$`);
+ return !!((_b = this.postalCodeField) === null || _b === void 0 ? void 0 : _b.value.match(postalCodeRegex));
+ }
+ /**
+ * Formats the zip code to #####-#### as the user inputs it
+ * The separator is determined by the TidyContact option, but defaults to "-"
+ */
+ liveValidate() {
+ var _a;
+ if (!this.shouldValidateUSZipCode()) return;
+ let value = (_a = this.postalCodeField) === null || _a === void 0 ? void 0 : _a.value;
+ // If the value is 5 characters or less, remove all non-numeric characters
+ if (value.length <= 5) {
+ value = value.replace(/\D/g, "");
+ }
+ // If one of the supported separators is endered as the 6th character, replace it with the official separator
+ else if (value.length === 6 && this.supportedSeparators.includes(value[5])) {
+ // Removing all non-numeric characters
+ value = value.replace(/\D/g, "") + this.separator;
+ } else {
+ // Removing all non-numeric characters
+ value = value.replace(/\D/g, "");
+ // Adding the separator after the 5th character
+ value = value.replace(/(\d{5})(\d)/, `$1${this.separator}$2`);
+ }
+ //set field value with max 10 characters
+ this.postalCodeField.value = value.slice(0, 10);
+ }
+ shouldValidateUSZipCode() {
+ // Validating US zip code only if country is US, country has not yet been selected
+ // or if there is no country field
+ const country = dist_engrid_ENGrid.getField("supporter.country") ? dist_engrid_ENGrid.getFieldValue("supporter.country") : "US";
+ return ["us", "united states", "usa", ""].includes(country.toLowerCase());
+ }
+ getSeparator() {
+ const tidyContact = dist_engrid_ENGrid.getOption("TidyContact");
+ if (tidyContact && tidyContact.us_zip_divider && this.supportedSeparators.includes(tidyContact.us_zip_divider)) {
+ return tidyContact.us_zip_divider;
+ }
+ return "-";
+ }
+ getRegexSeparator(separator) {
+ switch (separator) {
+ case "+":
+ return "\\+";
+ case "-":
+ return "-";
+ case " ":
+ return "\\s";
+ default:
+ this.logger.log(`Invalid separator "${separator}" provided to PostalCodeValidator, falling back to "-".`);
+ return "-";
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/vgs.js
+// This component allows you to customize the VGS theme options
+//
+// It is used in the following way:
+//
+// VGS: {
+// "transaction.ccnumber": {
+// showCardIcon: true,
+// placeholder: "β’β’β’β’ β’β’β’β’ β’β’β’β’ β’β’β’β’",
+// icons: {
+// (icons can't be urls, they have to be base64 encoded images)
+// cardPlaceholder: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%233BBF45'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z'/%3E%3C/svg%3E"
+// visa: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath fill='%233BBF45' d='M384 32H0v448h384V32z'/%3E%3Cpath fill='white' d='M128.5 352.5l-32-192h-32l32 192zm96-192l-32 192h-32l32-192z'/%3E%3C/svg%3E",
+// },
+// },
+// "transaction.ccvv": {
+// showCardIcon: false,
+// placeholder: "CVV",
+// hideValue: false,
+// },
+// },
+//
+// The VGS component can also be set at the page level, if necessary
+//
- // Move text to below the Premium Gift Header.
- const pgInfo = document.querySelector(".insert-after--pg-header");
- const pgHeader = document.querySelector(".en__pgHeader");
- if (pgHeader && pgInfo) {
- pgHeader.insertAdjacentElement("afterend", pgInfo);
+class vgs_VGS {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("VGS", "black", "pink", "π³");
+ this.vgsField = document.querySelector(".en__field--vgs");
+ this.options = dist_engrid_ENGrid.getOption("VGS");
+ this.paymentTypeField = document.querySelector("#en__field_transaction_paymenttype");
+ this._form = events_en_form_EnForm.getInstance();
+ this.field_expiration_month = null;
+ this.field_expiration_year = null;
+ this.handleExpUpdate = e => {
+ if (!this.field_expiration_month || !this.field_expiration_year) return;
+ const current_date = new Date();
+ const current_month = current_date.getMonth() + 1;
+ const current_year = parseInt(this.field_expiration_year[this.field_expiration_year.length - 1].value) > 2000 ? current_date.getFullYear() : current_date.getFullYear() - 2000;
+ // handle if year is changed to current year (disable all months less than current month)
+ // handle if month is changed to less than current month (disable current year)
+ if (e == "month") {
+ let selected_month = parseInt(this.field_expiration_month.value);
+ let disable = selected_month < current_month;
+ this.logger.log(`month disable ${disable}`);
+ this.logger.log(`selected_month ${selected_month}`);
+ for (let i = 0; i < this.field_expiration_year.options.length; i++) {
+ // disable or enable current year
+ if (parseInt(this.field_expiration_year.options[i].value) <= current_year) {
+ if (disable) {
+ this.field_expiration_year.options[i].setAttribute("disabled", "disabled");
+ } else {
+ this.field_expiration_year.options[i].disabled = false;
+ }
+ }
+ }
+ } else if (e == "year") {
+ let selected_year = parseInt(this.field_expiration_year.value);
+ let disable = selected_year == current_year;
+ this.logger.log(`year disable ${disable}`);
+ this.logger.log(`selected_year ${selected_year}`);
+ for (let i = 0; i < this.field_expiration_month.options.length; i++) {
+ // disable or enable all months less than current month
+ if (parseInt(this.field_expiration_month.options[i].value) < current_month) {
+ if (disable) {
+ this.field_expiration_month.options[i].setAttribute("disabled", "disabled");
+ } else {
+ this.field_expiration_month.options[i].disabled = false;
+ }
+ }
+ }
+ }
+ };
+ if (!this.shouldRun()) return;
+ this.setPaymentType();
+ this.setDefaults();
+ this.dumpGlobalVar();
+ const expireFiels = document.getElementsByName("transaction.ccexpire");
+ if (expireFiels) {
+ this.field_expiration_month = expireFiels[0];
+ this.field_expiration_year = expireFiels[1];
+ }
+ // Add event listeners to the expiration fields
+ if (this.field_expiration_month && this.field_expiration_year) {
+ ["change"].forEach(event => {
+ var _a, _b;
+ (_a = this.field_expiration_month) === null || _a === void 0 ? void 0 : _a.addEventListener(event, () => {
+ this.handleExpUpdate("month");
+ });
+ (_b = this.field_expiration_year) === null || _b === void 0 ? void 0 : _b.addEventListener(event, () => {
+ this.handleExpUpdate("year");
+ });
+ });
+ }
+ this._form.onValidate.subscribe(() => {
+ if (this._form.validate) {
+ const isValid = this.validate();
+ this.logger.log(`Form Validation: ${isValid}`);
+ this._form.validate = isValid;
+ }
+ });
}
- // Set specific placeholders
- const creditCardField = document.querySelector('input[name="supporter.creditCardHolderName"]');
- if (creditCardField) {
- creditCardField.setAttribute("placeholder", "Card Holder Name");
+ shouldRun() {
+ // Only run if the vgs field is present
+ if (!this.vgsField) return false;
+ return true;
}
- const accountHolderField = document.querySelector('input[name="supporter.NOT_TAGGED_79"]');
- if (accountHolderField) {
- accountHolderField.setAttribute("placeholder", "Account Holder's Name");
+ setDefaults() {
+ //EN attempts to define a few default styles for VGS fields based on our text field styling
+ //This does not always work, so we will provide our own defaults
+ const bodyStyles = getComputedStyle(document.body);
+ const styles = {
+ fontFamily: bodyStyles.getPropertyValue("--input_font-family") || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'",
+ fontSize: bodyStyles.getPropertyValue("--input_font-size") || "16px",
+ color: bodyStyles.getPropertyValue("--input_color") || "#000",
+ padding: bodyStyles.getPropertyValue("--input_padding") || "10px",
+ "&::placeholder": {
+ color: bodyStyles.getPropertyValue("--input_placeholder-color") || "#a9a9a9",
+ opacity: bodyStyles.getPropertyValue("--input_placeholder-opacity") || "1",
+ fontWeight: bodyStyles.getPropertyValue("--input_placeholder-font-weight") || "normal"
+ }
+ };
+ const options = this.options;
+ const defaultOptions = {
+ "transaction.ccnumber": {
+ showCardIcon: true,
+ placeholder: "β’β’β’β’ β’β’β’β’ β’β’β’β’ β’β’β’β’",
+ icons: {
+ cardPlaceholder: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAYAAADHl1ErAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB8ElEQVR4nO2c4W3CMBBGz1H/NyNkAzoCo2SDrkI3YJSOABt0g9IJXBnOqUkMyifUqkrek04RlvMjT2c7sc6EGKPBfBpcaSBMBGEiCBNBmAjCRBAmgjARhIkgTARhIggTQZhK2q0Yh5l1ZrYzs0PqsrI4+LN3VTeThkvntUm6Fbuxn2E/LITQmtm7mW08Sb/MbO9tpxhjui6WEMLWzJKDdO3N7Nmf9ZjaYoyn8y8X1o6GXxLV1lJyDeE+9oWPQ/ZRG4b9WkVVpqe+8LLLo7ErM6t248qllZnWBc+uV5+zumGsQjm3f/ic9tb4JGeeXcga4U723rptilVx0avgg2Q3m/JNn+y6zeAm+GSWUi/c7L5yfB77RJhACOHs6WnuLfmGpTI3YditEEGYCMJEECaCMJHZqySvHRfIMBGEiSBMBGEiCBNBmAjCRBAmgjARhIkgTGT2t+R/59EdYXZcfwmEiSBMBGEiCBNZzCr5VzvCZJjIIMxrPKFC6abMsHbaFcZuGq8StqKwDqZkN8emKBbrvawHCtxJ7y1nVxQF34lxUXBupOy8EtWy88jBhknUDjbkPhyd+Xn2l9lHZ8rgcNZVTA5nTYRFjv/dPf7HvzuJ8C0pgjARhIkgTARhIggTQZgIwkQQJoIwEYSJIEwEYQpm9g2Ro5zhLcuLBwAAAABJRU5ErkJggg=="
+ },
+ css: styles,
+ // Autocomplete is not customizable
+ autoComplete: "cc-number",
+ validations: ["required", "validCardNumber"],
+ validCardBrands: null
+ },
+ "transaction.ccvv": {
+ showCardIcon: false,
+ placeholder: "CVV",
+ hideValue: false,
+ // Autocomplete is not customizable
+ autoComplete: "cc-csc",
+ validations: ["required", "validCardSecurityCode"],
+ css: styles
+ },
+ "transaction.ccexpire": {
+ placeholder: "MM/YY",
+ autoComplete: "cc-exp",
+ validations: ["required", "validCardExpirationDate"],
+ css: styles
+ }
+ };
+ // Override the validCardBrands if set in the theme options, as this should not be deep merged.
+ if (options && options["transaction.ccnumber"] && options["transaction.ccnumber"].validCardBrands) {
+ defaultOptions["transaction.ccnumber"].validCardBrands = options["transaction.ccnumber"].validCardBrands;
+ }
+ // Deep merge the default options with the options set in the theme
+ this.options = dist_engrid_ENGrid.deepMerge(defaultOptions, options);
+ this.logger.log("Options", this.options);
}
- const bankNameField = document.querySelector('input[name="transaction.bankname"]');
- if (bankNameField) {
- bankNameField.setAttribute("placeholder", "Bank Name");
+ setPaymentType() {
+ // If there's no default payment type, set the default to card
+ if (dist_engrid_ENGrid.getPaymentType() === "") {
+ dist_engrid_ENGrid.setPaymentType("card");
+ }
+ }
+ dumpGlobalVar() {
+ // Dump the global variable for the VGS options
+ window.enVGSFields = this.options;
+ // EN is not reading the global variable because their JS file loads before ENgrid, so we're going to HACK TOWN
+ // Clean up the VGS iFrames
+ window.setTimeout(() => {
+ const vgsIElements = document.querySelectorAll(".en__field__input--vgs");
+ if (vgsIElements.length > 0) {
+ // Create a mutation observer that cleans the VGS Elements before anything is rendered
+ const observer = new MutationObserver(mutations => {
+ mutations.forEach(mutation => {
+ var _a;
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
+ mutation.addedNodes.forEach(node => {
+ if (node.nodeName === "IFRAME" && mutation.previousSibling && mutation.previousSibling.nodeName === "IFRAME") {
+ // Delete the previous sibling
+ mutation.previousSibling.remove();
+ }
+ });
+ }
+ // Check if the VGS Element is valid, and remove any validation classes and errors
+ if (mutation.type === "attributes" && mutation.attributeName === "class") {
+ const target = mutation.target;
+ if (target.classList.contains("vgs-collect-container__valid")) {
+ const fieldWrapper = target.closest(".en__field--vgs");
+ fieldWrapper === null || fieldWrapper === void 0 ? void 0 : fieldWrapper.classList.remove("en__field--validationFailed");
+ (_a = fieldWrapper === null || fieldWrapper === void 0 ? void 0 : fieldWrapper.querySelector(".en__field__error")) === null || _a === void 0 ? void 0 : _a.remove();
+ }
+ }
+ });
+ });
+ // Observe the VGS Elements
+ vgsIElements.forEach(vgsIElement => {
+ observer.observe(vgsIElement, {
+ childList: true,
+ attributeFilter: ["class"]
+ });
+ });
+ if (dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "vgs")) {
+ window.EngagingNetworks.require._defined.enjs.vgs.init();
+ } else {
+ this.logger.log("VGS is not defined");
+ }
+ }
+ }, 1000);
+ }
+ validate() {
+ if (this.paymentTypeField.value.toLowerCase() === "card" || this.paymentTypeField.value.toLowerCase() === "visa" || this.paymentTypeField.value.toLowerCase() === "vi") {
+ const cardContainer = document.querySelector(".en__field--vgs.en__field--ccnumber");
+ const cardEmpty = cardContainer === null || cardContainer === void 0 ? void 0 : cardContainer.querySelector(".vgs-collect-container__empty");
+ const cvvContainer = document.querySelector(".en__field--vgs.en__field--ccvv");
+ const cvvEmpty = cvvContainer === null || cvvContainer === void 0 ? void 0 : cvvContainer.querySelector(".vgs-collect-container__empty");
+ if (cardContainer && cardEmpty) {
+ window.setTimeout(() => {
+ dist_engrid_ENGrid.setError(cardContainer, "Please enter a valid card number");
+ // Scroll to the error
+ cardContainer.scrollIntoView({
+ behavior: "smooth"
+ });
+ }, 100);
+ return false;
+ }
+ if (cvvContainer && cvvEmpty) {
+ window.setTimeout(() => {
+ dist_engrid_ENGrid.setError(cvvContainer, "Please enter a valid CVV");
+ // Scroll to the error
+ cvvContainer.scrollIntoView({
+ behavior: "smooth"
+ });
+ }, 100);
+ return false;
+ }
+ }
+ return true;
}
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/country-redirect.js
+// This component allows you to redirect the user to a different page based on their country.
+// It works by checking the country field on the page and comparing it to the list of countries in the CountryRedirect option.
+// If the country matches one of the countries in the list, the user is redirected to the specified URL only if the URL is not the same as the current page.
+// The CountryRedirect option is an object with the country as the key and the URL as the value.
+// Example:
+//
+// CountryRedirect: {
+// US: "https://example.com/us",
+// CA: "https://example.com/ca",
+// GB: "https://example.com/gb",
+// },
+// The country codes must match the country codes in the country field
+// The CountryRedirect component can also be set at the page level. Useful for Regional Pages, with a Code Block like this:
+//
+//
+//
+// This will override the default CountryRedirect options for that page.
+//
- // Add placeholder to the Mobile Phone Field
- let enFieldMobilePhone = document.querySelector("input#en__field_supporter_phoneNumber2");
- if (enFieldMobilePhone) {
- enFieldMobilePhone.placeholder = enFieldMobilePhone.closest(".en__field")?.classList.contains("en__mandatory") ? "Mobile / Phone" : "Mobile / Phone (Optional)";
+class country_redirect_CountryRedirect {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("CountryRedirect", "white", "brown", "π«");
+ this._country = country_Country.getInstance();
+ if (!this.shouldRun()) return;
+ this._country.onCountryChange.subscribe(country => {
+ this.checkRedirect(country);
+ });
+ this.checkRedirect(this._country.country); // This will check the redirect when the page loads
}
- const observerConfig = {
- attributes: true,
- attributeFilter: ["placeholder", "aria-required"],
- subtree: true
- };
- const updatePlaceholder = field => {
- if (field.name === "transaction.donationAmt.other") {
- return; // Exclude specific field
+ shouldRun() {
+ // Only run if the CountryRedirect option is not false and the country field is present
+ if (!dist_engrid_ENGrid.getOption("CountryRedirect") || !this._country.countryField) {
+ return false;
}
- const isFieldRequired = field.required || field.getAttribute("aria-required") === "true" || field.closest(".en__component--formblock.i-required");
- const placeholder = field.getAttribute("placeholder");
- if (placeholder) {
- if (isFieldRequired && !placeholder.endsWith("*")) {
- field.setAttribute("placeholder", `${placeholder}*`);
- } else if (!isFieldRequired && placeholder.endsWith("*")) {
- field.setAttribute("placeholder", placeholder.slice(0, -1));
+ return true;
+ }
+ checkRedirect(country) {
+ const countryRedirect = dist_engrid_ENGrid.getOption("CountryRedirect");
+ // Check if the country is in the list and if the current URL is not the same as the redirect URL
+ // We are using includes because the URL might have query parameters
+ if (countryRedirect && country in countryRedirect && window.location.href.includes(countryRedirect[country]) === false) {
+ this.logger.log(`${country}: Redirecting to ${countryRedirect[country]}`);
+ let redirectUrl = new URL(countryRedirect[country]);
+ // If the redirect URL doesn't contain "?chain", add it
+ if (!redirectUrl.search.includes("chain")) {
+ redirectUrl.search += (redirectUrl.search ? "&" : "?") + "chain";
}
+ window.location.href = redirectUrl.href;
}
- };
- // Update required fields
- const fields = document.querySelectorAll("input[placeholder], textarea[placeholder]");
- fields.forEach(field => {
- updatePlaceholder(field);
-
- // Observe placeholder and aria-required changes
- const observer = new MutationObserver(() => updatePlaceholder(field));
- observer.observe(field, observerConfig);
- });
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/welcome-back.js
+/**
+ * This component adds a welcome back message and a personal details summary to the page.
+ * It depends on the "fast-personal-details" functionality from the FastFormFill component.
+ * The component will only run, when the "WelcomeBack" option is set,
+ * if the "fast-personal-details" class is present on the page and the FastFormFill conditions
+ * are met (all mandatory inputs in that block are filled).
+ *
+ * All the text content and positioning is configurable through the "WelcomeBack" option.
+ */
- //Allow override of pre-selected NSG amount
- function setPreselectedAmountFromUrl() {
- const hiddenInput = document.querySelector('input[name="transaction.donationAmt.sgid"]');
- // If the hidden input is already present, the EN NSG script has already run, set the amount immediately
- if (hiddenInput) {
- setTimeout(() => amt.setAmount(urlParams.get("transaction.donationAmt")), 1000);
- return;
+class welcome_back_WelcomeBack {
+ constructor() {
+ var _a;
+ this._form = events_en_form_EnForm.getInstance();
+ this.supporterDetails = {};
+ this.options = (_a = dist_engrid_ENGrid.getOption("WelcomeBack")) !== null && _a !== void 0 ? _a : false;
+ this.rememberMeEvents = remember_me_events_RememberMeEvents.getInstance();
+ this.hasRun = false;
+ if (!this.shouldRun()) return;
+ if (dist_engrid_ENGrid.getOption("RememberMe")) {
+ this.rememberMeEvents.onLoad.subscribe(() => {
+ this.run();
+ });
+ this.rememberMeEvents.onClear.subscribe(() => {
+ this.resetWelcomeBack();
+ });
+ } else {
+ this.run();
}
-
- // Otherwise, we will use a mutation observer to wait for the hidden input to be added to the DOM
- const observer = new MutationObserver((mutationsList, observer) => {
- for (const mutation of mutationsList) {
- if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
- const hiddenInput = document.querySelector('input[name="transaction.donationAmt.sgid"]');
- if (hiddenInput) {
- setTimeout(() => amt.setAmount(urlParams.get("transaction.donationAmt")), 1000);
- observer.disconnect();
- }
- }
- }
- });
- const pageForm = document.querySelector("form.en__component--page");
- if (!pageForm) return;
- observer.observe(pageForm, {
- childList: true,
- subtree: true
- });
}
- if (urlParams.has("transaction.donationAmt") && window.EngagingNetworks.suggestedGift && window.EngagingNetworks.suggestedGift.single && window.EngagingNetworks.suggestedGift.recurring) {
- setPreselectedAmountFromUrl();
+ run() {
+ if (this.hasRun) return;
+ this.hasRun = true;
+ this.supporterDetails = {
+ firstName: dist_engrid_ENGrid.getFieldValue("supporter.firstName"),
+ lastName: dist_engrid_ENGrid.getFieldValue("supporter.lastName"),
+ emailAddress: dist_engrid_ENGrid.getFieldValue("supporter.emailAddress"),
+ address1: dist_engrid_ENGrid.getFieldValue("supporter.address1"),
+ address2: dist_engrid_ENGrid.getFieldValue("supporter.address2"),
+ city: dist_engrid_ENGrid.getFieldValue("supporter.city"),
+ region: dist_engrid_ENGrid.getFieldValue("supporter.region"),
+ postcode: dist_engrid_ENGrid.getFieldValue("supporter.postcode"),
+ country: dist_engrid_ENGrid.getFieldValue("supporter.country"),
+ mobilePhone: dist_engrid_ENGrid.getFieldValue("supporter.phoneNumber2")
+ };
+ this.addWelcomeBack();
+ this.addPersonalDetailsSummary();
+ this.addEventListeners();
}
- document.querySelectorAll("h2.alt-ways-give-accordion, h2.by-the-num-accordion").forEach(title => {
- title.addEventListener("click", () => {
- const items = title.nextElementSibling;
- if (!items || !items.classList.contains("pre-footer-items") && !items.classList.contains("contact-us")) return;
- items.classList.toggle("hide");
+ shouldRun() {
+ return !!document.querySelector(".fast-personal-details") && dist_engrid_ENGrid.getBodyData("embedded") !== "thank-you-page-donation" && this.options !== false;
+ }
+ addWelcomeBack() {
+ var _a;
+ if (typeof this.options !== "object" || !this.options.welcomeBackMessage.display) return;
+ const options = this.options.welcomeBackMessage;
+ const welcomeBack = document.createElement("div");
+ welcomeBack.classList.add("engrid-welcome-back", "showif-fast-personal-details");
+ const title = options.title.replace("{firstName}", this.supporterDetails["firstName"]);
+ welcomeBack.innerHTML = `
+ ${title}
+ ${options.editText}
+
`;
+ (_a = document.querySelector(options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(options.placement, welcomeBack);
+ }
+ resetWelcomeBack() {
+ const inputs = document.querySelectorAll(".fast-personal-details .en__field__input");
+ inputs.forEach(input => {
+ if (input.type === "checkbox" || input.type === "radio") {
+ input.checked = false;
+ } else {
+ input.value = "";
+ }
});
- });
- function toggleClickToExpand() {
- const clickToExpandElements = document.querySelectorAll(".click-to-expand-tnc-toggle");
- clickToExpandElements.forEach(el => {
- el.insertAdjacentHTML("afterend", 'Read Less
');
- const closeButton = el.parentElement.querySelector(".click-to-expand-close");
- closeButton.addEventListener("click", () => {
- el.classList.remove("expanded");
+ this.supporterDetails = {};
+ dist_engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ cookie_remove("engrid-autofill");
+ }
+ addPersonalDetailsSummary() {
+ var _a;
+ if (typeof this.options !== "object" || !this.options.personalDetailsSummary.display) return;
+ let options = this.options.personalDetailsSummary;
+ const personalDetailsSummary = document.createElement("div");
+ personalDetailsSummary.classList.add("engrid-personal-details-summary", "showif-fast-personal-details");
+ personalDetailsSummary.innerHTML = `${options.title} `;
+ personalDetailsSummary.insertAdjacentHTML("beforeend", `
+
+ ${this.supporterDetails["firstName"]} ${this.supporterDetails["lastName"]}
+
+ ${this.supporterDetails["emailAddress"]}
+ ${this.supporterDetails["mobilePhone"] && options.showPhoneNumber ? ` ${this.supporterDetails["mobilePhone"]}` : ""}
+
+ `);
+ if (this.supporterDetails["address1"] && this.supporterDetails["city"] && this.supporterDetails["region"] && this.supporterDetails["postcode"]) {
+ personalDetailsSummary.insertAdjacentHTML("beforeend", `
+
+ ${this.supporterDetails["address1"]} ${this.supporterDetails["address2"]}
+
+ ${this.supporterDetails["city"]}, ${this.supporterDetails["region"]}
+ ${this.supporterDetails["postcode"]}
+
+ `);
+ }
+ personalDetailsSummary.insertAdjacentHTML("beforeend", `
+ ${options.editText}
+ `);
+ (_a = document.querySelector(options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(options.placement, personalDetailsSummary);
+ }
+ addEventListeners() {
+ document.querySelectorAll(".engrid-reset-welcome-back").forEach(element => {
+ element.addEventListener("click", () => {
+ this.resetWelcomeBack();
});
});
- }
- toggleClickToExpand();
- function addEcardAltTags() {
- const ecardImages = [...document.querySelectorAll(".en__ecarditems__thumb img")];
- const altTexts = [...document.querySelectorAll(".engrid-ecard-alt-tags p")];
- ecardImages.forEach((img, index) => {
- if (altTexts[index]) {
- img.setAttribute("alt", altTexts[index].textContent);
- }
+ this._form.onValidate.subscribe(this.enOnValidate.bind(this));
+ this._form.onValidate.subscribe(() => {
+ window.setTimeout(this.doubleCheckValidation.bind(this), 150);
});
}
- addEcardAltTags();
+ enOnValidate() {
+ if (!this._form.validate) {
+ // Disable the fast personal details if the form is invalidated by other components running before
+ dist_engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ return;
+ }
+ const regionField = dist_engrid_ENGrid.getField("supporter.region");
+ const regionFieldValue = regionField ? regionField.value : "";
+ const regionFieldType = regionField === null || regionField === void 0 ? void 0 : regionField.tagName.toLowerCase();
+ const regionFieldLabel = document.querySelector(".en__field--region label");
+ if (regionFieldType === "select" && regionFieldLabel && regionFieldValue === "") {
+ dist_engrid_ENGrid.setError(".en__field--region", `${regionFieldLabel.innerText} is required`);
+ dist_engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ this._form.validate = false;
+ } else {
+ // Remove the error message if the region field is filled
+ dist_engrid_ENGrid.removeError(".en__field--region");
+ }
+ }
+ doubleCheckValidation() {
+ // Disable the fast personal details if the form is invalidated by other components running AFTER
+ // the fast personal details component
+ const validationError = document.querySelector(".fast-personal-details .en__field--validationFailed");
+ if (validationError) {
+ dist_engrid_ENGrid.setBodyData("hide-fast-personal-details", false);
+ validationError.scrollIntoView({
+ behavior: "smooth",
+ block: "center"
+ });
+ }
+ return;
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/ecard-to-target-options.js
+const ecard_to_target_options_EcardToTargetOptionsDefaults = {
+ targetName: "",
+ targetEmail: "",
+ hideSendDate: true,
+ hideTarget: true,
+ hideMessage: true,
+ addSupporterNameToMessage: false,
+ targets: []
};
-;// CONCATENATED MODULE: ./src/scripts/bequest-lightbox.ts
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/ecard-to-target.js
+/**
+ * This component adjusts an ecard form to target a specific recipient,
+ * defined in a code block
+ */
+
-class BequestLightbox {
+class ecard_to_target_EcardToTarget {
constructor() {
- _defineProperty(this, "logger", new logger_EngridLogger("BequestLightbox", "yellow", "black"));
- _defineProperty(this, "modalContent", null);
- _defineProperty(this, "bequestUserProfile", undefined);
- _defineProperty(this, "pageJson", void 0);
- this.modalContent = document.querySelector(".modal--bequest");
- this.bequestUserProfile = window.bequestUserProfile || undefined;
- this.pageJson = window.pageJson;
- if (!this.shouldRun()) {
- this.logger.log("Not running bequest modal.");
- return;
- }
- this.addModal();
- if (this.shouldOpen()) {
- this.open();
- }
- this.logConditions();
+ this.options = ecard_to_target_options_EcardToTargetOptionsDefaults;
+ this.logger = new dist_logger_EngridLogger("EcardToTarget", "DarkBlue", "Azure", "π§");
+ this._form = events_en_form_EnForm.getInstance();
+ this.supporterNameAddedToMessage = false;
+ if (!this.shouldRun()) return;
+ this.options = Object.assign(Object.assign({}, this.options), window.EngridEcardToTarget);
+ this.logger.log("EcardToTarget running. Options:", this.options);
+ this.setTarget();
+ this.hideElements();
+ this.addSupporterNameToMessage();
}
shouldRun() {
- if (this.modalContent && !this.bequestUserProfile) {
- this.logger.log("Bequest modal found, but no user profile found. Please add the User Profile Script.");
+ return window.hasOwnProperty("EngridEcardToTarget") && typeof window.EngridEcardToTarget === "object" && (window.EngridEcardToTarget.hasOwnProperty("targetName") && window.EngridEcardToTarget.hasOwnProperty("targetEmail") || window.EngridEcardToTarget.hasOwnProperty("targets") && window.EngridEcardToTarget.targets.length > 0);
+ }
+ setTarget() {
+ const targetNameField = document.querySelector(".en__ecardrecipients__name input");
+ const targetEmailField = document.querySelector(".en__ecardrecipients__email input");
+ const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
+ if (!targetNameField || !targetEmailField || !addRecipientButton) {
+ this.logger.error("Could not add recipient. Required elements not found.");
+ return;
}
- return !!this.modalContent && !!this.bequestUserProfile;
- }
- shouldOpen() {
- if (this.modalContent?.classList.contains("modal--always-open")) {
- this.logger.log("Opening bequest modal. Always open trigger found.");
- return true;
+ let targets = this.options.targets;
+ // BC support for targetName and targetEmail
+ if (this.options.targetName && this.options.targetEmail) {
+ targets.push({
+ targetName: this.options.targetName,
+ targetEmail: this.options.targetEmail
+ });
}
- if (this.lessRestrictiveTrigger()) {
- this.logger.log("Opening bequest modal. Less restrictive trigger found.");
- return true;
+ // Remove duplicates from targets array
+ targets = targets.filter((target, index, self) => index === self.findIndex(t => t.targetName === target.targetName && t.targetEmail === target.targetEmail));
+ targets.forEach(target => {
+ const targetName = target.targetName;
+ const targetEmail = target.targetEmail;
+ if (!targetName || !targetEmail) {
+ this.logger.error("Could not add recipient. Target name or email is empty.");
+ return;
+ }
+ targetNameField.value = targetName;
+ targetEmailField.value = targetEmail;
+ addRecipientButton === null || addRecipientButton === void 0 ? void 0 : addRecipientButton.click();
+ this.logger.log("Added recipient", targetName, targetEmail);
+ });
+ }
+ hideElements() {
+ const messageBlock = document.querySelector(".en__ecardmessage");
+ const sendDateBlock = document.querySelector(".en__ecardrecipients__futureDelivery");
+ const targetBlock = document.querySelector(".en__ecardrecipients");
+ if (this.options.hideMessage && messageBlock) {
+ messageBlock.classList.add("hide");
}
- if (this.strictTrigger()) {
- this.logger.log("Opening bequest modal. Strict trigger found.");
- return true;
+ if (this.options.hideSendDate && sendDateBlock) {
+ sendDateBlock.classList.add("hide");
}
- this.logger.log("Not opening bequest modal. No conditions met.");
- return false;
- }
- logConditions() {
- // prettier-ignore
- this.logger.log(`country: ${this.pageJson?.country}
- amount: ${this.pageJson?.amount}
- doNotSendSolicitations: ${this.bequestUserProfile?.doNotSendSolicitations}
- crmConstituency: ${this.bequestUserProfile?.crmConstituency}
- plannedGiftProspect: ${this.bequestUserProfile?.plannedGiftProspect}
- totalNumberOfGifts: ${this.bequestUserProfile?.totalNumberOfGifts}
- includeInPlannedGivingSolicitations: ${this.bequestUserProfile?.includeInPlannedGivingSolicitations}
- bequest_lb_select: ${this.getCookie("bequest_lb_select")}
- gp_form_submitted: ${this.getCookie("gp_form_submitted")}
- per_gp: ${this.getCookie("per_gp")}
- gp_email: ${this.getCookie("gp_email")}`);
-
- // prettier-ignore
- this.logger.log(`country: ${this.pageJson?.country} = ${this.pageJson?.country === "US"}
- doNotSendSolicitations: ${this.bequestUserProfile?.doNotSendSolicitations} === "Y" = ${this.bequestUserProfile?.doNotSendSolicitations === "Y"}
- crmConstituency: ${this.bequestUserProfile?.crmConstituency} includes "Legacy Club" = ${this.bequestUserProfile?.crmConstituency?.includes("Legacy Club")}
- amount: ${this.pageJson?.amount} >= 100 = ${this.pageJson?.amount >= 100}
- bequest_lb_select: ${this.getCookie("bequest_lb_select")} = ${this.getCookie("bequest_lb_select")}
- gp_form_submitted: ${this.getCookie("gp_form_submitted")} = ${this.getCookie("gp_form_submitted")}
- per_gp: ${this.getCookie("per_gp")} = ${this.getCookie("per_gp")}
- gp_email: ${this.getCookie("gp_email")} = ${this.getCookie("gp_email")}
- totalNumberOfGifts: ${this.bequestUserProfile?.totalNumberOfGifts} >= 3 = ${Number(this.bequestUserProfile?.totalNumberOfGifts) >= 3}
- includeInPlannedGivingSolicitations: ${this.bequestUserProfile?.includeInPlannedGivingSolicitations} === "Y" = ${this.bequestUserProfile?.includeInPlannedGivingSolicitations === "Y"}
- plannedGiftProspect: ${this.bequestUserProfile?.plannedGiftProspect} === "Y" = ${this.bequestUserProfile?.plannedGiftProspect === "Y"}`);
- }
- lessRestrictiveTrigger() {
- if (this.modalContent?.classList.contains("modal--bequest-less-restrictive") && this.pageJson?.country === "US" && this.bequestUserProfile?.doNotSendSolicitations !== "Y" && !this.bequestUserProfile?.crmConstituency?.includes("Legacy Club") && !this.getCookie("bequest_lb_select") && !this.getCookie("gp_form_submitted")) {
- this.logger.log("Less restrictive trigger passed condition");
- return true;
+ if (this.options.hideTarget && targetBlock) {
+ targetBlock.classList.add("hide");
}
- return false;
}
- strictTrigger() {
- if (this.pageJson?.country === "US" && this.bequestUserProfile?.doNotSendSolicitations !== "Y" && !this.bequestUserProfile?.crmConstituency?.includes("Legacy Club") && this.pageJson?.amount >= 100 && !this.getCookie("bequest_lb_select") && !this.getCookie("gp_form_submitted")) {
- this.logger.log("Strict trigger passed first condition");
- if (this.getCookie("per_gp") === "true" || this.getCookie("gp_email") === "true" || Number(this.bequestUserProfile?.totalNumberOfGifts) >= 3 || this.bequestUserProfile?.includeInPlannedGivingSolicitations === "Y" || this.bequestUserProfile?.plannedGiftProspect === "Y") {
- this.logger.log("Strict trigger passed second condition");
- return true;
+ addSupporterNameToMessage() {
+ if (!this.options.addSupporterNameToMessage) return;
+ this._form.onSubmit.subscribe(() => {
+ if (!this._form.submit) return;
+ if (!this.supporterNameAddedToMessage) {
+ this.supporterNameAddedToMessage = true;
+ const supporterName = `${dist_engrid_ENGrid.getFieldValue("supporter.firstName")} ${dist_engrid_ENGrid.getFieldValue("supporter.lastName")}`;
+ const messageField = document.querySelector("[name='transaction.comments']");
+ if (!messageField) return;
+ messageField.value = `${messageField.value}\n${supporterName}`;
+ this.logger.log("Added supporter name to personalized message", supporterName);
}
- }
- return false;
+ });
}
- addModal() {
- document.body.insertAdjacentHTML("beforeend", `
-
-
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/interfaces/embedded-ecard-options.js
+const embedded_ecard_options_EmbeddedEcardOptionsDefaults = {
+ pageUrl: "",
+ headerText: "Send an Ecard notification of your gift",
+ checkboxText: "Yes, I would like to send an ecard to announce my gift.",
+ anchor: ".en__field--donationAmt",
+ placement: "afterend",
+ requireInMemCheckbox: false
+};
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/embedded-ecard.js
+/**
+ * This class handles adding a checkbox to a form that, when checked, will display an embedded ecard form.
+ * The embedded ecard form is hosted on a separate page and is displayed in an iframe.
+ * The form data is saved in session storage and is submitted when the thank you page is loaded.
+ * Options can set on the page via window.EngridEmbeddedEcard.
+ */
+
+
+class embedded_ecard_EmbeddedEcard {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("Embedded Ecard", "#D95D39", "#0E1428", "π§");
+ this.options = embedded_ecard_options_EmbeddedEcardOptionsDefaults;
+ this._form = events_en_form_EnForm.getInstance();
+ this.isSubmitting = false;
+ this.ecardFormActive = false;
+ this.iframe = null;
+ // For the page hosting the embedded ecard
+ if (this.onHostPage()) {
+ // Clean up session variables if the page is reloaded, and it isn't a submission failure
+ const submissionFailed = !!(dist_engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed());
+ if (!submissionFailed) {
+ sessionStorage.removeItem("engrid-embedded-ecard");
+ sessionStorage.removeItem("engrid-send-embedded-ecard");
+ }
+ this.options = Object.assign(Object.assign({}, embedded_ecard_options_EmbeddedEcardOptionsDefaults), window.EngridEmbeddedEcard);
+ const pageUrl = new URL(this.options.pageUrl);
+ pageUrl.searchParams.append("data-engrid-embedded-ecard", "true");
+ pageUrl.searchParams.append("chain", "");
+ this.options.pageUrl = pageUrl.href;
+ this.logger.log("Running Embedded Ecard component", this.options);
+ this.embedEcard();
+ this.addEventListeners();
+ }
+ // For the thank you page - after the host page form has been submitted
+ // Only runs if eCard was selected on the main page
+ if (this.onPostActionPage()) {
+ dist_engrid_ENGrid.setBodyData("embedded-ecard-sent", "true");
+ this.submitEcard();
+ }
+ // For the page that is embedded
+ if (this.onEmbeddedEcardPage()) {
+ this.setupEmbeddedPage();
+ }
+ }
+ onHostPage() {
+ return window.hasOwnProperty("EngridEmbeddedEcard") && typeof window.EngridEmbeddedEcard === "object" && window.EngridEmbeddedEcard.hasOwnProperty("pageUrl") && window.EngridEmbeddedEcard.pageUrl !== "";
+ }
+ onEmbeddedEcardPage() {
+ return dist_engrid_ENGrid.getPageType() === "ECARD" && dist_engrid_ENGrid.hasBodyData("embedded") && dist_engrid_ENGrid.getPageNumber() === 1;
+ }
+ onPostActionPage() {
+ return sessionStorage.getItem("engrid-embedded-ecard") !== null && sessionStorage.getItem("engrid-send-embedded-ecard") !== null && !this.onHostPage() && !this.onEmbeddedEcardPage();
+ }
+ embedEcard() {
+ var _a;
+ const container = document.createElement("div");
+ container.classList.add("engrid--embedded-ecard");
+ const heading = document.createElement("h3");
+ heading.textContent = this.options.headerText;
+ heading.classList.add("engrid--embedded-ecard-heading");
+ container.appendChild(heading);
+ const checkbox = document.createElement("div");
+ checkbox.classList.add("pseudo-en-field", "en__field", "en__field--checkbox", "en__field--000000", "en__field--embedded-ecard");
+ checkbox.innerHTML = `
+
+
+
+ ${this.options.checkboxText}
-
`);
- document.querySelector(".engrid-modal .engrid-modal__body")?.appendChild(this.modalContent);
- this.addEventListeners();
+
`;
+ container.appendChild(checkbox);
+ this.iframe = this.createIframe(this.options.pageUrl);
+ container.appendChild(this.iframe);
+ (_a = document.querySelector(this.options.anchor)) === null || _a === void 0 ? void 0 : _a.insertAdjacentElement(this.options.placement, container);
}
- open() {
- engrid_ENGrid.setBodyData("modal", "open");
- engrid_ENGrid.setBodyData("bequest-lightbox", "open");
- trackEvent("lightbox_impression", {
- lightbox_name: "bequest"
- });
+ createIframe(url) {
+ const iframe = document.createElement("iframe");
+ iframe.src = url;
+ iframe.setAttribute("src", url);
+ iframe.setAttribute("width", "100%");
+ iframe.setAttribute("scrolling", "no");
+ iframe.setAttribute("frameborder", "0");
+ iframe.setAttribute("title", "Ecard iframe");
+ iframe.classList.add("engrid-iframe", "engrid-iframe--embedded-ecard");
+ iframe.style.display = "none";
+ return iframe;
}
addEventListeners() {
- // Close event on top X
- document.querySelector(".engrid-modal__close")?.addEventListener("click", () => {
- this.close();
+ var _a;
+ const sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
+ if (this.options.requireInMemCheckbox) {
+ const inMemoriamCheckbox = document.getElementById("en__field_transaction_inmem");
+ inMemoriamCheckbox === null || inMemoriamCheckbox === void 0 ? void 0 : inMemoriamCheckbox.addEventListener("change", e => {
+ const checkbox = e.target;
+ const _sendEcardCheckbox = document.getElementById("en__field_embedded-ecard");
+ this.toggleEcardForm(checkbox.checked && _sendEcardCheckbox.checked);
+ });
+ this.toggleEcardForm(((_a = inMemoriamCheckbox === null || inMemoriamCheckbox === void 0 ? void 0 : inMemoriamCheckbox.checked) !== null && _a !== void 0 ? _a : true) && sendEcardCheckbox.checked);
+ } else {
+ this.toggleEcardForm(sendEcardCheckbox.checked);
+ }
+ sendEcardCheckbox === null || sendEcardCheckbox === void 0 ? void 0 : sendEcardCheckbox.addEventListener("change", e => {
+ const checkbox = e.target;
+ this.toggleEcardForm(checkbox.checked);
});
-
- // Bounce scale when clicking outside of modal
- document.querySelector(".engrid-modal__overlay")?.addEventListener("click", event => {
- if (event.target === event.currentTarget) {
- const modal = document.querySelector(".engrid-modal");
- if (modal) {
- modal.classList.remove("engrid-modal--scale");
- void modal.clientWidth;
- modal.classList.add("engrid-modal--scale");
+ this._form.onValidate.subscribe(this.validateRecipients.bind(this));
+ }
+ validateRecipients() {
+ var _a, _b, _c, _d;
+ if (!this.ecardFormActive || !this._form.validate) return;
+ this.logger.log("Validating ecard");
+ let embeddedEcardData = JSON.parse(sessionStorage.getItem("engrid-embedded-ecard") || "{}");
+ // Testing if the ecard recipient data is set and valid
+ if (!embeddedEcardData.formData || !embeddedEcardData.formData.recipients || embeddedEcardData.formData.recipients.length == 0 || embeddedEcardData.formData.recipients.some(recipient => {
+ const recipientName = recipient.name;
+ const recipientEmail = recipient.email;
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ return recipientName === "" || recipientEmail === "" || !emailRegex.test(recipientEmail);
+ })) {
+ this.logger.log("Ecard recipients validation failed");
+ this._form.validate = false;
+ this.sendPostMessage(this.iframe, "recipient_error");
+ const iframeDoc = ((_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentDocument) || ((_c = (_b = this.iframe) === null || _b === void 0 ? void 0 : _b.contentWindow) === null || _c === void 0 ? void 0 : _c.document);
+ if (!iframeDoc) return;
+ const scrollTarget = iframeDoc.querySelector(".en__ecardrecipients");
+ if (!scrollTarget) return;
+ const iframeRect = (_d = this.iframe) === null || _d === void 0 ? void 0 : _d.getBoundingClientRect();
+ if (!iframeRect) return;
+ const elementRect = scrollTarget.getBoundingClientRect();
+ window.scrollTo({
+ top: iframeRect.top + elementRect.top + window.scrollY - 10,
+ behavior: "smooth"
+ });
+ }
+ }
+ toggleEcardForm(visible) {
+ const iframe = document.querySelector(".engrid-iframe--embedded-ecard");
+ this.ecardFormActive = visible;
+ if (visible) {
+ iframe === null || iframe === void 0 ? void 0 : iframe.setAttribute("style", "display: block");
+ sessionStorage.setItem("engrid-send-embedded-ecard", "true");
+ this.logger.log("Ecard form is visible");
+ } else {
+ iframe === null || iframe === void 0 ? void 0 : iframe.setAttribute("style", "display: none");
+ sessionStorage.removeItem("engrid-send-embedded-ecard");
+ this.logger.log("Ecard form is hidden");
+ }
+ }
+ setEmbeddedEcardSessionData() {
+ let ecardVariant = document.querySelector("[name='friend.ecard']");
+ let ecardSendDate = document.querySelector("[name='ecard.schedule']");
+ let ecardMessage = document.querySelector("[name='transaction.comments']");
+ //add "chain" param to window.location.href if it doesnt have it
+ const pageUrl = new URL(window.location.href);
+ if (!pageUrl.searchParams.has("chain")) {
+ pageUrl.searchParams.append("chain", "");
+ }
+ const embeddedEcardData = {
+ pageUrl: pageUrl.href,
+ formData: {
+ ecardVariant: (ecardVariant === null || ecardVariant === void 0 ? void 0 : ecardVariant.value) || "",
+ ecardSendDate: (ecardSendDate === null || ecardSendDate === void 0 ? void 0 : ecardSendDate.value) || "",
+ ecardMessage: (ecardMessage === null || ecardMessage === void 0 ? void 0 : ecardMessage.value) || "",
+ recipients: this.getEcardRecipients()
+ }
+ };
+ sessionStorage.setItem("engrid-embedded-ecard", JSON.stringify(embeddedEcardData));
+ }
+ getEcardRecipients() {
+ const recipients = [];
+ const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
+ //Single recipient form where the "add recipient" button is hidden, and we use the recipient name and email fields
+ const isSingleRecipientForm = !addRecipientButton || addRecipientButton.offsetHeight === 0;
+ if (isSingleRecipientForm) {
+ // When it is a single recipient form, we only need to get the recipient name and email from the input fields
+ let recipientName = document.querySelector(".en__ecardrecipients__name > input");
+ let recipientEmail = document.querySelector(".en__ecardrecipients__email > input");
+ if (recipientName && recipientEmail) {
+ recipients.push({
+ name: recipientName.value,
+ email: recipientEmail.value
+ });
+ }
+ return recipients;
+ }
+ // For multiple recipient forms, we need to get the recipient name and email from each recipient in the recipient list
+ const recipientList = document.querySelector(".en__ecardrecipients__list");
+ recipientList === null || recipientList === void 0 ? void 0 : recipientList.querySelectorAll(".en__ecardrecipients__recipient").forEach(el => {
+ const recipientName = el.querySelector(".ecardrecipient__name");
+ const recipientEmail = el.querySelector(".ecardrecipient__email");
+ if (recipientName && recipientEmail) {
+ recipients.push({
+ name: recipientName.value,
+ email: recipientEmail.value
+ });
+ }
+ });
+ return recipients;
+ }
+ setupEmbeddedPage() {
+ let ecardVariant = document.querySelector("[name='friend.ecard']");
+ let ecardSendDate = document.querySelector("[name='ecard.schedule']");
+ let ecardMessage = document.querySelector("[name='transaction.comments']");
+ let recipientName = document.querySelector(".en__ecardrecipients__name > input");
+ let recipientEmail = document.querySelector(".en__ecardrecipients__email > input");
+ [ecardVariant, ecardSendDate, ecardMessage, recipientName, recipientEmail].forEach(el => {
+ el.addEventListener("input", () => {
+ if (this.isSubmitting) return;
+ this.setEmbeddedEcardSessionData();
+ });
+ });
+ // MutationObserver to detect changes in the recipient list and update the session data
+ const observer = new MutationObserver(mutationsList => {
+ for (let mutation of mutationsList) {
+ if (mutation.type === "childList") {
+ if (this.isSubmitting) return;
+ this.setEmbeddedEcardSessionData();
}
}
});
-
- // Close on "modal__close" click
- const closeEls = document.querySelectorAll(".modal__close");
- closeEls.forEach(el => {
+ const recipientList = document.querySelector(".en__ecardrecipients__list");
+ if (recipientList) {
+ observer.observe(recipientList, {
+ childList: true
+ });
+ }
+ document.querySelectorAll(".en__ecarditems__thumb").forEach(el => {
+ // Making sure the session value is changed when this is clicked
el.addEventListener("click", () => {
- this.close();
+ ecardVariant.dispatchEvent(new Event("input"));
});
});
-
- // Resize iframe on load
- const iframe = document.querySelector(".engrid-modal__body iframe");
- if (iframe) {
- this.resizeIframe(iframe);
- iframe.addEventListener("load", () => {
- this.resizeIframe(iframe);
+ // Remove the recipient error message when the user starts typing in the recipient fields
+ [recipientName, recipientEmail].forEach(el => {
+ el.addEventListener("input", () => {
+ const recipientDetails = document.querySelector(".en__ecardrecipients__detail");
+ const error = document.querySelector(".engrid__recipient__error");
+ recipientDetails === null || recipientDetails === void 0 ? void 0 : recipientDetails.classList.remove("validationFail");
+ error === null || error === void 0 ? void 0 : error.classList.add("hide");
});
- window.addEventListener("resize", () => {
- this.resizeIframe(iframe);
- });
- }
-
- // Listen for iframe submission message from iframe page 2, and close modal.
- window.addEventListener("message", event => {
- if (event.data === "iframeSubmitted") {
- this.close();
- trackEvent("lightbox_click", {
- lightbox_name: "bequest"
- });
- }
});
- }
- close() {
- engrid_ENGrid.setBodyData("modal", "closed");
- engrid_ENGrid.setBodyData("bequest-lightbox", "closed");
- }
- resizeIframe(iframe) {
- iframe.style.height = iframe.contentWindow?.document.body.scrollHeight + "px";
- }
- getCookie(cookieName) {
- const name = `${cookieName}=`;
- const decodedCookie = decodeURIComponent(document.cookie);
- const cookieArray = decodedCookie.split(";");
- for (let i = 0; i < cookieArray.length; i++) {
- let cookie = cookieArray[i];
- while (cookie.charAt(0) === " ") {
- cookie = cookie.substring(1);
+ window.addEventListener("message", e => {
+ if (e.origin !== location.origin || !e.data.action) return;
+ this.logger.log("Received post message", e.data);
+ switch (e.data.action) {
+ case "submit_form":
+ this.isSubmitting = true;
+ let embeddedEcardData = JSON.parse(sessionStorage.getItem("engrid-embedded-ecard") || "{}");
+ if (ecardVariant) {
+ ecardVariant.value = embeddedEcardData.formData["ecardVariant"];
+ }
+ if (ecardSendDate) {
+ ecardSendDate.value = embeddedEcardData.formData["ecardSendDate"];
+ }
+ if (ecardMessage) {
+ ecardMessage.value = embeddedEcardData.formData["ecardMessage"];
+ }
+ const addRecipientButton = document.querySelector(".en__ecarditems__addrecipient");
+ embeddedEcardData.formData.recipients.forEach(recipient => {
+ recipientName.value = recipient.name;
+ recipientEmail.value = recipient.email;
+ addRecipientButton === null || addRecipientButton === void 0 ? void 0 : addRecipientButton.click();
+ });
+ const form = events_en_form_EnForm.getInstance();
+ form.submitForm();
+ sessionStorage.removeItem("engrid-embedded-ecard");
+ sessionStorage.removeItem("engrid-send-embedded-ecard");
+ break;
+ case "set_recipient":
+ recipientName.value = e.data.name;
+ recipientEmail.value = e.data.email;
+ recipientName.dispatchEvent(new Event("input"));
+ recipientEmail.dispatchEvent(new Event("input"));
+ break;
+ case "recipient_error":
+ const recipientDetails = document.querySelector(".en__ecardrecipients__detail");
+ const error = document.querySelector(".engrid__recipient__error");
+ if (error) {
+ error.classList.remove("hide");
+ } else {
+ recipientDetails === null || recipientDetails === void 0 ? void 0 : recipientDetails.insertAdjacentHTML("afterend", "
Please provide the details for your eCard recipient
");
+ }
+ recipientDetails === null || recipientDetails === void 0 ? void 0 : recipientDetails.classList.add("validationFail");
+ window.dispatchEvent(new Event("resize"));
+ break;
}
- if (cookie.indexOf(name) === 0) {
- return cookie.substring(name.length, cookie.length);
+ });
+ this.sendPostMessage("parent", "ecard_form_ready");
+ }
+ submitEcard() {
+ var _a;
+ const embeddedEcardData = JSON.parse(sessionStorage.getItem("engrid-embedded-ecard") || "{}");
+ this.logger.log("Submitting ecard", embeddedEcardData);
+ const iframe = this.createIframe(embeddedEcardData.pageUrl);
+ (_a = document.querySelector(".body-main")) === null || _a === void 0 ? void 0 : _a.appendChild(iframe);
+ window.addEventListener("message", e => {
+ if (e.origin !== location.origin || !e.data.action) return;
+ if (e.data.action === "ecard_form_ready") {
+ this.sendPostMessage(iframe, "submit_form");
}
+ });
+ }
+ sendPostMessage(target, action, data = {}) {
+ var _a;
+ if (!target) return;
+ const message = Object.assign({
+ action
+ }, data);
+ if (target === "parent") {
+ window.parent.postMessage(message, location.origin);
+ } else {
+ (_a = target.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, location.origin);
}
- return null;
}
}
-// EXTERNAL MODULE: ./node_modules/tippy.js/dist/tippy.esm.js + 54 modules
-var tippy_esm = __webpack_require__(9244);
-;// CONCATENATED MODULE: ./src/scripts/tooltip.ts
-
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/us-only-form.js
+/*
+ * This class disables the country field and fixes the country to "United States"
+ */
-class Tooltip {
+class us_only_form_UsOnlyForm {
constructor() {
- _defineProperty(this, "Els", void 0);
- this.Els = document.querySelectorAll("[data-engrid-tooltip]");
if (!this.shouldRun()) return;
- this.addTooltips();
+ if (!document.querySelector(".en__field--country .en__field__notice")) {
+ dist_engrid_ENGrid.addHtml('
Note: This action is limited to U.S. addresses.
', ".us-only-form .en__field--country .en__field__element", "after");
+ }
+ const countrySelect = dist_engrid_ENGrid.getField("supporter.country");
+ countrySelect.setAttribute("disabled", "disabled");
+ let countryValue = "United States";
+ if ([...countrySelect.options].some(o => o.value === "US")) {
+ countryValue = "US";
+ } else if ([...countrySelect.options].some(o => o.value === "USA")) {
+ countryValue = "USA";
+ }
+ dist_engrid_ENGrid.setFieldValue("supporter.country", countryValue);
+ dist_engrid_ENGrid.createHiddenInput("supporter.country", countryValue);
+ countrySelect.addEventListener("change", () => {
+ countrySelect.value = countryValue;
+ });
}
shouldRun() {
- return this.Els.length > 0;
- }
- addTooltips() {
- this.Els.forEach(el => {
- const content = el.getAttribute("data-engrid-tooltip");
- const trigger = el.getAttribute("data-engrid-tooltip-trigger") || "click";
- if (!content) return;
- (0,tippy_esm/* default */.Ay)(el, {
- content: content,
- theme: "light-border",
- allowHTML: true,
- trigger: trigger,
- hideOnClick: "toggle"
- });
- });
+ return !!document.querySelector(".en__component--formblock.us-only-form .en__field--country");
}
}
-;// CONCATENATED MODULE: ./src/scripts/ihmo.ts
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/thank-you-page-conditional-content.js
-
-class IHMO {
+class thank_you_page_conditional_content_ThankYouPageConditionalContent {
constructor() {
- _defineProperty(this, "giftType", "HONORARY");
- _defineProperty(this, "giftNotification", "ECARD");
- _defineProperty(this, "formLayouts", {
- HONORARY: {
- ECARD: {
- topFields: [".en__field--honname", ".en__field--othamt2"],
- bottomFields: [".en__field--infemail"]
- },
- MAIL: {
- topFields: [".en__field--honname", ".en__field--othamt2"],
- bottomFields: [".en__field--NOT_TAGGED_38", ".en__field--NOT_TAGGED_33", ".en__field--NOT_TAGGED_34", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35", ".en__field--NOT_TAGGED_37"]
- },
- NONE: {
- topFields: [".en__field--honname", ".en__field--othamt2"],
- bottomFields: []
- }
- },
- MEMORIAL: {
- ECARD: {
- topFields: [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35"],
- bottomFields: [".en__field--infname", ".en__field--othamt3", ".en__field--infemail"]
- },
- MAIL: {
- topFields: [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35"],
- bottomFields: [".en__field--infname", ".en__field--othamt3", ".en__field--infcountry", ".en__field--infadd1", ".en__field--infadd2", ".en__field--infcity", ".en__field--infreg", ".en__field--infpostcd"]
- },
- NONE: {
- topFields: [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35"],
- bottomFields: []
- }
- }
- });
- _defineProperty(this, "ihmoCheckbox", document.querySelector('[name="transaction.inmem"][type="checkbox"]'));
- _defineProperty(this, "topForm", document.querySelector(".ihmo-top-form"));
- _defineProperty(this, "bottomForm", document.querySelector(".ihmo-bottom-form"));
- _defineProperty(this, "_donationFrequency", DonationFrequency.getInstance());
- _defineProperty(this, "sourceCodeField", document.querySelector('[name="supporter.appealCode"]'));
- // If we're on the thank you page, add the gift details as data attributes and return
- if (this.onThankYouPage()) {
- this.setGiftDetailsAsDataAttributes();
- return;
- }
- // Stop here if we're not on an IHMO page
+ this.logger = new dist_logger_EngridLogger("ThankYouPageConditionalContent");
if (!this.shouldRun()) return;
- this.createPageLayout();
- this.configureForm(this.giftType, this.giftNotification);
- this.addEventListeners();
- this.hideAllFields();
- this.setDefaultSourceCodes();
- // If IHMO is checked, save the gift details and set the source code
- if (this.ihmoCheckbox?.checked) {
- this.saveGiftDetails();
- this.setSourceCode(this.giftType);
+ this.applyShowHideRadioCheckboxesState();
+ }
+ getShowHideRadioCheckboxesState() {
+ var _a;
+ try {
+ const plainState = (_a = window.sessionStorage.getItem(`engrid_ShowHideRadioCheckboxesState`)) !== null && _a !== void 0 ? _a : "";
+ return JSON.parse(plainState);
+ } catch (err) {
+ return [];
}
}
- shouldRun() {
- return !!this.ihmoCheckbox;
+ applyShowHideRadioCheckboxesState() {
+ const state = this.getShowHideRadioCheckboxesState();
+ if (state) {
+ state.forEach(item => {
+ this.logger.log("Processing TY page conditional content item:", item);
+ if (dist_engrid_ENGrid.getPageID() === item.page) {
+ document.querySelectorAll(`[class*="${item.class}"]`).forEach(el => {
+ el.classList.add("hide");
+ });
+ document.querySelectorAll(`.${item.class}${item.value}`).forEach(el => {
+ el.classList.remove("hide");
+ });
+ }
+ });
+ }
+ this.deleteShowHideRadioCheckboxesState();
}
- onThankYouPage() {
- return sessionStorage.getItem("engrid_ihmo-gift-details") !== null && engrid_ENGrid.getPageNumber() === 2;
+ deleteShowHideRadioCheckboxesState() {
+ window.sessionStorage.removeItem(`engrid_ShowHideRadioCheckboxesState`);
}
- createPageLayout() {
- const ihmoWrapper = document.createElement("div");
- ihmoWrapper.classList.add("engrid--ihmo-wrapper", "ihmo-closed");
+ shouldRun() {
+ return dist_engrid_ENGrid.getGiftProcess();
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/checkbox-label.js
+// Component to allow the user to set custom labels for the checkboxes,
+// you can customize the checkbox label on a per-page basis, which is not possible with Engaging Networks
+// The .checkbox-label element should be placed right before the checkbox form block
- // Add all elements with the class "ihmo-content" to the IHMO content wrapper
- const ihmoContent = document.querySelectorAll(".ihmo-content");
- ihmoContent.forEach(content => {
- ihmoWrapper.appendChild(content);
+class checkbox_label_CheckboxLabel {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("CheckboxLabel", "#00CC95", "#2C3E50", "β
");
+ this.checkBoxesLabels = document.querySelectorAll(".checkbox-label");
+ if (!this.shoudRun()) return;
+ this.logger.log(`Found ${this.checkBoxesLabels.length} custom labels`);
+ this.run();
+ }
+ shoudRun() {
+ return this.checkBoxesLabels.length > 0;
+ }
+ run() {
+ this.checkBoxesLabels.forEach(checkboxLabel => {
+ const labelHTML = checkboxLabel.innerHTML.trim();
+ const checkboxContainer = checkboxLabel.nextElementSibling;
+ const checkboxLabelElement = checkboxContainer.querySelector("label:last-child");
+ if (!checkboxLabelElement || !labelHTML) return;
+ checkboxLabelElement.innerHTML = `
${labelHTML}
`;
+ // Remove the original label element
+ checkboxLabel.remove();
+ this.logger.log(`Set checkbox label to "${labelHTML}"`);
});
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/optin-ladder.js
+/**
+ * Docs: https://engrid.4sitestudios.com/component/optin-ladder
+ * This component is responsible for showing a ladder of checkboxes, one at a time, to the user.
+ * If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit.
+ * If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match.
+ * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps.
+ * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page.
+ */
- // Insert the IHMO content wrapper after the IHMO checkbox
- this.ihmoCheckbox?.closest(".en__component--formblock")?.insertAdjacentElement("afterend", ihmoWrapper);
-
- // If the page includes the embedded ecard component, move it to the IHMO content wrapper
- const embeddedEcard = document.querySelector(".engrid--embedded-ecard");
- if (embeddedEcard) {
- embeddedEcard.classList.add("ihmo-content");
- const ecardAnchor = document.querySelector(".en__field--select-notification-option")?.closest(".en__component--formblock");
- if (ecardAnchor) {
- ecardAnchor.insertAdjacentElement("afterend", embeddedEcard);
+class optin_ladder_OptInLadder {
+ constructor() {
+ this.logger = new EngridLogger("OptInLadder", "lightgreen", "darkgreen", "β");
+ this._form = EnForm.getInstance();
+ if (!this.inIframe()) {
+ this.runAsParent();
+ } else if (ENGrid.getPageNumber() === 1) {
+ this.runAsChildRegular();
+ } else {
+ this.runAsChildThankYou();
+ }
+ }
+ runAsParent() {
+ this.logger.log("Running as Parent");
+ if (ENGrid.getPageNumber() > 1 && ENGrid.getPageNumber() === ENGrid.getPageCount()) {
+ // We are on the Thank You Page as a Parent
+ // Check autoinject iFrame
+ const optInLadderOptions = ENGrid.getOption("OptInLadder");
+ if (!optInLadderOptions || !optInLadderOptions.iframeUrl) {
+ this.logger.log("Options not found");
+ return;
}
- const ecardIframe = embeddedEcard.querySelector("iframe");
- if (ecardIframe) {
- // Extra URL param on eCard does additional functionality for IHMO page.
- ecardIframe.setAttribute("src", ecardIframe.src + "&data-engrid-embedded-ihmo=true");
+ // Create an iFrame
+ const iframe = document.createElement("iframe");
+ iframe.src = optInLadderOptions.iframeUrl;
+ iframe.style.width = "100%";
+ iframe.style.height = "0";
+ iframe.scrolling = "no";
+ iframe.frameBorder = "0";
+ iframe.allowFullscreen = true;
+ iframe.allow = "payment";
+ iframe.classList.add("opt-in-ladder-iframe");
+ iframe.classList.add("engrid-iframe");
+ iframe.setAttribute("title", "Optin Ladder iframe");
+ // If the page already has an iFrame with the same class, we don't need to add another one
+ const existingIframe = document.querySelector(".opt-in-ladder-iframe");
+ if (existingIframe) {
+ this.logger.log("iFrame already exists");
+ return;
+ }
+ // Check if the current page is part of the excludePageIDs
+ if (optInLadderOptions.excludePageIDs && optInLadderOptions.excludePageIDs.includes(ENGrid.getPageID())) {
+ this.logger.log("Current page is excluded");
+ return;
+ }
+ // Append the iFrame to the proper placement
+ const placementQuerySelector = optInLadderOptions.placementQuerySelector || ".body-top";
+ const placement = document.querySelector(placementQuerySelector);
+ if (!placement) {
+ this.logger.error("Placement not found");
+ return;
+ }
+ placement.appendChild(iframe);
+ } else {
+ // Grab all the checkboxes with the name starting with "supporter.questions"
+ const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
+ if (checkboxes.length === 0) {
+ this.logger.log("No checkboxes found");
+ return;
+ }
+ this._form.onSubmit.subscribe(() => {
+ // Save the checkbox values to sessionStorage
+ this.saveOptInsToSessionStorage("parent");
+ });
+ if (ENGrid.getPageNumber() === 1) {
+ // Delete items from sessionStorage
+ this.clearSessionStorage();
}
}
- engrid_ENGrid.setBodyData("ihmo", "true");
}
- addEventListeners() {
- // When "This gift is in honor or memory of someone" checkbox is changed
- this.ihmoCheckbox?.addEventListener("change", e => {
- const checkbox = e.target;
- if (checkbox.checked) {
- document.querySelector(".engrid--ihmo-wrapper")?.classList.remove("ihmo-closed");
- this.configureForm(this.giftType, this.giftNotification);
- this.saveGiftDetails();
- this.setSourceCode(this.giftType);
+ runAsChildRegular() {
+ if (!this.isEmbeddedThankYouPage()) {
+ this.logger.log("Not Embedded on a Thank You Page");
+ return;
+ }
+ const optInHeaders = document.querySelectorAll(".en__component--copyblock.optin-ladder");
+ const optInFormBlocks = document.querySelectorAll(".en__component--formblock.optin-ladder");
+ if (optInHeaders.length === 0 && optInFormBlocks.length === 0) {
+ this.logger.log("No optin-ladder elements found");
+ return;
+ }
+ // Check if the e-mail field exist and is not empty
+ const emailField = ENGrid.getField("supporter.emailAddress");
+ if (!emailField || !emailField.value) {
+ this.logger.log("Email field is empty");
+ // Since this is a OptInLadder page with no e-mail address, hide the page
+ this.hidePage(true);
+ return;
+ }
+ const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
+ let currentStep = 0;
+ let totalSteps = optInHeaders.length;
+ let currentHeader = null;
+ let currentFormBlock = null;
+ for (let i = 0; i < optInHeaders.length; i++) {
+ const header = optInHeaders[i];
+ // Get the optin number from the .optin-ladder-XXXX class
+ const optInNumber = header.className.match(/optin-ladder-(\d+)/);
+ if (!optInNumber) {
+ this.logger.error(`No optin number found in ${header.innerText.trim()}`);
+ return;
+ }
+ const optInIndex = optInNumber[1];
+ // Get the checkbox FormBlock
+ const formBlock = document.querySelector(`.en__component--formblock.optin-ladder:has(.en__field--${optInIndex})`);
+ if (!formBlock) {
+ this.logger.log(`No form block found for ${header.innerText.trim()}`);
+ // Remove the header if there is no form block
+ header.remove();
+ // Increment the current step
+ currentStep++;
+ continue;
+ }
+ // Check if the optInIndex is in sessionStorage
+ if (sessionStorageCheckboxValues[optInIndex] === "Y") {
+ // If the checkbox is checked, remove the header and form block
+ header.remove();
+ formBlock.remove();
+ // Increment the current step
+ currentStep++;
+ continue;
+ }
+ // If there's a header and a form block, end the loop
+ currentHeader = header;
+ currentFormBlock = formBlock;
+ currentStep++;
+ break;
+ }
+ if (!currentHeader || !currentFormBlock) {
+ this.logger.log("No optin-ladder elements found");
+ // Set the current step to the total steps to avoid redirecting to the first page
+ currentStep = totalSteps;
+ this.saveStepToSessionStorage(currentStep, totalSteps);
+ // hide the page
+ this.hidePage();
+ return;
+ }
+ // Show the current header and form block, while removing the rest
+ optInHeaders.forEach(header => {
+ if (header !== currentHeader) {
+ header.remove();
} else {
- document.querySelector(".engrid--ihmo-wrapper")?.classList.add("ihmo-closed");
- this.displayEcard(false);
- this.hideAllFields();
- this.clearGiftDetails();
- this.setSourceCode(false);
+ header.style.display = "block";
}
});
-
- // When the "Gift Type" radio button is changed
- document.getElementsByName("transaction.trbopts").forEach(el => {
- el.addEventListener("change", e => {
- const radio = e.target;
- const giftType = radio.value === "In Honor" ? "HONORARY" : "MEMORIAL";
- this.configureForm(giftType, this.giftNotification);
- this.saveGiftDetails();
- this.setSourceCode(giftType);
- });
- });
-
- // When the "Select Notification option" radio button is changed
- document.getElementsByName("supporter.questions.1381061").forEach(el => {
- el.addEventListener("change", e => {
- const radio = e.target;
- let giftNotification;
- if (radio.value === "Send an ecard") {
- giftNotification = "ECARD";
- } else if (radio.value === "Notify by mail") {
- giftNotification = "MAIL";
- } else {
- giftNotification = "NONE";
- }
- this.configureForm(this.giftType, giftNotification);
- this.saveGiftDetails();
- });
+ optInFormBlocks.forEach(formBlock => {
+ if (formBlock !== currentFormBlock) {
+ formBlock.remove();
+ } else {
+ formBlock.style.display = "block";
+ }
});
- const firstNameField = document.getElementById("en__field_transaction_infname");
- const lastNameField = document.getElementById("en__field_transaction_othamt3");
- const emailField = document.getElementById("en__field_transaction_infemail");
- const honorFirstNameField = document.getElementById("en__field_transaction_honname");
- const honorLastNameField = document.getElementById("en__field_transaction_othamt2");
- const ecardIframe = document.querySelector(".engrid-iframe--embedded-ecard");
-
- // Setting the recipient name and email in the ecard iframe
- [firstNameField, lastNameField, emailField, honorFirstNameField, honorLastNameField].forEach(field => {
- field.addEventListener("input", () => {
- const fullName = this.giftType === "HONORARY" ? `${honorFirstNameField.value} ${honorLastNameField.value}` : `${firstNameField.value} ${lastNameField.value}`;
- ecardIframe.contentWindow?.postMessage({
- action: "set_recipient",
- name: fullName,
- email: emailField.value
- }, location.origin);
- });
+ // Save the current step to sessionStorage
+ this.saveStepToSessionStorage(currentStep, totalSteps);
+ // On form submit, save the checkbox values to sessionStorage
+ this._form.onSubmit.subscribe(() => {
+ this.saveOptInsToSessionStorage("child");
+ // Save the current step to sessionStorage
+ currentStep++;
+ this.saveStepToSessionStorage(currentStep, totalSteps);
});
-
- //Hiding the IHMO section when monthly donation is selected
- // Listen for changes to the donation frequency and amount
- this._donationFrequency.onFrequencyChange.subscribe(frequency => {
- if (frequency !== "onetime") {
- // Hide the IHMO section, hide the fields to prevent validation errors
- // Disable ecard to prevent it being sent
- document.querySelectorAll(".ihmo-element").forEach(el => {
- el.classList.add("hide");
- });
- document.querySelector(".engrid--ihmo-wrapper")?.classList.add("ihmo-closed");
- this.displayEcard(false);
- this.hideAllFields();
- this.hideField(".en__field--inmem");
+ }
+ runAsChildThankYou() {
+ if (!this.isEmbeddedThankYouPage()) {
+ this.logger.log("Not Embedded on a Thank You Page");
+ return;
+ }
+ const hasOptInLadderStop = sessionStorage.getItem("engrid.optin-ladder-stop");
+ const hasOptInLadderPersistStop = sessionStorage.getItem("engrid.optin-ladder-persist-stop");
+ if (hasOptInLadderPersistStop) {
+ this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page");
+ sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
+ return;
+ }
+ if (hasOptInLadderStop) {
+ this.logger.log("OptInLadder has been stopped");
+ return;
+ }
+ const sessionStorageOptInLadder = JSON.parse(sessionStorage.getItem("engrid.optin-ladder") || "{}");
+ const currentStep = sessionStorageOptInLadder.step || 0;
+ const totalSteps = sessionStorageOptInLadder.totalSteps || 0;
+ if (totalSteps === 0) {
+ this.logger.log("No total steps found in sessionStorage");
+ this.hidePage();
+ return;
+ } else if (currentStep <= totalSteps) {
+ this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`);
+ this.hidePage(true);
+ // Redirect to the first page
+ window.location.href = this.getFirstPageUrl();
+ return;
+ } else {
+ this.logger.log(`Current step ${currentStep} is greater than total steps ${totalSteps}`);
+ // Remove the session storage
+ this.clearSessionStorage();
+ }
+ }
+ inIframe() {
+ try {
+ return window.self !== window.top;
+ } catch (e) {
+ return true;
+ }
+ }
+ saveStepToSessionStorage(step, totalSteps) {
+ sessionStorage.setItem("engrid.optin-ladder", JSON.stringify({
+ step,
+ totalSteps
+ }));
+ this.logger.log(`Saved step ${step} of ${totalSteps} to sessionStorage`);
+ }
+ saveOptInsToSessionStorage(type = "parent") {
+ // Grab all the checkboxes with the name starting with "supporter.questions"
+ const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
+ if (checkboxes.length === 0) {
+ this.logger.log("No checkboxes found");
+ return;
+ }
+ const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
+ let hasDeny = false;
+ // Loop through all the checkboxes and store the value in sessionStorage
+ checkboxes.forEach(checkbox => {
+ if (checkbox.checked) {
+ const index = checkbox.name.split(".")[2];
+ sessionStorageCheckboxValues[index] = "Y";
} else {
- // Make IHMO elements visible
- document.querySelectorAll(".ihmo-element").forEach(el => {
- el.classList.remove("hide");
- });
- this.showField(".en__field--inmem");
- if (this.ihmoCheckbox?.checked) {
- // Don't call "configureForm" unless the IHMO checkbox is checked, otherwise we might get validation errors
- this.configureForm(this.giftType, this.giftNotification);
- document.querySelector(".engrid--ihmo-wrapper")?.classList.remove("ihmo-closed");
- }
+ hasDeny = true;
}
});
-
- // When gift designation changes, update the source code
- if (this.sourceCodeField?.tagName === "SELECT") {
- this.sourceCodeField?.addEventListener("change", () => {
- const sourceCodeType = this.ihmoCheckbox?.checked ? this.giftType : false;
- this.setSourceCode(sourceCodeType);
- });
+ sessionStorage.setItem("engrid.supporter.questions", JSON.stringify(sessionStorageCheckboxValues));
+ this.logger.log(`Saved checkbox values to sessionStorage: ${JSON.stringify(sessionStorageCheckboxValues)}`);
+ if (type === "child" && hasDeny) {
+ // Add a deny value to the sessionStorage to stop the ladder
+ sessionStorage.setItem("engrid.optin-ladder-stop", "Y");
+ }
+ }
+ isEmbeddedThankYouPage() {
+ return ENGrid.getBodyData("embedded") === "thank-you-page-donation";
+ }
+ getPageUrl(page, chain = false) {
+ const url = new URL(window.location.href);
+ const path = url.pathname.split("/");
+ path[path.length - 1] = String(page);
+ return url.origin + path.join("/") + (chain ? "?chain" : "");
+ }
+ getFirstPageUrl() {
+ return this.getPageUrl(1, true);
+ }
+ hidePage(forceHide = false) {
+ if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) {
+ this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page");
+ sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y");
+ window.location.href = this.getPageUrl(2);
+ } else {
+ const engridPage = document.querySelector("#engrid");
+ if (engridPage) {
+ engridPage.classList.add("hide");
+ }
}
}
- configureForm(giftType, notificationType) {
- this.giftType = giftType;
- this.giftNotification = notificationType;
- this.setFormLayout();
- this.setFormHeadings();
- this.setFieldLabels();
- this.displayEcard(this.giftNotification === "ECARD" && this.ihmoCheckbox?.checked);
+ clearSessionStorage() {
+ sessionStorage.removeItem("engrid.supporter.questions");
+ sessionStorage.removeItem("engrid.optin-ladder");
+ sessionStorage.removeItem("engrid.optin-ladder-stop");
+ sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/post-donation-embed.js
+// This component only works on Thank You pages and the current page IS NOT embedded as an iframe.
+// It searches for a post-donation tag (engrid-post-donation)
+// and if it exists, it will replace it with an iframe of the chained `src` attribute (or the current donation page, replacing the
+// "/donate/2" with "/donate/1").
+// The engrid-post-donation tag has 3 attributes:
+// 1. src: the URL of the iframe to load (optional)
+// 2. params: the URL parameters to pass to the iframe
+// 3. amounts: comma separated list of amounts to pass to the iframe
+
+class post_donation_embed_PostDonationEmbed {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("PostDonationEmbed", "red", "white", "πΌοΈ");
+ if (!this.shouldRun()) return;
+ this.logger.log("Post Donation Tag found");
+ const postDonationTag = document.querySelector("engrid-post-donation");
+ // Get `src` attribute from the
tag if it exists
+ // If not, use the current page URL as the base URL
+ let iFrameSRC;
+ if (!postDonationTag.getAttribute("src")) {
+ iFrameSRC = new URL(window.location.href);
+ // Modify the path: replace "/donate/2" with "/donate/1"
+ iFrameSRC.pathname = iFrameSRC.pathname.replace("/donate/2", "/donate/1");
+ } else {
+ iFrameSRC = new URL(postDonationTag.getAttribute("src") || "");
+ }
+ // Extract parameters from the tag
+ let params = postDonationTag.getAttribute("params") || "";
+ let amounts = postDonationTag.getAttribute("amounts");
+ // Format parameters correctly
+ let searchParams = new URLSearchParams(params.replace(/&/g, "&"));
+ let paramString = searchParams.toString().replace(/%5B/g, "[").replace(/%5D/g, "]");
+ // Construct new URL with "chain" parameter
+ let newUrl = `${iFrameSRC.origin}${iFrameSRC.pathname}?chain&${paramString}`;
+ if (amounts) {
+ newUrl += `&engrid-amounts=${amounts}`;
+ }
+ // Create the iframe element
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("loading", "lazy");
+ iframe.setAttribute("width", "100%");
+ iframe.setAttribute("scrolling", "no");
+ iframe.setAttribute("class", "engrid-iframe thank-you-page-donation");
+ iframe.setAttribute("src", newUrl);
+ iframe.setAttribute("frameborder", "0");
+ iframe.setAttribute("allowfullscreen", "");
+ iframe.setAttribute("allowpaymentrequest", "true");
+ iframe.setAttribute("allow", "payment");
+ iframe.setAttribute("title", "Post Donation iframe");
+ // Replace with the iframe
+ postDonationTag.replaceWith(iframe);
}
- saveGiftDetails() {
- const giftDetails = {
- giftType: this.giftType,
- giftNotification: this.giftNotification
- };
- sessionStorage.setItem("engrid_ihmo-gift-details", JSON.stringify(giftDetails));
- this.setGiftDetailsAsDataAttributes();
+ shouldRun() {
+ return dist_engrid_ENGrid.isThankYouPage() && this.hasPostDonationTag() && dist_engrid_ENGrid.getBodyData("embedded") === null;
}
- clearGiftDetails() {
- sessionStorage.removeItem("engrid_ihmo-gift-details");
- this.setGiftDetailsAsDataAttributes();
+ hasPostDonationTag() {
+ return !!document.querySelector("engrid-post-donation");
}
- setGiftDetailsAsDataAttributes() {
- const giftDetails = sessionStorage.getItem("engrid_ihmo-gift-details");
- if (!giftDetails) {
- engrid_ENGrid.setBodyData("ihmo-gift-type", false);
- engrid_ENGrid.setBodyData("ihmo-gift-notification", false);
- return;
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/frequency-upsell-modal.js
+/*
+ * FrequencyUpsellModal - this is class that creates the modal for the frequency upsell.
+ * This component is intentionally "dumb" and only creates the modal renders its content.
+ * Logic for showing the modal and handling the upsell is in the FrequencyUpsell class.
+ */
+
+class frequency_upsell_modal_FrequencyUpsellModal extends modal_Modal {
+ constructor(upsellOptions) {
+ super({
+ onClickOutside: "bounce",
+ customClass: `engrid--frequency-upsell-modal ${upsellOptions.customClass}`,
+ showCloseX: false
+ });
+ this._amountWithFees = 0;
+ this._upsellAmountWithFees = 0;
+ this.upsellOptions = upsellOptions;
+ this.updateModalContent();
+ }
+ set amountWithFees(value) {
+ this._amountWithFees = value;
+ }
+ set upsellAmountWithFees(value) {
+ this._upsellAmountWithFees = value;
+ }
+ updateModalContent() {
+ var _a;
+ this.modalContent = this.getModalContent();
+ const modalBody = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector(".engrid-modal__body");
+ if (modalBody) {
+ modalBody.innerHTML = "";
+ modalBody.insertAdjacentHTML("beforeend", this.modalContent);
}
- const {
- giftType,
- giftNotification
- } = JSON.parse(giftDetails);
- engrid_ENGrid.setBodyData("ihmo-gift-type", giftType);
- engrid_ENGrid.setBodyData("ihmo-gift-notification", giftNotification);
}
- setSourceCode(giftType) {
- if (!this.sourceCodeField) return;
+ getModalContent() {
+ if (!this.upsellOptions) return "";
+ return `
+
+
+
+
${this.replaceAmountTokens(this.upsellOptions.title)}
+
${this.replaceAmountTokens(this.upsellOptions.paragraph)}
+
+
+
+ ${this.replaceAmountTokens(this.upsellOptions.yesButton)}
+
+
+ ${this.replaceAmountTokens(this.upsellOptions.noButton)}
+
+
+
+ `;
+ }
+ replaceAmountTokens(string) {
+ const amount = dist_engrid_ENGrid.formatNumber(this._amountWithFees, this._amountWithFees % 1 == 0 ? 0 : 2, ".", "");
+ const upsellAmount = dist_engrid_ENGrid.formatNumber(this._upsellAmountWithFees, this._upsellAmountWithFees % 1 == 0 ? 0 : 2, ".", "");
+ return string.replace(/{current_amount}/g, amount).replace(/{upsell_amount}/g, upsellAmount);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/frequency-upsell.js
+/*
+ * FrequencyUpsell component which creates a modal to upsell the frequency of the donation
+ * This is typically used to upsell a single donation into an annual donation, but the component
+ * options can be configured to upsell any frequency to any other frequency. The upsell amount can also be configured
+ * See FrequencyUpsellOptions for more details.
+ */
- // If source code overriding is disabled, return early
- if (window.EngridDisableIhmoSourceCodeOverriding && window.EngridDisableIhmoSourceCodeOverriding === true) {
- return;
- }
- const sourceCodeContainer = this.sourceCodeField instanceof HTMLSelectElement ? this.sourceCodeField.options[this.sourceCodeField.selectedIndex] : this.sourceCodeField;
- if (sourceCodeContainer.value === "AHOMAONLN21W0XXX01" && this.sourceCodeField instanceof HTMLSelectElement) {
- // if "use my gift where it's needed most" option is selected, do not change the source code"
+
+class frequency_upsell_FrequencyUpsell {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("FrequencyUpsell", "lightgray", "darkblue", "π¦");
+ this.upsellModal = null;
+ this.options = null;
+ this._frequency = donation_frequency_DonationFrequency.getInstance();
+ this._amount = donation_amount_DonationAmount.getInstance();
+ this._fee = processing_fees_ProcessingFees.getInstance();
+ this._form = events_en_form_EnForm.getInstance();
+ this.modalSeen = false;
+ if (!this.shouldRun()) {
+ this.logger.log("FrequencyUpsell not running");
return;
}
-
- // Determine the part of the source code to replace and the replacement value
- const isUS = this.isUSState(sourceCodeContainer.value);
- const endIndex = sourceCodeContainer.value.length;
- let target, replacement;
- if (giftType === "HONORARY" || giftType === "MEMORIAL") {
- if (isUS) {
- target = sourceCodeContainer.value.substring(endIndex - 6);
- replacement = giftType === "HONORARY" ? "TRIHXX" : "TRIMXX";
+ this.options = this.selectOptions(window.EngridFrequencyUpsell);
+ this.logger.log("FrequencyUpsell initialized", this.options);
+ this.upsellModal = new frequency_upsell_modal_FrequencyUpsellModal(this.options);
+ this.createFrequencyField();
+ this.addEventListeners();
+ }
+ /**
+ * Select the proper options (single config or A/B variant) and return a concrete FrequencyUpsellOptions object.
+ * If an A/B test config is provided (abTest: true, options: [...]) a random variant is chosen and stored
+ * in a 1-day cookie so subsequent visits get the same variant.
+ */
+ selectOptions(config) {
+ // Simple (non AB) case
+ if (!config.abTest) {
+ return Object.assign(Object.assign({}, frequency_upsell_options_FrequencyUpsellOptionsDefaults), config);
+ }
+ const abConfig = config;
+ const cookieName = abConfig.cookieName || "engrid_frequency_upsell_variant";
+ const existing = cookie_get(cookieName);
+ let index;
+ if (existing !== undefined) {
+ const parsed = parseInt(existing, 10);
+ if (!isNaN(parsed) && parsed >= 0 && parsed < abConfig.options.length) {
+ index = parsed;
} else {
- target = sourceCodeContainer.value.substring(endIndex - 6, endIndex - 2);
- replacement = giftType === "HONORARY" ? "TRIH" : "TRIM";
+ index = this.randomIndex(abConfig.options.length);
}
- sourceCodeContainer.value = sourceCodeContainer.value.replace(target, replacement);
} else {
- // Reset to default if not honorary or memorial
- sourceCodeContainer.value = sourceCodeContainer.getAttribute("data-default-source-code") || "";
+ index = this.randomIndex(abConfig.options.length);
}
- engrid_ENGrid.setBodyData("source-code", this.sourceCodeField.value);
+ // Persist for configured duration
+ const duration = abConfig.cookieDurationDays || 1;
+ cookie_set(cookieName, index.toString(), {
+ expires: duration
+ });
+ const chosen = abConfig.options[index];
+ // Push variant info to dataLayer if available
+ if (window.dataLayer) {
+ window.dataLayer.push({
+ event: "frequency_upsell_ab_variant",
+ frequencyUpsellVariantIndex: index,
+ frequencyUpsellVariantTitle: chosen.title
+ });
+ }
+ return Object.assign(Object.assign({}, frequency_upsell_options_FrequencyUpsellOptionsDefaults), chosen);
}
- setFormLayout() {
- const formLayout = this.formLayouts[this.giftType][this.giftNotification];
- // Add fields to the top form section
- formLayout.topFields.forEach(field => {
- const el = document.querySelector(field);
- if (el) {
- this.topForm?.appendChild(el);
- this.showField(el);
+ randomIndex(length) {
+ return Math.floor(Math.random() * length);
+ }
+ /**
+ * Check if the FrequencyUpsell should run:
+ * - Check if the FrequencyUpsell is enabled in the window object
+ * - Check that we don't have an EngridUpsell active on this page
+ * - Check that we don't have an EngagingNetworks upsell active on this page
+ * @returns {boolean} - true if the FrequencyUpsell should run, false otherwise
+ */
+ shouldRun() {
+ return window.EngridFrequencyUpsell && !window.EngridUpsell && (!window.EngagingNetworks.upsell || window.EngagingNetworks.upsell.length === 0);
+ }
+ /**
+ * Get the upsell amount with/without fees
+ * We want to display to the user the amount with fees, but we need to set the donation amount to the value without fees
+ * @param {boolean} withFee - true if we want to include the fees in the upsell amount
+ * @returns {number} - The upsell amount with fees
+ */
+ getUpsellAmount(withFee) {
+ if (withFee) {
+ const upsellAmount = this.options.upsellAmount(this._amount.amount);
+ return upsellAmount + this._fee.calculateFees(upsellAmount);
+ }
+ return this.options.upsellAmount(this._amount.amount);
+ }
+ addEventListeners() {
+ var _a, _b;
+ // When the Modal buttons are clicked
+ (_b = (_a = this.upsellModal) === null || _a === void 0 ? void 0 : _a.modal) === null || _b === void 0 ? void 0 : _b.addEventListener("click", e => {
+ const target = e.target;
+ // Upsell is accepted
+ if (target.id === "frequency-upsell-yes") {
+ this.logger.log("Frequency upsell accepted");
+ this._frequency.setFrequency(this.options.upsellFrequency);
+ this._amount.setAmount(this.getUpsellAmount(false));
+ this.options.onAccept();
+ this._form.submitForm();
+ this.upsellModal.close();
+ return;
}
- });
-
- // Add fields to the bottom form section
- formLayout.bottomFields.forEach(field => {
- const el = document.querySelector(field);
- if (el) {
- this.bottomForm?.appendChild(el);
- this.showField(el);
+ // Upsell is declined
+ if (target.id === "frequency-upsell-no") {
+ this.logger.log("Frequency upsell declined");
+ this.options.onDecline();
+ this._form.submitForm();
+ this.upsellModal.close();
+ return;
}
});
-
- // Hide unused fields in the top form section
- const topFormFields = this.topForm?.children || [];
- [...topFormFields].forEach(el => {
- const classList = Array.from(el.classList);
- const isActiveField = formLayout.topFields.some(field => classList.includes(field.slice(1)));
- if (!isActiveField) {
- this.hideField(el);
+ // When the form is submitted
+ this._form.onSubmit.subscribe(() => {
+ var _a;
+ // If we have a frequency we want to upsell on & the modal isn't already open
+ // Since frequency in the event class doesn't have a specific type, I need to cast our options array to a general string array
+ if (this.options.upsellFromFrequency.includes(this._frequency.frequency) && !this.modalSeen) {
+ // Open the modal and prevent form submission
+ this.upsellModal.amountWithFees = this._amount.amount + this._fee.calculateFees(this._amount.amount);
+ this.upsellModal.upsellAmountWithFees = this.getUpsellAmount(true);
+ this.upsellModal.updateModalContent();
+ this.logger.log("Frequency upsell modal opened");
+ (_a = this.upsellModal) === null || _a === void 0 ? void 0 : _a.open();
+ this.options.onOpen();
+ this.modalSeen = true;
+ this._form.submit = false;
+ return false;
}
+ // If not opening, continue with the form submission
+ this._form.submit = true;
+ return true;
});
+ }
+ /**
+ * Create the frequency field for the upsell, if it does not exist on the page already
+ * This is required by DonationFrequency to set the frequency
+ */
+ createFrequencyField() {
+ const frequencyField = document.querySelector(`input[name="transaction.recurrfreq"][value="${this.options.upsellFrequency.toUpperCase()}"]`);
+ if (frequencyField) return;
+ const frequencyFieldContainer = document.querySelector(".en__field--recurrfreq .en__field__element");
+ frequencyFieldContainer === null || frequencyFieldContainer === void 0 ? void 0 : frequencyFieldContainer.insertAdjacentHTML("beforeend", `
+
+
+
+ `);
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/sticky-nsg.js
- // Hide unused fields in the bottom form section
- const bottomFormFields = this.bottomForm?.children || [];
- [...bottomFormFields].forEach(el => {
- const classList = Array.from(el.classList);
- const isActiveField = formLayout.bottomFields.some(field => classList.includes(field.slice(1)));
- if (!isActiveField) {
- this.hideField(el);
- }
+
+
+class sticky_nsg_StickyNSG {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("StickyNSG", "teal", "white", "π");
+ this.cookieName = "engrid-sticky-nsg";
+ if (!this.shouldRun()) return;
+ this.logger.log("Sticky NSG is enabled");
+ this.deleteCookieIfGiftProcessComplete();
+ this.createStickyNSGCookie();
+ this.applyStickyNSGCookie();
+ }
+ shouldRun() {
+ return dist_engrid_ENGrid.getOption("StickyNSG") === true;
+ }
+ /*
+ * Determine if NSG provided by EN is active on the page
+ */
+ nsgActiveOnPage() {
+ return window.EngagingNetworks && window.EngagingNetworks.suggestedGift && typeof window.EngagingNetworks.suggestedGift === "object" && Object.keys(window.EngagingNetworks.suggestedGift).length > 0;
+ }
+ /*
+ * Delete the cookie if the gift process is complete
+ */
+ deleteCookieIfGiftProcessComplete() {
+ if (dist_engrid_ENGrid.getGiftProcess()) {
+ this.logger.log("Gift process complete, removing sticky NSG cookie if it exists");
+ cookie_remove(this.cookieName);
+ }
+ }
+ /*
+ * Create the sticky NSG cookie if NSG is active on the page
+ */
+ createStickyNSGCookie() {
+ var _a, _b, _c, _d, _e, _f;
+ if (!this.nsgActiveOnPage()) {
+ this.logger.log("No NSG active on page, not creating sticky NSG cookie");
+ return;
+ }
+ const url = new URL(window.location.href);
+ if (url.searchParams.get("skipstickynsg") === "true") {
+ this.logger.log("'skipstickynsg' param present, not creating sticky NSG cookie");
+ return;
+ }
+ // We do some reformating to match the EngridAmounts format
+ // We also add "Other" to the amounts list
+ const nsg = window.EngagingNetworks.suggestedGift;
+ this.logger.log("Creating sticky NSG cookie", nsg);
+ const oneTimeNsg = (_a = nsg.single) === null || _a === void 0 ? void 0 : _a.reduce((acc, curr) => {
+ acc[curr.value] = curr.value;
+ return acc;
+ }, {});
+ const oneTimeDefault = (_c = (_b = nsg.single) === null || _b === void 0 ? void 0 : _b.find(gift => gift.nextSuggestedGift)) === null || _c === void 0 ? void 0 : _c.value;
+ const recurringNsg = (_d = nsg.recurring) === null || _d === void 0 ? void 0 : _d.reduce((acc, curr) => {
+ acc[curr.value] = curr.value;
+ return acc;
+ }, {});
+ const recurringDefault = (_f = (_e = nsg.recurring) === null || _e === void 0 ? void 0 : _e.find(gift => gift.nextSuggestedGift)) === null || _f === void 0 ? void 0 : _f.value;
+ const nsgCookieData = {};
+ if (oneTimeNsg && oneTimeDefault) {
+ nsgCookieData.onetime = {
+ amounts: oneTimeNsg,
+ default: oneTimeDefault,
+ stickyDefault: false
+ };
+ }
+ if (recurringNsg && recurringDefault) {
+ nsgCookieData.monthly = {
+ amounts: recurringNsg,
+ default: recurringDefault,
+ stickyDefault: false
+ };
+ }
+ if (Object.keys(nsgCookieData).length === 0) {
+ this.logger.log("No valid NSG data found to create sticky NSG cookie");
+ return;
+ }
+ const cookieValue = JSON.stringify(nsgCookieData);
+ cookie_set(this.cookieName, cookieValue, {
+ path: "/",
+ expires: 30
});
+ this.logger.log("Sticky NSG cookie created", cookieValue);
}
- setFormHeadings() {
- const headings = document.querySelectorAll(".form-heading.ihmo-content h3");
- if (headings.length === 0) return;
- const firstHeading = headings[0];
- const lastHeading = headings[headings.length - 1];
- if (!firstHeading || !lastHeading) return;
- if (this.giftType === "HONORARY") {
- firstHeading.textContent = "PERSON TO BE HONORED";
- lastHeading.textContent = "HONOREE'S PERSONAL INFORMATION";
- if (this.giftNotification === "ECARD" || this.giftNotification === "NONE") {
- lastHeading.closest(".form-heading")?.classList.add("hide");
- } else {
- lastHeading.closest(".form-heading")?.classList.remove("hide");
+ /*
+ * Apply the sticky NSG cookie values to window.EngridAmounts if NSG is not active on the page
+ */
+ applyStickyNSGCookie() {
+ if (this.nsgActiveOnPage()) {
+ this.logger.log("NSG active on page, not applying sticky NSG cookie, leaving the EN NSG values.");
+ return;
+ }
+ const cookieValue = cookie_get(this.cookieName);
+ if (!cookieValue) {
+ this.logger.log("No sticky NSG cookie found, nothing to apply");
+ return;
+ }
+ try {
+ const nsg = JSON.parse(cookieValue);
+ this.logger.log("Applying sticky NSG cookie values", nsg);
+ window.EngridAmounts = nsg;
+ } catch (e) {
+ this.logger.error("Error parsing sticky NSG cookie, not applying", e);
+ }
+ }
+}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/sticky-prepopulation.js
+var dist_sticky_prepopulation_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function (resolve) {
+ resolve(value);
+ });
+ }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
}
- } else {
- firstHeading.textContent = "PERSON TO BE REMEMBERED";
- lastHeading.textContent = "PERSON TO BE NOTIFIED";
- if (this.giftNotification === "NONE") {
- lastHeading.closest(".form-heading")?.classList.add("hide");
- } else {
- lastHeading.closest(".form-heading")?.classList.remove("hide");
+ }
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
}
}
- }
- setFieldLabels() {
- const firstNameFieldLabel = document.querySelector(".en__field--honname > label");
- const lastNameFieldLabel = document.querySelector(".en__field--othamt2 > label");
- const cityFieldLabel = document.querySelector(".en__field--NOT_TAGGED_36 > label");
- const stateFieldLabel = document.querySelector(".en__field--NOT_TAGGED_35 > label");
- if (!firstNameFieldLabel || !lastNameFieldLabel || !cityFieldLabel || !stateFieldLabel) {
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+
+
+
+class sticky_prepopulation_StickyPrepopulation {
+ constructor() {
+ this.logger = new dist_logger_EngridLogger("StickyPrepopulation", "teal", "white", "π");
+ this.options = {
+ fields: []
+ };
+ this.cookieName = "engrid-sticky-prepop";
+ if (!this.shouldRun()) {
return;
}
- if (this.giftType === "HONORARY") {
- firstNameFieldLabel.textContent = "Honoree First Name";
- lastNameFieldLabel.textContent = "Honoree Last Name";
- cityFieldLabel.textContent = "Honoree City";
- stateFieldLabel.textContent = "Honoree State";
+ this.logger.log("StickyPrepopulation initialized");
+ if (dist_engrid_ENGrid.getGiftProcess()) {
+ this.deleteCookie();
+ return;
+ }
+ if (dist_engrid_ENGrid.getPageNumber() !== 1 || !dist_engrid_ENGrid.getField("supporter.emailAddress")) {
+ this.logger.log("Not on page 1 or email field not present, not creating cookie or applying pre-population.");
+ return;
+ }
+ this.createCookie();
+ this.applyPrepopulation();
+ }
+ /*
+ * Determine if we should run the script
+ * Do not run if RememberMe is active
+ * Do not run if on a chain link
+ * Only run if StickyPrepopulation option is set with fields
+ */
+ shouldRun() {
+ if (dist_engrid_ENGrid.getOption("RememberMe")) {
+ return false;
+ }
+ const url = new URL(window.location.href);
+ const options = dist_engrid_ENGrid.getOption("StickyPrepopulation");
+ if (options && (options === null || options === void 0 ? void 0 : options.fields.length) > 0 && !url.searchParams.has("chain")) {
+ this.options = options;
+ return true;
} else {
- firstNameFieldLabel.textContent = "Deceased Person's First Name";
- lastNameFieldLabel.textContent = "Deceased Person's Last Name";
- cityFieldLabel.textContent = "Deceased Person's City";
- stateFieldLabel.textContent = "Deceased Person's State";
+ return false;
}
}
- displayEcard(show = true) {
- const eCardCheckbox = document.getElementById("en__field_embedded-ecard");
- eCardCheckbox.checked = show;
- eCardCheckbox.dispatchEvent(new Event("change"));
+ /*
+ * Delete the cookie if the gift process is complete
+ */
+ deleteCookie() {
+ this.logger.log("Gift process complete, removing sticky prepopulation cookie if it exists");
+ cookie_remove(this.cookieName);
}
- hideAllFields() {
- [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35", ".en__field--infname", ".en__field--othamt3", ".en__field--infcountry", ".en__field--infadd1", ".en__field--infadd2", ".en__field--infcity", ".en__field--infreg", ".en__field--infpostcd", ".en__field--infemail", ".en__field--NOT_TAGGED_38", ".en__field--NOT_TAGGED_33", ".en__field--NOT_TAGGED_34", ".en__field--NOT_TAGGED_37"].forEach(field => {
- this.hideField(field);
+ /*
+ * Create the cookie if we're coming from a campaign link and supporterId is present
+ */
+ createCookie() {
+ var _a;
+ return dist_sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ // If we're not coming from a campaign link, don't create the cookie
+ if (!((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId)) {
+ this.logger.log("No supporterId present, not creating sticky prepopulation cookie");
+ return;
+ }
+ try {
+ const encryptedSupporterDetails = yield this.encryptSupporterDetails(this.getSupporterDetailsFromFields());
+ cookie_set(this.cookieName, window.btoa(JSON.stringify({
+ encryptedData: encryptedSupporterDetails.encryptedData,
+ iv: encryptedSupporterDetails.iv,
+ pageId: dist_engrid_ENGrid.getPageID()
+ })), {
+ path: "/",
+ expires: 7
+ });
+ } catch (e) {
+ this.logger.log("Error creating sticky prepopulation cookie");
+ return;
+ }
+ this.logger.log("Sticky prepopulation cookie created");
});
}
- hideField(field) {
- const el = field instanceof Element ? field : document.querySelector(field);
- if (el) {
- const identifier = [...el.classList].find(c => c.match(/en__field--\d+/))?.replace("en__field--", "");
- if (identifier) {
- window.EngagingNetworks.require._defined.enjs.hideField(identifier);
+ /*
+ * If the cookie is present and supporterId is not (it's not a campaign link prefilled by EN),
+ * then apply the prepopulation
+ */
+ applyPrepopulation() {
+ var _a;
+ return dist_sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const cookieData = cookie_get(this.cookieName);
+ if (!cookieData) {
+ this.logger.log("No sticky prepopulation cookie found, not prepopulating fields");
+ return;
}
- }
+ if ((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId) {
+ this.logger.log("SupporterId present, not applying sticky prepopulation");
+ return;
+ }
+ let supporterDetails = {};
+ try {
+ const encryptedSupporterDetails = JSON.parse(window.atob(cookieData));
+ if (!encryptedSupporterDetails || (encryptedSupporterDetails === null || encryptedSupporterDetails === void 0 ? void 0 : encryptedSupporterDetails.pageId) !== dist_engrid_ENGrid.getPageID()) {
+ this.logger.log("No encrypted supporter details found in cookie, or page ID does not match");
+ return;
+ }
+ supporterDetails = JSON.parse(yield this.decryptSupporterDetails(this.base64ToArrayBuffer(encryptedSupporterDetails.encryptedData), new Uint8Array(this.base64ToArrayBuffer(encryptedSupporterDetails.iv))));
+ } catch (e) {
+ this.logger.log("Error decrypting supporter details from cookie");
+ return;
+ }
+ this.options.fields.forEach(fieldName => {
+ if (!supporterDetails[fieldName]) return;
+ dist_engrid_ENGrid.setFieldValue(fieldName, decodeURIComponent(supporterDetails[fieldName]));
+ this.logger.log(`Setting "${fieldName}" to "${decodeURIComponent(supporterDetails[fieldName])}"`);
+ });
+ });
}
- showField(field) {
- const el = field instanceof Element ? field : document.querySelector(field);
- if (el) {
- const identifier = [...el.classList].find(c => c.match(/en__field--\d+/))?.replace("en__field--", "");
- if (identifier) {
- window.EngagingNetworks.require._defined.enjs.showField(identifier);
+ /*
+ * Get the supporter details from the form fields
+ */
+ getSupporterDetailsFromFields() {
+ const supporterDetails = {};
+ this.options.fields.forEach(fieldName => {
+ let field = document.querySelector(`[name="${fieldName}"]`);
+ // If it is a radio or checkbox, get the checked value
+ if (field) {
+ if (field.type === "radio" || field.type === "checkbox") {
+ field = document.querySelector(`[name="${fieldName}"]:checked`);
+ }
+ supporterDetails[fieldName] = encodeURIComponent(field.value);
}
+ });
+ return supporterDetails;
+ }
+ /*
+ * Encrypt the supporter details
+ */
+ encryptSupporterDetails(supporterDetails) {
+ return dist_sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const encryptionKey = yield this.createEncryptionKey(this.getSeed());
+ const iv = window.crypto.getRandomValues(new Uint8Array(12));
+ const supporterDetailsString = JSON.stringify(supporterDetails);
+ const encryptedData = yield window.crypto.subtle.encrypt({
+ name: "AES-GCM",
+ iv: iv
+ }, encryptionKey, new TextEncoder().encode(supporterDetailsString));
+ return {
+ encryptedData: this.arrayBufferToBase64(encryptedData),
+ iv: this.arrayBufferToBase64(iv)
+ };
+ });
+ }
+ /*
+ * Decrypt the supporter details
+ */
+ decryptSupporterDetails(encryptedSupporterDetails, iv) {
+ return dist_sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const encryptionKey = yield this.createEncryptionKey(this.getSeed());
+ const decryptedData = yield window.crypto.subtle.decrypt({
+ name: "AES-GCM",
+ iv: iv
+ }, encryptionKey, encryptedSupporterDetails);
+ return new TextDecoder().decode(decryptedData);
+ });
+ }
+ /*
+ * Create the encryption key
+ */
+ createEncryptionKey(seed) {
+ return dist_sticky_prepopulation_awaiter(this, void 0, void 0, function* () {
+ const encoder = new TextEncoder();
+ const keyMaterial = yield window.crypto.subtle.importKey("raw", encoder.encode(seed), {
+ name: "PBKDF2"
+ }, false, ["deriveKey"]);
+ return yield window.crypto.subtle.deriveKey({
+ name: "PBKDF2",
+ salt: encoder.encode(seed),
+ iterations: 100000,
+ hash: "SHA-256"
+ }, keyMaterial, {
+ name: "AES-GCM",
+ length: 256
+ }, false, ["encrypt", "decrypt"]);
+ });
+ }
+ /*
+ * Convert an ArrayBuffer to a base64 string
+ */
+ arrayBufferToBase64(buffer) {
+ let binary = "";
+ const bytes = new Uint8Array(buffer);
+ const len = bytes.byteLength;
+ for (let i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i]);
}
+ return window.btoa(binary);
}
-
/*
- * Set the default source codes as a data attribute
+ * Create an Array Buffer from a base64 string
*/
- setDefaultSourceCodes() {
- if (!this.sourceCodeField) return;
- if (this.sourceCodeField instanceof HTMLInputElement) {
- // If the source code field is an input, set the default source code as a data attribute
- this.sourceCodeField.setAttribute("data-default-source-code", this.sourceCodeField.value);
- return;
+ base64ToArrayBuffer(base64) {
+ const binary_string = window.atob(base64);
+ const len = binary_string.length;
+ const bytes = new Uint8Array(len);
+ for (let i = 0; i < len; i++) {
+ bytes[i] = binary_string.charCodeAt(i);
}
-
- // If the source code field is a select, set the default source code as a data attribute on each option
- this.sourceCodeField.querySelectorAll("option").forEach(option => {
- if (option && option.value) {
- option.setAttribute("data-default-source-code", option.value);
- }
- });
+ return bytes.buffer;
}
- isUSState(source) {
- const state = source.substring(1, 3);
- return ["AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"].includes(state);
+ /*
+ * Derive a seed from the page URL
+ */
+ getSeed() {
+ const url = new URL(window.location.href);
+ return url.origin + url.pathname + (url.searchParams.get("ea.tracking.id") ? `?ea.tracking.id=${url.searchParams.get("ea.tracking.id")}` : '');
}
}
-;// CONCATENATED MODULE: ./src/scripts/widget-progress-bar.ts
-
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/preferred-payment-method.js
-class WidgetProgressBar {
+class preferred_payment_method_PreferredPaymentMethod {
constructor() {
- _defineProperty(this, "logger", new logger_EngridLogger("WidgetProgressBar", "black", "yellow", "π«"));
- _defineProperty(this, "widget", document.querySelector(".en__component--widgetblock"));
- _defineProperty(this, "increase", 1.25);
- _defineProperty(this, "threshold", 80);
+ var _a;
+ this.logger = new dist_logger_EngridLogger("PreferredPaymentMethod", "#ffffff", "#1f2933", "βοΈ");
+ this.availabilityTimeoutMs = 4000;
+ this.cleanupHandlers = [];
+ this.selectionFinalized = false;
+ this.listenersAttached = false;
+ this.config = this.resolveConfig();
+ this.preferredFieldName = ((_a = this.config.preferredPaymentMethodField) === null || _a === void 0 ? void 0 : _a.trim()) || "";
if (!this.shouldRun()) {
- this.logger.log("Not running");
return;
}
- const widget = document.querySelector(".enWidget--progressBar");
- if (widget && widget.querySelector(".raised-remaining")) {
- this.logger.log("Widget found via querySelector");
- this.run(widget);
- } else {
- this.addMutationObserver();
+ this.attachGiveBySelectListeners();
+ const candidates = this.buildCandidateList();
+ if (candidates.length === 0) {
+ this.logger.log("No payment methods to evaluate. Skipping.");
+ return;
}
+ this.logger.log(`Evaluating preferred payment methods in order: ${candidates.join(", ")}`);
+ this.tryCandidateAtIndex(0, candidates);
}
- addMutationObserver() {
- // Watch for changes to the widget, until an element with the class "enWidget--progressBar" is found
- const observer = new MutationObserver(mutations => {
- mutations.forEach(mutation => {
- if (mutation.addedNodes.length && mutation.addedNodes[0].querySelector(".remaining")) {
- observer.disconnect();
- // There's an additional script that runs after the widget is added to the DOM, so we need to wait a bit before running our code
- window.setTimeout(() => {
- this.logger.log("Widget found via MutationObserver");
- this.widget = document.querySelector(".enWidget--progressBar");
- this.run(this.widget);
- }, 150);
- return;
+ shouldRun() {
+ if (dist_engrid_ENGrid.getPageType() !== "DONATION") {
+ this.logger.log("Not a donation page. Skipping preferred payment selection.");
+ return false;
+ }
+ // If there's a "payment" URL parameter, we can proceed
+ if (dist_engrid_ENGrid.getUrlParameter("payment")) {
+ return true;
+ }
+ if (!this.getGiveBySelectInputs().length) {
+ this.logger.log("No give-by-select inputs found. Skipping.");
+ return false;
+ }
+ const config = dist_engrid_ENGrid.getOption("PreferredPaymentMethod") || false;
+ if (config === false) {
+ this.logger.log("PreferredPaymentMethod option disabled.");
+ return false;
+ }
+ return true;
+ }
+ resolveConfig() {
+ const option = dist_engrid_ENGrid.getOption("PreferredPaymentMethod") || false;
+ if (option && typeof option === "object") {
+ const preferredPaymentMethodField = option.preferredPaymentMethodField || "";
+ const defaultPaymentMethod = Array.isArray(option.defaultPaymentMethod) ? option.defaultPaymentMethod.filter(item => !!item) : [];
+ return {
+ preferredPaymentMethodField,
+ defaultPaymentMethod: defaultPaymentMethod.length > 0 ? defaultPaymentMethod : ["card"]
+ };
+ }
+ return {
+ preferredPaymentMethodField: "",
+ defaultPaymentMethod: ["card"]
+ };
+ }
+ buildCandidateList() {
+ const candidates = [];
+ const seen = new Set();
+ const pushCandidate = value => {
+ if (!value) return;
+ const normalized = this.normalizePaymentValue(value);
+ if (!normalized || seen.has(normalized)) return;
+ seen.add(normalized);
+ candidates.push(normalized);
+ };
+ pushCandidate(this.getFieldPreference());
+ pushCandidate(this.getUrlPreference());
+ this.config.defaultPaymentMethod.forEach(pushCandidate);
+ return candidates;
+ }
+ hasPreferredField() {
+ if (!this.preferredFieldName) return false;
+ const field = dist_engrid_ENGrid.getField(this.preferredFieldName);
+ return !!field;
+ }
+ attachGiveBySelectListeners() {
+ if (this.listenersAttached) return;
+ if (!this.preferredFieldName) return;
+ if (!this.hasPreferredField()) {
+ this.logger.log(`Preferred payment field "${this.preferredFieldName}" not found. Field sync disabled.`);
+ return;
+ }
+ const inputs = this.getGiveBySelectInputs();
+ inputs.forEach(input => {
+ input.addEventListener("change", () => {
+ if (input.checked) {
+ this.syncPreferredField(input.value);
}
});
});
- observer.observe(this.widget, {
- childList: true,
- subtree: true
+ this.listenersAttached = true;
+ }
+ syncPreferredField(value) {
+ if (!this.preferredFieldName) return;
+ if (!this.hasPreferredField()) return;
+ dist_engrid_ENGrid.setFieldValue(this.preferredFieldName, value, false, true);
+ }
+ getFieldPreference() {
+ if (!this.preferredFieldName) {
+ return null;
+ }
+ const fieldValue = dist_engrid_ENGrid.getFieldValue(this.preferredFieldName);
+ if (!fieldValue) {
+ this.logger.log(`Preferred payment field "${this.preferredFieldName}" is empty. Moving on.`);
+ return null;
+ }
+ this.logger.log(`Preferred payment from field "${this.preferredFieldName}" resolved to "${fieldValue}".`);
+ return fieldValue;
+ }
+ getUrlPreference() {
+ const urlValue = dist_engrid_ENGrid.getUrlParameter("payment");
+ if (typeof urlValue === "string" && urlValue.trim() !== "") {
+ this.logger.log(`Preferred payment from URL parameter: "${urlValue}".`);
+ return urlValue;
+ }
+ return null;
+ }
+ tryCandidateAtIndex(index, candidates) {
+ if (this.selectionFinalized) {
+ return;
+ }
+ if (index >= candidates.length) {
+ this.logger.log("No preferred payment method was applied.");
+ return;
+ }
+ const method = candidates[index];
+ if (!this.paymentMethodExists(method)) {
+ this.logger.log(`Payment method "${method}" not found. Skipping.`);
+ this.tryCandidateAtIndex(index + 1, candidates);
+ return;
+ }
+ if (this.isPaymentMethodAvailable(method)) {
+ this.logger.success(`Selecting available payment method "${method}".`);
+ this.applySelection(method);
+ return;
+ }
+ this.logger.log(`Payment method "${method}" exists but is not available yet. Waiting up to ${this.availabilityTimeoutMs}ms.`);
+ this.waitForAvailability(method, () => {
+ if (this.selectionFinalized) return;
+ if (this.isPaymentMethodAvailable(method)) {
+ this.logger.success(`Selecting payment method "${method}" once it became available.`);
+ this.applySelection(method);
+ }
+ }, () => {
+ if (this.selectionFinalized) return;
+ this.logger.log(`Payment method "${method}" still unavailable after waiting. Trying next option.`);
+ this.tryCandidateAtIndex(index + 1, candidates);
});
}
- run(widget) {
- const fill = widget.querySelector(".enWidget__fill");
- const percentage = fill ? parseInt(fill.style.width, 10) : 0;
- this.logger.log("Percentage", percentage);
- if (percentage >= this.threshold) {
- this.logger.log("Incrementing goal");
- const supporters = parseInt(widget.querySelector(".raised > div")?.textContent?.replace(/\,/g, "") || "0");
- const newGoal = Math.ceil(supporters * this.increase);
- // If new goal is NaN, don't alter progress bar and bail here
- if (isNaN(newGoal)) {
- this.logger.log("Error: New goal is NaN, not altering progress bar");
+ waitForAvailability(method, onAvailable, onTimeout) {
+ const observers = [];
+ const cleanup = () => {
+ observers.forEach(observer => observer.disconnect());
+ observers.length = 0;
+ this.cleanupHandlers = this.cleanupHandlers.filter(fn => fn !== cleanup);
+ window.clearTimeout(timeoutId);
+ };
+ this.cleanupHandlers.push(cleanup);
+ const checkAvailability = () => {
+ if (this.selectionFinalized) {
+ cleanup();
return;
}
- // Reset fill width so that animation runs once new width is set
- fill.style.width = "0";
- const remainingElement = widget.querySelector(".remaining > div:first-child span");
- if (remainingElement) {
- remainingElement.textContent = (newGoal - supporters).toLocaleString();
+ if (this.isPaymentMethodAvailable(method)) {
+ cleanup();
+ onAvailable();
}
- this.logger.log("New goal", newGoal);
- fill.style.width = `${supporters / newGoal * 100}%`;
+ };
+ const fieldContainer = this.getGiveBySelectContainer() || document.body;
+ const domObserver = new MutationObserver(() => checkAvailability());
+ domObserver.observe(fieldContainer, {
+ attributes: true,
+ attributeFilter: ["class", "style"],
+ childList: true,
+ subtree: true
+ });
+ observers.push(domObserver);
+ const attributeFilters = this.getAvailabilityAttributeFilters(method);
+ if (attributeFilters.length > 0) {
+ const attrObserver = new MutationObserver(() => checkAvailability());
+ attrObserver.observe(document.body, {
+ attributes: true,
+ attributeFilter: attributeFilters
+ });
+ observers.push(attrObserver);
}
+ const timeoutId = window.setTimeout(() => {
+ cleanup();
+ onTimeout();
+ }, this.availabilityTimeoutMs);
}
- shouldRun() {
- return engrid_ENGrid.getPageType() !== "DONATION" && !!this.widget;
+ applySelection(method) {
+ if (this.selectionFinalized) {
+ return;
+ }
+ const input = this.findPaymentInput(method);
+ if (!input) {
+ this.logger.log(`Unable to locate give-by-select input for "${method}" during selection.`);
+ return;
+ }
+ if (!this.isPaymentMethodAvailable(method)) {
+ this.logger.log(`Payment method "${method}" is not available to select.`);
+ return;
+ }
+ input.checked = true;
+ input.dispatchEvent(new Event("change", {
+ bubbles: true,
+ cancelable: true
+ }));
+ dist_engrid_ENGrid.setPaymentType(method);
+ this.syncPreferredField(input.value);
+ this.selectionFinalized = true;
+ this.cleanupAllObservers();
+ }
+ paymentMethodExists(method) {
+ return !!this.findPaymentInput(method);
+ }
+ isPaymentMethodAvailable(method) {
+ const input = this.findPaymentInput(method);
+ if (!input || input.disabled) {
+ return false;
+ }
+ const container = this.getInputContainer(input);
+ return container ? dist_engrid_ENGrid.isVisible(container) : dist_engrid_ENGrid.isVisible(input);
+ }
+ findPaymentInput(method) {
+ const normalized = this.normalizePaymentValue(method);
+ if (!normalized) {
+ return null;
+ }
+ const inputs = this.getGiveBySelectInputs();
+ return Array.from(inputs).find(input => input.value && this.normalizePaymentValue(input.value) === normalized) || null;
+ }
+ getGiveBySelectInputs() {
+ return document.getElementsByName("transaction.giveBySelect");
+ }
+ getGiveBySelectContainer() {
+ return document.querySelector(".en__field--give-by-select, .give-by-select");
+ }
+ getInputContainer(input) {
+ return input.closest(".en__field__item") || input.closest(".en__field__element") || input.parentElement;
+ }
+ findLabelForInput(input) {
+ if (input.id) {
+ const externalLabel = document.querySelector(`label[for="${input.id}"]`);
+ if (externalLabel) {
+ return externalLabel;
+ }
+ }
+ return input.closest("label");
+ }
+ normalizePaymentValue(value) {
+ return value.trim().toLowerCase();
+ }
+ getAvailabilityAttributeFilters(method) {
+ const map = {
+ stripedigitalwallet: ["data-engrid-payment-type-option-apple-pay", "data-engrid-payment-type-option-google-pay"],
+ paypaltouch: ["data-engrid-payment-type-option-paypal-one-touch", "data-engrid-payment-type-option-venmo"],
+ daf: ["data-engrid-payment-type-option-daf"]
+ };
+ return map[method] || [];
+ }
+ cleanupAllObservers() {
+ this.cleanupHandlers.forEach(cleanup => cleanup());
+ this.cleanupHandlers = [];
}
}
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/version.js
+const version_AppVersion = "0.25.2";
+;// CONCATENATED MODULE: ../engrid/packages/scripts/dist/index.js
+ // Runs first so it can change the DOM markup before any markup dependent code fires
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Events
+
+// Version
+
;// CONCATENATED MODULE: ./src/scripts/gdcp/config/gdcp-fields.ts
const gdcpFields = [{
channel: "email",
@@ -29401,13 +50309,31 @@ const pages = {
};
;// CONCATENATED MODULE: ./src/scripts/gdcp/gdcp-manager.ts
-
+var _GdcpManager;
+ // Uses ENGrid via NPM
class GdcpManager {
+ /**
+ * Returns a promise that resolves once GdcpManager has finished
+ * dealing with any pending QCB iframe submissions for the current
+ * page β including the "nothing to do" case. Safe to call before
+ * GdcpManager is instantiated.
+ */
+ static qcbChainDecided() {
+ return GdcpManager._qcbChainDecidedPromise;
+ }
+
+ /** Idempotent resolve of the qcb-chain-decided deferred. */
+ resolveQcbChainDecided() {
+ if (GdcpManager._qcbChainDecidedResolve) {
+ GdcpManager._qcbChainDecidedResolve();
+ GdcpManager._qcbChainDecidedResolve = null;
+ }
+ }
constructor() {
_defineProperty(this, "logger", new logger_EngridLogger("GDCP", "#00ff00", "#000000", "π€"));
_defineProperty(this, "gdcpFieldManager", new GdcpFieldManager());
@@ -29421,9 +50347,10 @@ class GdcpManager {
_defineProperty(this, "submissionFailed", !!(engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "checkSubmissionFailed") && window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed()));
_defineProperty(this, "_form", en_form_EnForm.getInstance());
_defineProperty(this, "pages", pages);
- this.handleDoubleOptInEmail();
- this.handlePostalMailQcb();
- this.handleMobilePhoneQcb();
+ // Kick off the async QCB follow-up flow. We don't `await` here β
+ // the rest of the constructor proceeds with the usual GDCP setup,
+ // and BequestLightbox coordinates via `qcbChainDecided()`.
+ void this.queueGdcpFollowUps();
if (!this.shouldRun()) {
engrid_ENGrid.setBodyData("gdcp", "false");
this.logger.log("GDCP is not running on this page.");
@@ -29495,496 +50422,1478 @@ class GdcpManager {
}
return location;
}
-
- // No location data from Cloudflare + no location fields on page
- // Return default "Unknown" location
- return location;
+
+ // No location data from Cloudflare + no location fields on page
+ // Return default "Unknown" location
+ return location;
+ }
+
+ /**
+ * Handle adding the state field to the page if the user's location is the US and the state field is missing
+ */
+ addStateFieldIfNeeded(location) {
+ // If strict mode is active we don't need to add the state field
+ if (this.strictMode) {
+ return;
+ }
+ if (location.startsWith("US") && !engrid_ENGrid.getField("supporter.region") && this.gdcpFieldManager.getFields().size > 0) {
+ this.logger.log("Location is US and state field is missing, adding state field to page");
+ this.createUSStatesField();
+ }
+ }
+
+ /**
+ * Create US states field and add it to the page
+ * When positioning on the page, we always use flexbox ordering
+ * to prevent issues with the i-hide i-50 etc helper classes
+ */
+ createUSStatesField() {
+ //If the state field is already on the page or we're in strict mode, no need to add it
+ if (engrid_ENGrid.getField("supporter.region") || this.strictMode) {
+ return;
+ }
+ const usStatesFieldHtml = `
+
State or Province
+
+ SELECT STATE/PROVINCE Alaska Alabama Arizona Arkansas California Colorado Connecticut Delaware District of Columbia Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi Missouri Montana Nebraska Nevada New Hampshire New Jersey New Mexico New York North Carolina North Dakota Ohio Oklahoma Oregon Pennsylvania Rhode Island South Carolina South Dakota Tennessee Texas Utah Vermont Virginia Washington West Virginia Wisconsin Wyoming Armed Forces Americas Armed Forces Europe/Canada/Middle East/Africa Armed Forces Pacific American Samoa Canal Zone Guam Minor Outlying Islands Northern Mariana Islands Puerto Rico Virgin Islands None
+
+
`;
+
+ //If the page has a country field we will position the state field after it
+ const countryField = document.querySelector(".en__field--country");
+ if (countryField) {
+ countryField.parentElement?.insertAdjacentHTML("beforeend", usStatesFieldHtml);
+
+ //Doing the ordering here to prevent issues with the i-hide i-50 etc helper classes
+ const children = countryField.parentElement?.children;
+ let countryOrder;
+ if (children) {
+ for (let i = 0; i < children.length; i++) {
+ const child = children[i];
+ child.style.order = i.toString();
+ if (child.classList.contains("en__field--country")) {
+ countryOrder = i;
+ }
+ }
+ }
+ document.querySelector(".en__field--region")?.setAttribute("style", `order: ${countryOrder}`);
+ this.watchForLocationChange();
+ return;
+ }
+
+ //Else, if the page has an email field we will position it at the top of the form block
+ const emailField = document.querySelector(".en__field--email, .en__field--emailAddress");
+ if (emailField) {
+ emailField.parentElement?.insertAdjacentHTML("beforeend", usStatesFieldHtml);
+ const regionField = document.querySelector(".en__field--region");
+ if (regionField) {
+ //Position the region field as the first field inside the form block with the email field
+ //Use flex ordering to do this to not interfere with the form's default order (and any iX- helper classes)
+ regionField.style.order = "-1";
+ }
+ return;
+ }
+ }
+
+ /**
+ * Watch for changes in the user's location (country and region fields) and apply the opt in rules
+ */
+ watchForLocationChange() {
+ const countryField = engrid_ENGrid.getField("supporter.country");
+ const regionField = engrid_ENGrid.getField("supporter.region");
+ if (countryField && !this.countryListenerAdded) {
+ countryField.addEventListener("change", () => {
+ let location = engrid_ENGrid.getFieldValue("supporter.country");
+ if (engrid_ENGrid.getFieldValue("supporter.region")) {
+ location += `-${engrid_ENGrid.getFieldValue("supporter.region")}`;
+ }
+ this.userLocation = location;
+ this.addStateFieldIfNeeded(this.userLocation);
+ this.applyRulesForLocation(this.userLocation);
+ });
+ this.countryListenerAdded = true;
+ }
+ if (regionField && !this.regionListenerAdded) {
+ regionField.addEventListener("change", () => {
+ //Must always have country value - fall back to our initial value if country field if not on page
+ const country = engrid_ENGrid.getFieldValue("supporter.country") || this.userLocation.split("-")[0];
+ this.userLocation = `${country}-${engrid_ENGrid.getFieldValue("supporter.region")}`;
+ this.applyRulesForLocation(this.userLocation);
+ });
+ this.regionListenerAdded = true;
+ }
+ }
+
+ /**
+ * Setup the GDCP fields on the page
+ * Determines if the required fields are present for a channel and creates the GDCP field
+ * Hides the EN opt in fields for the GDCP field
+ */
+ async setupGdcpFields() {
+ for (const gdcpField of this.gdcpFields) {
+ const enFieldsAreOnPage = await this.enFieldsForGdcpFieldOnPage(gdcpField);
+ if (enFieldsAreOnPage) {
+ this.gdcpFieldManager.addField(gdcpField);
+ this.hideEnOptInFields(gdcpField);
+ if (!this.singleOptInMode) {
+ this.logger.log(`Creating GDCP field for "${gdcpField.channel}"`);
+ this.createGdcpField(gdcpField);
+ }
+ } else {
+ this.logger.log(`Did not find the required fields for channel "${gdcpField.channel}" - "${gdcpField.dataFieldName}" and any of opt in field(s) "${gdcpField.optInFieldNames.join(", ")}". Skipping adding GDCP field for this channel to page.`);
+ }
+ }
+ if (this.singleOptInMode && this.gdcpFieldManager.getFields().size > 0) {
+ this.logger.log("Single Opt-In mode is active, creating checkbox");
+ this.createSingleOptInCheckbox();
+ }
+ }
+ hideEnOptInFields(gdcpField) {
+ gdcpField.optInFieldNames.forEach(name => {
+ const input = document.querySelector(`[name="${name}"]`);
+ input?.closest(".en__field")?.classList.add("hide");
+ });
+ }
+
+ /**
+ * Creates the GDCP field element and adds it to the page
+ * Also adds an event listener to toggle all the opt in fields when the GDCP field is checked/unchecked
+ */
+ createGdcpField(gdcpField) {
+ // @ts-ignore
+ const fieldHtmlLabel = window.pageJson.locale.startsWith("es") ? gdcpField.gdcpFieldHtmlLabelEs : gdcpField.gdcpFieldHtmlLabel;
+ const field = `
+
+
+
+
+
+ ${fieldHtmlLabel}
+
+
+
+
+ ${fieldHtmlLabel}
+
+
+
+
`;
+ const formElement = document.querySelector(`[name="${gdcpField.dataFieldName}"]`)?.closest(".en__field");
+ if (formElement) {
+ formElement.insertAdjacentHTML("beforeend", field);
+ }
+ const input = document.querySelector(`[name="${gdcpField.gdcpFieldName}"]`);
+ if (input) {
+ input.addEventListener("change", () => {
+ this.gdcpFieldManager.setChecked(gdcpField.gdcpFieldName, input.checked, true);
+ this.gdcpFieldManager.setTouched(gdcpField.gdcpFieldName);
+ });
+ }
+ return input;
+ }
+
+ /**
+ * Check if the corresponding EN fields are present on the page
+ * for a given GDCP Opt In Field
+ * i.e. Its data field + any of the opt in fields
+ */
+ async enFieldsForGdcpFieldOnPage(gdcpField) {
+ const dataFieldPresent = document.querySelector(`[name="${gdcpField.dataFieldName}"]`);
+ if (!dataFieldPresent) {
+ return false;
+ }
+ const optInFieldsNames = gdcpField.optInFieldNames.map(name => `[name="${name}"]`).join(", ");
+ const optInFieldsPresent = document.querySelector(optInFieldsNames);
+ if (gdcpField.channel !== "postal_mail" && gdcpField.channel !== "mobile_phone") {
+ return !!dataFieldPresent && !!optInFieldsPresent;
+ }
+ if (gdcpField.channel === "postal_mail") {
+ try {
+ const postalMailOptInFieldPresent = await this.isPresentOnEmbeddedForm(this.pages.postal_mail_qcb, `#en__field_supporter_questions_1942219`);
+ return !!dataFieldPresent && !!optInFieldsPresent && postalMailOptInFieldPresent;
+ } catch (e) {
+ this.logger.error("Error checking if opted into postal mail", e);
+ return false;
+ }
+ }
+
+ // mobile_phone
+ try {
+ const mobilePhoneOptInFieldPresent = await this.isPresentOnEmbeddedForm(this.pages.mobile_phone_qcbs, `#en__field_supporter_questions_848527, #en__field_supporter_questions_848528`);
+ return !!dataFieldPresent && !!optInFieldsPresent && mobilePhoneOptInFieldPresent;
+ } catch (e) {
+ this.logger.error("Error checking if opted into mobile phone", e);
+ return false;
+ }
+ }
+
+ /*
+ * Check if a given element is present on an embedded form (iframe)
+ */
+ async isPresentOnEmbeddedForm(pageUrl, selector) {
+ const iframe = this.createChainedIframeForm(pageUrl);
+ await new Promise((resolve, reject) => {
+ iframe.addEventListener("load", resolve);
+ iframe.addEventListener("error", reject);
+ });
+ const iframeDocument = iframe.contentDocument || iframe.contentWindow?.document;
+ let elementInIframe = iframeDocument?.querySelector(selector);
+ return !!elementInIframe;
+ }
+
+ /**
+ * Apply the opt in rules for the user's location
+ * @param location The user's location
+ * @param scrollToChangedField Whether to scroll to the field highest up the page that has changed state
+ */
+ applyRulesForLocation(location, scrollToChangedField = true) {
+ const {
+ checkedStateChangedFields
+ } = this.ruleHandler.applyOptInRules(location);
+ if (scrollToChangedField) {
+ this.scrollUpToHighestChangedField(checkedStateChangedFields);
+ }
+ }
+
+ /**
+ * Scroll to the field highest up the page that has changed state
+ */
+ scrollUpToHighestChangedField(checkedStateChangedFields) {
+ if (checkedStateChangedFields.length) {
+ // Only rules that have a visible checkbox
+ const visibleFields = checkedStateChangedFields.filter(field => {
+ const gdcpField = this.gdcpFieldManager.getField(field.gdcpFieldName);
+ return gdcpField?.visible;
+ });
+
+ // Get the DOM element of the data field of the field highest up the page
+ const firstChangedField = visibleFields.map(field => {
+ return document.querySelector(`[name="${field.dataFieldName}"]`)?.closest(".en__field");
+ }).filter(el => el).reduce((a, b) => {
+ return a?.getBoundingClientRect().top < b?.getBoundingClientRect().top ? a : b;
+ });
+ if (firstChangedField) {
+ const fieldTop = firstChangedField.getBoundingClientRect().top + window.scrollY;
+ // Only scroll if the field is above the current scroll position
+ if (fieldTop < window.scrollY) {
+ firstChangedField.scrollIntoView({
+ behavior: "smooth"
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a consent statement below the submit button for existing supporters
+ */
+ addConsentStatementForExistingSupporters() {
+ if (engrid_ENGrid.getFieldValue("supporter.emailAddress") && !this.submissionFailed) {
+ const submitButtonBlock = document.querySelector(".en__submit")?.parentElement;
+ const consentStatement = `
+
+
+ You previously provided your communication preferences. If you wish to change those preferences, please
+ click here .
+
+
+ `;
+ submitButtonBlock?.insertAdjacentHTML("afterend", consentStatement);
+ }
+ }
+
+ /**
+ * Get the value of a cookie by name
+ */
+ getCookie(cookieName) {
+ const name = `${cookieName}=`;
+ const decodedCookie = decodeURIComponent(document.cookie);
+ const cookieArray = decodedCookie.split(";");
+ for (let i = 0; i < cookieArray.length; i++) {
+ let cookie = cookieArray[i];
+ while (cookie.charAt(0) === " ") {
+ cookie = cookie.substring(1);
+ }
+ if (cookie.indexOf(name) === 0) {
+ return cookie.substring(name.length, cookie.length);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Actions for when EN form is submitted
+ * @private
+ */
+ onSubmit() {
+ this._form.onSubmit.subscribe(() => {
+ // Save the GDCP fields state to session (for restoring in case of submission errors)
+ this.gdcpFieldManager.saveStateToSession();
+ });
+ }
+
+ /**
+ * Restore the state of the GDCP + Opt In fields from session storage
+ * Used when the submission fails, instead of applying location-based rules again.
+ */
+ restoreFieldsStateFromSession() {
+ this.logger.log("Detected submission failure. Restoring GDCP + Opt In field states.");
+ this.gdcpFieldManager.applyStateFromSession();
+ }
+
+ /**
+ * Clear the session storage state
+ * @private
+ */
+ clearSessionState() {
+ this.gdcpFieldManager.clearStateFromSession();
+ }
+
+ /**
+ * Enqueue any pending GDCP follow-up iframe submissions onto the shared
+ * IframeQueue and start processing. Replaces three independent
+ * setTimeout-spaced submissions which suffered ~40% record loss when
+ * EN handled concurrent iframe submits. The queue processes items
+ * strictly sequentially (the next iframe is created only after the
+ * previous one reaches its Thank You page), without `?chain`.
+ *
+ * Asynchronous because resolving the supporter email goes through
+ * EN's async `enjs.getPageData` callback (the synchronous
+ * `getSupporterData` XHR is unreliable in modern browsers β see
+ * the comment on `resolveSupporterEmail`). The method always
+ * resolves the static `qcbChainDecided` promise on the way out so
+ * BequestLightbox can stop waiting regardless of which branch was
+ * taken (skipped, errored, or completed).
+ */
+ async queueGdcpFollowUps() {
+ try {
+ // QCB follow-up work is signalled by sessionStorage entries
+ // written by an earlier form submission (donation, advocacy,
+ // etc.). If none of those entries are present (or all of them
+ // were written on the current page), there's nothing to do β
+ // skip silently. This avoids a spurious "supporter email not
+ // found" error log on every entry page that has no pending
+ // QCB session data.
+ //
+ // We intentionally do NOT gate this on isThankYouPage(). Some
+ // client flows chain pages across page types (e.g. an
+ // advocacy Thank You page that redirects via `?chain` into a
+ // donation form page 1), and on those chained pages the
+ // earlier-page sessionData is still pending and EN pre-fills
+ // the supporter email field, so the chain can run there.
+ if (!this.hasPendingQcbWork()) return;
+
+ // EN's QCB forms need the supporter's email to match the
+ // record to a supporter β the job `?chain` used to do
+ // server-side. If we can't find one, no QCB record can be
+ // created, so we bail out loudly rather than queueing iframes
+ // that are guaranteed to time out.
+ const email = await this.resolveSupporterEmail();
+ if (!email) {
+ this.logger.error("Skipping QCB iframe queue: could not resolve supporter " + "email. EN's `enjs.getPageData` did not return a valid " + "`emailAddress`. Check that the /pagedata response on " + "this Thank You page contains supporter data.");
+ return;
+ }
+ const queue = IframeQueue.getInstance();
+ this.maybeEnqueueDoubleOptInEmail(queue, email);
+ this.maybeEnqueuePostalMailQcb(queue, email);
+ this.maybeEnqueueMobilePhoneQcb(queue, email);
+ if (queue.size === 0 && !queue.isProcessing) return;
+ this.logger.log(`Starting iframe queue with ${queue.size} pending follow-up(s).`);
+ // Await the chain so callers awaiting `qcbChainDecided()` only
+ // see the promise resolve after the queue is done.
+ await queue.process().catch(err => {
+ this.logger.error("Iframe queue rejected:", err);
+ });
+ } finally {
+ this.resolveQcbChainDecided();
+ }
+ }
+
+ /**
+ * Returns true when any of the three QCB sessionStorage entries
+ * indicates pending work on the current page (i.e. the entry was
+ * written on a previous page in the flow and hasn't been consumed
+ * yet, and the prior submission didn't fail). Used as a cheap
+ * early bail-out in `queueGdcpFollowUps` before any email
+ * resolution work is done.
+ */
+ hasPendingQcbWork() {
+ const keys = ["gdcp-email-double-opt-in", "gdcp-postal-mail-create-qcb", "gdcp-mobile-phone-create-qcb"];
+ for (const key of keys) {
+ let data;
+ try {
+ data = JSON.parse(sessionStorage.getItem(key) || "{}");
+ } catch {
+ continue;
+ }
+ if (data.page && data.page !== window.location.pathname && !this.submissionFailed) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Resolve the supporter's email address, trying sources in this
+ * order:
+ *
+ * 1. `ENGrid.getFieldValue("supporter.emailAddress")` β synchronous
+ * read of the supporter email form field. On chained pages
+ * (e.g. advocacy Thank You β donation page 1 via `?chain`)
+ * EN pre-fills supporter fields on the next page, so the
+ * email is right there with no XHR required. This is the
+ * hot path for the chained-page scenario.
+ *
+ * 2. EN's async `enjs.getPageData` API β callback-based, reads
+ * the supporter from EN's in-page data layer (the `/pagedata`
+ * response). Used on pages where the email isn't echoed onto
+ * a form field (typical TY page after a standalone donation).
+ * Chosen over the synchronous `enjs.getSupporterData` because
+ * that one's underlying XHR is set with `async: false`, which
+ * modern browsers (Chrome, Firefox) routinely block or abort
+ * silently in cross-origin / iframe contexts. When that
+ * happens EN caches an empty result and every later call
+ * returns the empty cache. `getPageData` is the well-behaved
+ * callback-based alternative on the same data source β it
+ * caches into `enjs._pageDataResponse` and replays for
+ * subsequent callers, so it's reliable and idempotent.
+ *
+ * The validation regex is intentionally lenient β EN already
+ * validated the email on submission, so we're just guarding
+ * against empty strings or obviously malformed values. Resolves
+ * to null after a 30s timeout if EN's framework isn't loaded or
+ * the /pagedata call hangs.
+ */
+ resolveSupporterEmail() {
+ return new Promise(resolve => {
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ const maxWaitMs = 30000;
+ let settled = false;
+ const finish = email => {
+ if (settled) return;
+ settled = true;
+ window.clearTimeout(timeoutId);
+ resolve(email);
+ };
+ const timeoutId = window.setTimeout(() => {
+ this.logger.error(`resolveSupporterEmail: timed out after ${maxWaitMs}ms ` + `waiting for EN's getPageData callback.`);
+ finish(null);
+ }, maxWaitMs);
+
+ // Source 1: supporter email field on the current page (synchronous).
+ const fromField = engrid_ENGrid.getFieldValue("supporter.emailAddress");
+ if (typeof fromField === "string" && emailRegex.test(fromField)) {
+ finish(fromField);
+ return;
+ }
+
+ // Source 2: EN's async getPageData (XHR-backed, cached).
+ if (!engrid_ENGrid.checkNested(window.EngagingNetworks, "require", "_defined", "enjs", "getPageData")) {
+ finish(null);
+ return;
+ }
+ try {
+ window.EngagingNetworks.require._defined.enjs.getPageData(data => {
+ const email = data?.emailAddress;
+ if (typeof email === "string" && emailRegex.test(email)) {
+ finish(email);
+ } else {
+ finish(null);
+ }
+ }, _err => {
+ finish(null);
+ });
+ } catch {
+ finish(null);
+ }
+ });
+ }
+
+ /**
+ * Enqueue the double-opt-in email trigger iframe, if the session data
+ * indicates the supporter just opted in to email on a different page.
+ */
+ maybeEnqueueDoubleOptInEmail(queue, email) {
+ const sessionData = JSON.parse(sessionStorage.getItem("gdcp-email-double-opt-in") || "{}");
+ const shouldSend = sessionData.page && sessionData.page !== window.location.pathname && !this.submissionFailed;
+ if (!shouldSend) return;
+ const url = this.pages.double_opt_in_email_trigger;
+ queue.enqueue({
+ url,
+ fields: {
+ "supporter.emailAddress": email
+ },
+ autoSubmit: true,
+ // keepIframeOnError: true, // uncomment to debug (or enable ENgrid debug mode)
+ onComplete: () => {
+ this.logger.log(`Double opt-in email sent via iframe queue: ${url}`);
+ },
+ onError: error => {
+ this.logger.error(`Double opt-in email iframe queue item failed: ${error.message}`);
+ }
+ });
+ sessionStorage.removeItem("gdcp-email-double-opt-in");
+ }
+
+ /**
+ * Enqueue the postal-mail QCB iframe, if the session data indicates a
+ * QCB needs to be recorded. When the supporter opted out (state === "N")
+ * we still enqueue, but pass the negative answer via the populate
+ * message so the embedded form records the negative QCB.
+ */
+ maybeEnqueuePostalMailQcb(queue, email) {
+ const sessionData = JSON.parse(sessionStorage.getItem("gdcp-postal-mail-create-qcb") || "{}");
+ const shouldCreateQcb = sessionData.page && sessionData.page !== window.location.pathname && !this.submissionFailed;
+ if (!shouldCreateQcb) return;
+ const fields = {
+ "supporter.emailAddress": email
+ };
+ if (sessionData.state === "N") {
+ fields["supporter.questions.1942219"] = "N";
+ }
+ const url = this.pages.postal_mail_qcb;
+ queue.enqueue({
+ url,
+ fields,
+ autoSubmit: true,
+ // keepIframeOnError: true, // uncomment to debug (or enable ENgrid debug mode)
+ onComplete: () => {
+ this.logger.log(`Postal mail QCB created via iframe queue (state=${sessionData.state || "Y"}).`);
+ },
+ onError: error => {
+ this.logger.error(`Postal mail QCB iframe queue item failed: ${error.message}`);
+ }
+ });
+ sessionStorage.removeItem("gdcp-postal-mail-create-qcb");
+ }
+
+ /**
+ * Enqueue the mobile-phone QCB iframe, if the session data indicates
+ * a QCB needs to be recorded. Negative QCBs are intentionally not
+ * created for the mobile-phone channel β when state === "N" the
+ * session marker is cleared and no iframe is enqueued.
+ */
+ maybeEnqueueMobilePhoneQcb(queue, email) {
+ const sessionData = JSON.parse(sessionStorage.getItem("gdcp-mobile-phone-create-qcb") || "{}");
+ const shouldCreateQcb = sessionData.page && sessionData.page !== window.location.pathname && !this.submissionFailed;
+ if (!shouldCreateQcb) return;
+ if (sessionData.state === "N") {
+ // Negative QCBs are not recorded for the mobile-phone channel.
+ sessionStorage.removeItem("gdcp-mobile-phone-create-qcb");
+ this.logger.log("Skipping mobile phone QCB (state=N β negative QCBs are not recorded for this channel).");
+ return;
+ }
+ const url = this.pages.mobile_phone_qcbs;
+ queue.enqueue({
+ url,
+ fields: {
+ "supporter.emailAddress": email
+ },
+ autoSubmit: true,
+ // keepIframeOnError: true, // uncomment to debug (or enable ENgrid debug mode)
+ onComplete: () => {
+ this.logger.log(`Mobile phone QCB created via iframe queue: ${url}`);
+ },
+ onError: error => {
+ this.logger.error(`Mobile phone QCB iframe queue item failed: ${error.message}`);
+ }
+ });
+ sessionStorage.removeItem("gdcp-mobile-phone-create-qcb");
+ }
+
+ /**
+ * Create a hidden chained iframe (with `?chain` and optional
+ * `?autosubmit=Y`). Used **only** by `isPresentOnEmbeddedForm` for
+ * synchronous DOM inspection β that flow loads an iframe, waits for
+ * `load`, and reads the document, without submitting. The
+ * post-submission QCB / opt-in chains use the IframeQueue component
+ * instead and never go through this helper.
+ */
+ createChainedIframeForm(urlString, autoSubmit = false) {
+ const url = new URL(urlString);
+ url.searchParams.append("chain", "");
+ if (autoSubmit) {
+ url.searchParams.append("autosubmit", "Y");
+ }
+ const iframe = document.createElement("iframe");
+ iframe.src = url.toString();
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ return iframe;
+ }
+
+ /**
+ * Create a single opt in checkbox for the page
+ */
+ createSingleOptInCheckbox() {
+ const field = `
+ `;
+ const formElement = document.querySelector(".en__submit");
+ if (formElement) {
+ formElement.closest(".en__component--formblock")?.insertAdjacentHTML("beforebegin", field);
+ }
+ const input = document.querySelector(`[name="engrid.gdcp-single-opt-in"]`);
+ if (input) {
+ input.addEventListener("change", () => {
+ this.gdcpFields.forEach(gdcpField => {
+ this.gdcpFieldManager.setChecked(gdcpField.gdcpFieldName, input.checked, true);
+ this.gdcpFieldManager.setTouched(gdcpField.gdcpFieldName);
+ });
+ });
+ }
+ return input;
}
/**
- * Handle adding the state field to the page if the user's location is the US and the state field is missing
+ * Set the initial state of the GDCP fields to unchecked in single opt in mode
+ * Set them to touched so that any location rule change won't modify the checked state
+ * We still want the location based rules to apply so we have the double opt in and no qcb rules
*/
- addStateFieldIfNeeded(location) {
- // If strict mode is active we don't need to add the state field
- if (this.strictMode) {
+ setSingleOptInModeInitialState() {
+ if (this.singleOptInMode && !this.submissionFailed) {
+ this.logger.log("Single Opt-In Mode - Setting all opt-ins to unchecked as initial state.");
+ this.gdcpFields.forEach(gdcpField => {
+ this.gdcpFieldManager.setChecked(gdcpField.gdcpFieldName, false, true);
+ this.gdcpFieldManager.setTouched(gdcpField.gdcpFieldName);
+ });
+ }
+ }
+ createMobilePhoneSessionStorageListener() {
+ const gdcpFieldName = this.gdcpFields.find(field => field.channel === "mobile_phone")?.gdcpFieldName;
+ const mobilePhoneGdcpField = engrid_ENGrid.getField(gdcpFieldName || "");
+ if (!mobilePhoneGdcpField) {
+ // GDCP isn't enabled for mobile phone on this page
return;
}
- if (location.startsWith("US") && !engrid_ENGrid.getField("supporter.region") && this.gdcpFieldManager.getFields().size > 0) {
- this.logger.log("Location is US and state field is missing, adding state field to page");
- this.createUSStatesField();
+ const fields = [mobilePhoneGdcpField, engrid_ENGrid.getField("supporter.phoneNumber2"), engrid_ENGrid.getField("supporter.country")].filter(Boolean).flat();
+
+ // Do an initial call to handle the current state (if pre-filled)
+ this.setMobilePhoneSessionItem();
+ fields.forEach(field => {
+ field?.addEventListener("change", this.setMobilePhoneSessionItem.bind(this));
+ });
+ }
+ setMobilePhoneSessionItem() {
+ const gdcpFieldName = this.gdcpFields.find(field => field.channel === "mobile_phone")?.gdcpFieldName;
+ const checked = this.gdcpFieldManager.getField(gdcpFieldName || "")?.checked;
+ if (engrid_ENGrid.getFieldValue("supporter.phoneNumber2") !== "" && engrid_ENGrid.getFieldValue("supporter.country") === "US") {
+ sessionStorage.setItem("gdcp-mobile-phone-create-qcb", JSON.stringify({
+ state: checked ? "Y" : "N",
+ page: window.location.pathname
+ }));
+ this.logger.log(`Mobile Phone channel will create QCB with status: ${checked ? "Y" : "N"}`);
+ } else {
+ sessionStorage.removeItem("gdcp-mobile-phone-create-qcb");
+ this.logger.log(`Mobile Phone channel missing required data, won't create a QCB`);
}
}
+}
+_GdcpManager = GdcpManager;
+/**
+ * Deferred used to signal when the QCB iframe queue's outcome has
+ * been decided β i.e. either the chain finished (success or error)
+ * or it was determined there's no chain to run (not a Thank You
+ * page, no supporter email, or no pending QCB sessions).
+ *
+ * BequestLightbox awaits this before opening so the bequest iframe
+ * isn't competing with EN's form-submission machinery while QCB
+ * iframes are in flight. The promise is created at class-load time
+ * so callers (notably BequestLightbox, which is constructed before
+ * GdcpManager in TNC's bootstrap) get a stable reference regardless
+ * of construction order.
+ */
+_defineProperty(GdcpManager, "_qcbChainDecidedResolve", null);
+_defineProperty(GdcpManager, "_qcbChainDecidedPromise", new Promise(resolve => {
+ _GdcpManager._qcbChainDecidedResolve = resolve;
+}));
+;// CONCATENATED MODULE: ./src/scripts/bequest-lightbox.ts
- /**
- * Create US states field and add it to the page
- * When positioning on the page, we always use flexbox ordering
- * to prevent issues with the i-hide i-50 etc helper classes
- */
- createUSStatesField() {
- //If the state field is already on the page or we're in strict mode, no need to add it
- if (engrid_ENGrid.getField("supporter.region") || this.strictMode) {
- return;
- }
- const usStatesFieldHtml = `
-
State or Province
-
- SELECT STATE/PROVINCE Alaska Alabama Arizona Arkansas California Colorado Connecticut Delaware District of Columbia Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi Missouri Montana Nebraska Nevada New Hampshire New Jersey New Mexico New York North Carolina North Dakota Ohio Oklahoma Oregon Pennsylvania Rhode Island South Carolina South Dakota Tennessee Texas Utah Vermont Virginia Washington West Virginia Wisconsin Wyoming Armed Forces Americas Armed Forces Europe/Canada/Middle East/Africa Armed Forces Pacific American Samoa Canal Zone Guam Minor Outlying Islands Northern Mariana Islands Puerto Rico Virgin Islands None
-
-
`;
+ // Uses ENGrid via Visual Studio Workspace
- //If the page has a country field we will position the state field after it
- const countryField = document.querySelector(".en__field--country");
- if (countryField) {
- countryField.parentElement?.insertAdjacentHTML("beforeend", usStatesFieldHtml);
- //Doing the ordering here to prevent issues with the i-hide i-50 etc helper classes
- const children = countryField.parentElement?.children;
- let countryOrder;
- if (children) {
- for (let i = 0; i < children.length; i++) {
- const child = children[i];
- child.style.order = i.toString();
- if (child.classList.contains("en__field--country")) {
- countryOrder = i;
- }
- }
- }
- document.querySelector(".en__field--region")?.setAttribute("style", `order: ${countryOrder}`);
- this.watchForLocationChange();
+class BequestLightbox {
+ constructor() {
+ _defineProperty(this, "logger", new dist_logger_EngridLogger("BequestLightbox", "yellow", "black"));
+ _defineProperty(this, "modalContent", null);
+ _defineProperty(this, "bequestUserProfile", undefined);
+ _defineProperty(this, "pageJson", void 0);
+ this.modalContent = document.querySelector(".modal--bequest");
+ this.bequestUserProfile = window.bequestUserProfile || undefined;
+ this.pageJson = window.pageJson;
+ if (!this.shouldRun()) {
+ this.logger.log("Not running bequest modal.");
return;
}
- //Else, if the page has an email field we will position it at the top of the form block
- const emailField = document.querySelector(".en__field--email, .en__field--emailAddress");
- if (emailField) {
- emailField.parentElement?.insertAdjacentHTML("beforeend", usStatesFieldHtml);
- const regionField = document.querySelector(".en__field--region");
- if (regionField) {
- //Position the region field as the first field inside the form block with the email field
- //Use flex ordering to do this to not interfere with the form's default order (and any iX- helper classes)
- regionField.style.order = "-1";
- }
- return;
+ // Defuse any iframes inside the modal before the user can see it.
+ // The browser starts loading an iframe the moment it parses the
+ // `src` attribute, which is long before this constructor runs β so
+ // by the time we get here a GET to EN may already be in flight. We
+ // rewrite `src` to "about:blank", which navigates the frame and
+ // aborts the in-flight request. The original URL is stashed in
+ // `data-deferred-src` and restored when the modal actually opens
+ // (see `armModalIframes`). This preserves the "one EN thing at a
+ // time" invariant of the Iframe Queue refactor β without this,
+ // the bequest iframe would load concurrently with queued QCB
+ // iframes even though the bequest *submit* is correctly gated on
+ // `onChainComplete`.
+ this.defuseModalIframes();
+ this.addModal();
+ if (this.shouldOpen()) {
+ this.openWhenSafe();
}
+ this.logConditions();
}
/**
- * Watch for changes in the user's location (country and region fields) and apply the opt in rules
+ * Open the bequest lightbox after GdcpManager has decided what to
+ * do with any pending QCB iframe submissions. Opening synchronously
+ * alongside in-flight QCB submits causes EN to drop QCB records
+ * (the original bug tracked in EN-2802 / EN-2803), so this defers
+ * until `GdcpManager.qcbChainDecided()` resolves.
+ *
+ * That promise resolves under all of:
+ * - the iframe queue chain finishes successfully,
+ * - the chain errors out (so we don't get stuck closed),
+ * - GdcpManager determines there's no chain to run (not a Thank
+ * You page, no supporter email available, no pending QCB
+ * sessions).
+ *
+ * A safety-net timeout opens the lightbox after 15s if the
+ * promise never resolves (e.g., GdcpManager wasn't instantiated
+ * for some reason).
*/
- watchForLocationChange() {
- const countryField = engrid_ENGrid.getField("supporter.country");
- const regionField = engrid_ENGrid.getField("supporter.region");
- if (countryField && !this.countryListenerAdded) {
- countryField.addEventListener("change", () => {
- let location = engrid_ENGrid.getFieldValue("supporter.country");
- if (engrid_ENGrid.getFieldValue("supporter.region")) {
- location += `-${engrid_ENGrid.getFieldValue("supporter.region")}`;
- }
- this.userLocation = location;
- this.addStateFieldIfNeeded(this.userLocation);
- this.applyRulesForLocation(this.userLocation);
- });
- this.countryListenerAdded = true;
- }
- if (regionField && !this.regionListenerAdded) {
- regionField.addEventListener("change", () => {
- //Must always have country value - fall back to our initial value if country field if not on page
- const country = engrid_ENGrid.getFieldValue("supporter.country") || this.userLocation.split("-")[0];
- this.userLocation = `${country}-${engrid_ENGrid.getFieldValue("supporter.region")}`;
- this.applyRulesForLocation(this.userLocation);
- });
- this.regionListenerAdded = true;
- }
+ openWhenSafe() {
+ const safetyNetMs = 15000;
+ let opened = false;
+ const openOnce = reason => {
+ if (opened) return;
+ opened = true;
+ this.logger.log(`Opening bequest lightbox: ${reason}.`);
+ this.armModalIframes();
+ this.open();
+ };
+ GdcpManager.qcbChainDecided().then(() => {
+ openOnce("QCB chain decided");
+ });
+ window.setTimeout(() => {
+ openOnce(`safety-net timeout (${safetyNetMs}ms)`);
+ }, safetyNetMs);
}
/**
- * Setup the GDCP fields on the page
- * Determines if the required fields are present for a channel and creates the GDCP field
- * Hides the EN opt in fields for the GDCP field
+ * Replace the `src` of every iframe inside `.modal--bequest` with
+ * `about:blank` (aborting any in-flight load) and stash the original
+ * URL on `data-deferred-src` so it can be restored when the modal
+ * is about to be shown. Called in the constructor.
*/
- async setupGdcpFields() {
- for (const gdcpField of this.gdcpFields) {
- const enFieldsAreOnPage = await this.enFieldsForGdcpFieldOnPage(gdcpField);
- if (enFieldsAreOnPage) {
- this.gdcpFieldManager.addField(gdcpField);
- this.hideEnOptInFields(gdcpField);
- if (!this.singleOptInMode) {
- this.logger.log(`Creating GDCP field for "${gdcpField.channel}"`);
- this.createGdcpField(gdcpField);
- }
- } else {
- this.logger.log(`Did not find the required fields for channel "${gdcpField.channel}" - "${gdcpField.dataFieldName}" and any of opt in field(s) "${gdcpField.optInFieldNames.join(", ")}". Skipping adding GDCP field for this channel to page.`);
- }
- }
- if (this.singleOptInMode && this.gdcpFieldManager.getFields().size > 0) {
- this.logger.log("Single Opt-In mode is active, creating checkbox");
- this.createSingleOptInCheckbox();
- }
- }
- hideEnOptInFields(gdcpField) {
- gdcpField.optInFieldNames.forEach(name => {
- const input = document.querySelector(`[name="${name}"]`);
- input?.closest(".en__field")?.classList.add("hide");
+ defuseModalIframes() {
+ const iframes = this.modalContent?.querySelectorAll("iframe[src]");
+ if (!iframes || iframes.length === 0) return;
+ iframes.forEach(iframe => {
+ const src = iframe.getAttribute("src");
+ if (!src || src === "about:blank") return;
+ iframe.dataset.deferredSrc = src;
+ iframe.setAttribute("src", "about:blank");
+ this.logger.log(`Defused iframe load: ${src}`);
});
}
/**
- * Creates the GDCP field element and adds it to the page
- * Also adds an event listener to toggle all the opt in fields when the GDCP field is checked/unchecked
+ * Restore the original `src` on every iframe previously defused by
+ * `defuseModalIframes`. Called immediately before each `open()` call
+ * site in `openWhenSafe()`. After this runs the iframe begins
+ * loading normally and the user can interact with it as they would
+ * have before the queue refactor.
+ *
+ * We scope the query through the document (not `this.modalContent`)
+ * because `addModal()` moves the modal element into a wrapper, so
+ * the iframes now live under `.engrid-modal__body`.
*/
- createGdcpField(gdcpField) {
- // @ts-ignore
- const fieldHtmlLabel = window.pageJson.locale.startsWith("es") ? gdcpField.gdcpFieldHtmlLabelEs : gdcpField.gdcpFieldHtmlLabel;
- const field = `
-
-
-
-
-
- ${fieldHtmlLabel}
-
-
-
-
- ${fieldHtmlLabel}
-
-
-
-
`;
- const formElement = document.querySelector(`[name="${gdcpField.dataFieldName}"]`)?.closest(".en__field");
- if (formElement) {
- formElement.insertAdjacentHTML("beforeend", field);
+ armModalIframes() {
+ const iframes = document.querySelectorAll(".engrid-modal__body iframe[data-deferred-src]");
+ if (iframes.length === 0) return;
+ iframes.forEach(iframe => {
+ const src = iframe.dataset.deferredSrc;
+ if (!src) return;
+ iframe.setAttribute("src", src);
+ delete iframe.dataset.deferredSrc;
+ this.logger.log(`Armed iframe load: ${src}`);
+ });
+ }
+ shouldRun() {
+ if (this.modalContent && !this.bequestUserProfile) {
+ this.logger.log("Bequest modal found, but no user profile found. Please add the User Profile Script.");
}
- const input = document.querySelector(`[name="${gdcpField.gdcpFieldName}"]`);
- if (input) {
- input.addEventListener("change", () => {
- this.gdcpFieldManager.setChecked(gdcpField.gdcpFieldName, input.checked, true);
- this.gdcpFieldManager.setTouched(gdcpField.gdcpFieldName);
- });
+ return !!this.modalContent && !!this.bequestUserProfile;
+ }
+ shouldOpen() {
+ if (this.modalContent?.classList.contains("modal--always-open")) {
+ this.logger.log("Opening bequest modal. Always open trigger found.");
+ return true;
}
- return input;
+ if (this.lessRestrictiveTrigger()) {
+ this.logger.log("Opening bequest modal. Less restrictive trigger found.");
+ return true;
+ }
+ if (this.strictTrigger()) {
+ this.logger.log("Opening bequest modal. Strict trigger found.");
+ return true;
+ }
+ this.logger.log("Not opening bequest modal. No conditions met.");
+ return false;
}
+ logConditions() {
+ // prettier-ignore
+ this.logger.log(`country: ${this.pageJson?.country}
+ amount: ${this.pageJson?.amount}
+ doNotSendSolicitations: ${this.bequestUserProfile?.doNotSendSolicitations}
+ crmConstituency: ${this.bequestUserProfile?.crmConstituency}
+ plannedGiftProspect: ${this.bequestUserProfile?.plannedGiftProspect}
+ totalNumberOfGifts: ${this.bequestUserProfile?.totalNumberOfGifts}
+ includeInPlannedGivingSolicitations: ${this.bequestUserProfile?.includeInPlannedGivingSolicitations}
+ bequest_lb_select: ${this.getCookie("bequest_lb_select")}
+ gp_form_submitted: ${this.getCookie("gp_form_submitted")}
+ per_gp: ${this.getCookie("per_gp")}
+ gp_email: ${this.getCookie("gp_email")}`);
- /**
- * Check if the corresponding EN fields are present on the page
- * for a given GDCP Opt In Field
- * i.e. Its data field + any of the opt in fields
- */
- async enFieldsForGdcpFieldOnPage(gdcpField) {
- const dataFieldPresent = document.querySelector(`[name="${gdcpField.dataFieldName}"]`);
- if (!dataFieldPresent) {
- return false;
+ // prettier-ignore
+ this.logger.log(`country: ${this.pageJson?.country} = ${this.pageJson?.country === "US"}
+ doNotSendSolicitations: ${this.bequestUserProfile?.doNotSendSolicitations} === "Y" = ${this.bequestUserProfile?.doNotSendSolicitations === "Y"}
+ crmConstituency: ${this.bequestUserProfile?.crmConstituency} includes "Legacy Club" = ${this.bequestUserProfile?.crmConstituency?.includes("Legacy Club")}
+ amount: ${this.pageJson?.amount} >= 100 = ${this.pageJson?.amount >= 100}
+ bequest_lb_select: ${this.getCookie("bequest_lb_select")} = ${this.getCookie("bequest_lb_select")}
+ gp_form_submitted: ${this.getCookie("gp_form_submitted")} = ${this.getCookie("gp_form_submitted")}
+ per_gp: ${this.getCookie("per_gp")} = ${this.getCookie("per_gp")}
+ gp_email: ${this.getCookie("gp_email")} = ${this.getCookie("gp_email")}
+ totalNumberOfGifts: ${this.bequestUserProfile?.totalNumberOfGifts} >= 3 = ${Number(this.bequestUserProfile?.totalNumberOfGifts) >= 3}
+ includeInPlannedGivingSolicitations: ${this.bequestUserProfile?.includeInPlannedGivingSolicitations} === "Y" = ${this.bequestUserProfile?.includeInPlannedGivingSolicitations === "Y"}
+ plannedGiftProspect: ${this.bequestUserProfile?.plannedGiftProspect} === "Y" = ${this.bequestUserProfile?.plannedGiftProspect === "Y"}`);
+ }
+ lessRestrictiveTrigger() {
+ if (this.modalContent?.classList.contains("modal--bequest-less-restrictive") && this.pageJson?.country === "US" && this.bequestUserProfile?.doNotSendSolicitations !== "Y" && !this.bequestUserProfile?.crmConstituency?.includes("Legacy Club") && !this.getCookie("bequest_lb_select") && !this.getCookie("gp_form_submitted")) {
+ this.logger.log("Less restrictive trigger passed condition");
+ return true;
}
- const optInFieldsNames = gdcpField.optInFieldNames.map(name => `[name="${name}"]`).join(", ");
- const optInFieldsPresent = document.querySelector(optInFieldsNames);
- if (gdcpField.channel !== "postal_mail" && gdcpField.channel !== "mobile_phone") {
- return !!dataFieldPresent && !!optInFieldsPresent;
+ return false;
+ }
+ strictTrigger() {
+ if (this.pageJson?.country === "US" && this.bequestUserProfile?.doNotSendSolicitations !== "Y" && !this.bequestUserProfile?.crmConstituency?.includes("Legacy Club") && this.pageJson?.amount >= 100 && !this.getCookie("bequest_lb_select") && !this.getCookie("gp_form_submitted")) {
+ this.logger.log("Strict trigger passed first condition");
+ if (this.getCookie("per_gp") === "true" || this.getCookie("gp_email") === "true" || Number(this.bequestUserProfile?.totalNumberOfGifts) >= 3 || this.bequestUserProfile?.includeInPlannedGivingSolicitations === "Y" || this.bequestUserProfile?.plannedGiftProspect === "Y") {
+ this.logger.log("Strict trigger passed second condition");
+ return true;
+ }
}
- if (gdcpField.channel === "postal_mail") {
- try {
- const postalMailOptInFieldPresent = await this.isPresentOnEmbeddedForm(this.pages.postal_mail_qcb, `#en__field_supporter_questions_1942219`);
- return !!dataFieldPresent && !!optInFieldsPresent && postalMailOptInFieldPresent;
- } catch (e) {
- this.logger.error("Error checking if opted into postal mail", e);
- return false;
+ return false;
+ }
+ addModal() {
+ document.body.insertAdjacentHTML("beforeend", ``);
+ document.querySelector(".engrid-modal .engrid-modal__body")?.appendChild(this.modalContent);
+ this.addEventListeners();
+ }
+ open() {
+ dist_engrid_ENGrid.setBodyData("modal", "open");
+ dist_engrid_ENGrid.setBodyData("bequest-lightbox", "open");
+ trackEvent("lightbox_impression", {
+ lightbox_name: "bequest"
+ });
+ }
+ addEventListeners() {
+ // Close event on top X
+ document.querySelector(".engrid-modal__close")?.addEventListener("click", () => {
+ this.close();
+ });
+
+ // Bounce scale when clicking outside of modal
+ document.querySelector(".engrid-modal__overlay")?.addEventListener("click", event => {
+ if (event.target === event.currentTarget) {
+ const modal = document.querySelector(".engrid-modal");
+ if (modal) {
+ modal.classList.remove("engrid-modal--scale");
+ void modal.clientWidth;
+ modal.classList.add("engrid-modal--scale");
+ }
}
+ });
+
+ // Close on "modal__close" click
+ const closeEls = document.querySelectorAll(".modal__close");
+ closeEls.forEach(el => {
+ el.addEventListener("click", () => {
+ this.close();
+ });
+ });
+
+ // Resize iframe on load
+ const iframe = document.querySelector(".engrid-modal__body iframe");
+ if (iframe) {
+ this.resizeIframe(iframe);
+ iframe.addEventListener("load", () => {
+ this.resizeIframe(iframe);
+ });
+ window.addEventListener("resize", () => {
+ this.resizeIframe(iframe);
+ });
}
- // mobile_phone
- try {
- const mobilePhoneOptInFieldPresent = await this.isPresentOnEmbeddedForm(this.pages.mobile_phone_qcbs, `#en__field_supporter_questions_848527, #en__field_supporter_questions_848528`);
- return !!dataFieldPresent && !!optInFieldsPresent && mobilePhoneOptInFieldPresent;
- } catch (e) {
- this.logger.error("Error checking if opted into mobile phone", e);
- return false;
+ // Listen for iframe submission message from iframe page 2, and close modal.
+ window.addEventListener("message", event => {
+ if (event.data === "iframeSubmitted") {
+ this.close();
+ trackEvent("lightbox_click", {
+ lightbox_name: "bequest"
+ });
+ }
+ });
+ }
+ close() {
+ dist_engrid_ENGrid.setBodyData("modal", "closed");
+ dist_engrid_ENGrid.setBodyData("bequest-lightbox", "closed");
+ }
+ resizeIframe(iframe) {
+ iframe.style.height = iframe.contentWindow?.document.body.scrollHeight + "px";
+ }
+ getCookie(cookieName) {
+ const name = `${cookieName}=`;
+ const decodedCookie = decodeURIComponent(document.cookie);
+ const cookieArray = decodedCookie.split(";");
+ for (let i = 0; i < cookieArray.length; i++) {
+ let cookie = cookieArray[i];
+ while (cookie.charAt(0) === " ") {
+ cookie = cookie.substring(1);
+ }
+ if (cookie.indexOf(name) === 0) {
+ return cookie.substring(name.length, cookie.length);
+ }
}
+ return null;
}
+}
+// EXTERNAL MODULE: ./node_modules/tippy.js/dist/tippy.esm.js + 54 modules
+var tippy_esm = __webpack_require__(9244);
+;// CONCATENATED MODULE: ./src/scripts/tooltip.ts
- /*
- * Check if a given element is present on an embedded form (iframe)
- */
- async isPresentOnEmbeddedForm(pageUrl, selector) {
- const iframe = this.createChainedIframeForm(pageUrl);
- await new Promise((resolve, reject) => {
- iframe.addEventListener("load", resolve);
- iframe.addEventListener("error", reject);
+
+class Tooltip {
+ constructor() {
+ _defineProperty(this, "Els", void 0);
+ this.Els = document.querySelectorAll("[data-engrid-tooltip]");
+ if (!this.shouldRun()) return;
+ this.addTooltips();
+ }
+ shouldRun() {
+ return this.Els.length > 0;
+ }
+ addTooltips() {
+ this.Els.forEach(el => {
+ const content = el.getAttribute("data-engrid-tooltip");
+ const trigger = el.getAttribute("data-engrid-tooltip-trigger") || "click";
+ if (!content) return;
+ (0,tippy_esm/* default */.Ay)(el, {
+ content: content,
+ theme: "light-border",
+ allowHTML: true,
+ trigger: trigger,
+ hideOnClick: "toggle"
+ });
});
- const iframeDocument = iframe.contentDocument || iframe.contentWindow?.document;
- let elementInIframe = iframeDocument?.querySelector(selector);
- return !!elementInIframe;
}
+}
+;// CONCATENATED MODULE: ./src/scripts/ihmo.ts
- /**
- * Apply the opt in rules for the user's location
- * @param location The user's location
- * @param scrollToChangedField Whether to scroll to the field highest up the page that has changed state
- */
- applyRulesForLocation(location, scrollToChangedField = true) {
- const {
- checkedStateChangedFields
- } = this.ruleHandler.applyOptInRules(location);
- if (scrollToChangedField) {
- this.scrollUpToHighestChangedField(checkedStateChangedFields);
+
+class IHMO {
+ constructor() {
+ _defineProperty(this, "giftType", "HONORARY");
+ _defineProperty(this, "giftNotification", "ECARD");
+ _defineProperty(this, "formLayouts", {
+ HONORARY: {
+ ECARD: {
+ topFields: [".en__field--honname", ".en__field--othamt2"],
+ bottomFields: [".en__field--infemail"]
+ },
+ MAIL: {
+ topFields: [".en__field--honname", ".en__field--othamt2"],
+ bottomFields: [".en__field--NOT_TAGGED_38", ".en__field--NOT_TAGGED_33", ".en__field--NOT_TAGGED_34", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35", ".en__field--NOT_TAGGED_37"]
+ },
+ NONE: {
+ topFields: [".en__field--honname", ".en__field--othamt2"],
+ bottomFields: []
+ }
+ },
+ MEMORIAL: {
+ ECARD: {
+ topFields: [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35"],
+ bottomFields: [".en__field--infname", ".en__field--othamt3", ".en__field--infemail"]
+ },
+ MAIL: {
+ topFields: [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35"],
+ bottomFields: [".en__field--infname", ".en__field--othamt3", ".en__field--infcountry", ".en__field--infadd1", ".en__field--infadd2", ".en__field--infcity", ".en__field--infreg", ".en__field--infpostcd"]
+ },
+ NONE: {
+ topFields: [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35"],
+ bottomFields: []
+ }
+ }
+ });
+ _defineProperty(this, "ihmoCheckbox", document.querySelector('[name="transaction.inmem"][type="checkbox"]'));
+ _defineProperty(this, "topForm", document.querySelector(".ihmo-top-form"));
+ _defineProperty(this, "bottomForm", document.querySelector(".ihmo-bottom-form"));
+ _defineProperty(this, "_donationFrequency", DonationFrequency.getInstance());
+ _defineProperty(this, "sourceCodeField", document.querySelector('[name="supporter.appealCode"]'));
+ // If we're on the thank you page, add the gift details as data attributes and return
+ if (this.onThankYouPage()) {
+ this.setGiftDetailsAsDataAttributes();
+ return;
+ }
+ // Stop here if we're not on an IHMO page
+ if (!this.shouldRun()) return;
+ this.createPageLayout();
+ this.configureForm(this.giftType, this.giftNotification);
+ this.addEventListeners();
+ this.hideAllFields();
+ this.setDefaultSourceCodes();
+ // If IHMO is checked, save the gift details and set the source code
+ if (this.ihmoCheckbox?.checked) {
+ this.saveGiftDetails();
+ this.setSourceCode(this.giftType);
+ }
+ }
+ shouldRun() {
+ return !!this.ihmoCheckbox;
+ }
+ onThankYouPage() {
+ return sessionStorage.getItem("engrid_ihmo-gift-details") !== null && engrid_ENGrid.getPageNumber() === 2;
+ }
+ createPageLayout() {
+ const ihmoWrapper = document.createElement("div");
+ ihmoWrapper.classList.add("engrid--ihmo-wrapper", "ihmo-closed");
+
+ // Add all elements with the class "ihmo-content" to the IHMO content wrapper
+ const ihmoContent = document.querySelectorAll(".ihmo-content");
+ ihmoContent.forEach(content => {
+ ihmoWrapper.appendChild(content);
+ });
+
+ // Insert the IHMO content wrapper after the IHMO checkbox
+ this.ihmoCheckbox?.closest(".en__component--formblock")?.insertAdjacentElement("afterend", ihmoWrapper);
+
+ // If the page includes the embedded ecard component, move it to the IHMO content wrapper
+ const embeddedEcard = document.querySelector(".engrid--embedded-ecard");
+ if (embeddedEcard) {
+ embeddedEcard.classList.add("ihmo-content");
+ const ecardAnchor = document.querySelector(".en__field--select-notification-option")?.closest(".en__component--formblock");
+ if (ecardAnchor) {
+ ecardAnchor.insertAdjacentElement("afterend", embeddedEcard);
+ }
+ const ecardIframe = embeddedEcard.querySelector("iframe");
+ if (ecardIframe) {
+ // Extra URL param on eCard does additional functionality for IHMO page.
+ ecardIframe.setAttribute("src", ecardIframe.src + "&data-engrid-embedded-ihmo=true");
+ }
}
+ engrid_ENGrid.setBodyData("ihmo", "true");
}
+ addEventListeners() {
+ // When "This gift is in honor or memory of someone" checkbox is changed
+ this.ihmoCheckbox?.addEventListener("change", e => {
+ const checkbox = e.target;
+ if (checkbox.checked) {
+ document.querySelector(".engrid--ihmo-wrapper")?.classList.remove("ihmo-closed");
+ this.configureForm(this.giftType, this.giftNotification);
+ this.saveGiftDetails();
+ this.setSourceCode(this.giftType);
+ } else {
+ document.querySelector(".engrid--ihmo-wrapper")?.classList.add("ihmo-closed");
+ this.displayEcard(false);
+ this.hideAllFields();
+ this.clearGiftDetails();
+ this.setSourceCode(false);
+ }
+ });
- /**
- * Scroll to the field highest up the page that has changed state
- */
- scrollUpToHighestChangedField(checkedStateChangedFields) {
- if (checkedStateChangedFields.length) {
- // Only rules that have a visible checkbox
- const visibleFields = checkedStateChangedFields.filter(field => {
- const gdcpField = this.gdcpFieldManager.getField(field.gdcpFieldName);
- return gdcpField?.visible;
+ // When the "Gift Type" radio button is changed
+ document.getElementsByName("transaction.trbopts").forEach(el => {
+ el.addEventListener("change", e => {
+ const radio = e.target;
+ const giftType = radio.value === "In Honor" ? "HONORARY" : "MEMORIAL";
+ this.configureForm(giftType, this.giftNotification);
+ this.saveGiftDetails();
+ this.setSourceCode(giftType);
});
+ });
- // Get the DOM element of the data field of the field highest up the page
- const firstChangedField = visibleFields.map(field => {
- return document.querySelector(`[name="${field.dataFieldName}"]`)?.closest(".en__field");
- }).filter(el => el).reduce((a, b) => {
- return a?.getBoundingClientRect().top < b?.getBoundingClientRect().top ? a : b;
+ // When the "Select Notification option" radio button is changed
+ document.getElementsByName("supporter.questions.1381061").forEach(el => {
+ el.addEventListener("change", e => {
+ const radio = e.target;
+ let giftNotification;
+ if (radio.value === "Send an ecard") {
+ giftNotification = "ECARD";
+ } else if (radio.value === "Notify by mail") {
+ giftNotification = "MAIL";
+ } else {
+ giftNotification = "NONE";
+ }
+ this.configureForm(this.giftType, giftNotification);
+ this.saveGiftDetails();
});
- if (firstChangedField) {
- const fieldTop = firstChangedField.getBoundingClientRect().top + window.scrollY;
- // Only scroll if the field is above the current scroll position
- if (fieldTop < window.scrollY) {
- firstChangedField.scrollIntoView({
- behavior: "smooth"
- });
+ });
+ const firstNameField = document.getElementById("en__field_transaction_infname");
+ const lastNameField = document.getElementById("en__field_transaction_othamt3");
+ const emailField = document.getElementById("en__field_transaction_infemail");
+ const honorFirstNameField = document.getElementById("en__field_transaction_honname");
+ const honorLastNameField = document.getElementById("en__field_transaction_othamt2");
+ const ecardIframe = document.querySelector(".engrid-iframe--embedded-ecard");
+
+ // Setting the recipient name and email in the ecard iframe
+ [firstNameField, lastNameField, emailField, honorFirstNameField, honorLastNameField].forEach(field => {
+ field.addEventListener("input", () => {
+ const fullName = this.giftType === "HONORARY" ? `${honorFirstNameField.value} ${honorLastNameField.value}` : `${firstNameField.value} ${lastNameField.value}`;
+ ecardIframe.contentWindow?.postMessage({
+ action: "set_recipient",
+ name: fullName,
+ email: emailField.value
+ }, location.origin);
+ });
+ });
+
+ //Hiding the IHMO section when monthly donation is selected
+ // Listen for changes to the donation frequency and amount
+ this._donationFrequency.onFrequencyChange.subscribe(frequency => {
+ if (frequency !== "onetime") {
+ // Hide the IHMO section, hide the fields to prevent validation errors
+ // Disable ecard to prevent it being sent
+ document.querySelectorAll(".ihmo-element").forEach(el => {
+ el.classList.add("hide");
+ });
+ document.querySelector(".engrid--ihmo-wrapper")?.classList.add("ihmo-closed");
+ this.displayEcard(false);
+ this.hideAllFields();
+ this.hideField(".en__field--inmem");
+ } else {
+ // Make IHMO elements visible
+ document.querySelectorAll(".ihmo-element").forEach(el => {
+ el.classList.remove("hide");
+ });
+ this.showField(".en__field--inmem");
+ if (this.ihmoCheckbox?.checked) {
+ // Don't call "configureForm" unless the IHMO checkbox is checked, otherwise we might get validation errors
+ this.configureForm(this.giftType, this.giftNotification);
+ document.querySelector(".engrid--ihmo-wrapper")?.classList.remove("ihmo-closed");
}
}
+ });
+
+ // When gift designation changes, update the source code
+ if (this.sourceCodeField?.tagName === "SELECT") {
+ this.sourceCodeField?.addEventListener("change", () => {
+ const sourceCodeType = this.ihmoCheckbox?.checked ? this.giftType : false;
+ this.setSourceCode(sourceCodeType);
+ });
}
}
-
- /**
- * Add a consent statement below the submit button for existing supporters
- */
- addConsentStatementForExistingSupporters() {
- if (engrid_ENGrid.getFieldValue("supporter.emailAddress") && !this.submissionFailed) {
- const submitButtonBlock = document.querySelector(".en__submit")?.parentElement;
- const consentStatement = `
-
-
- You previously provided your communication preferences. If you wish to change those preferences, please
- click here .
-
-
- `;
- submitButtonBlock?.insertAdjacentHTML("afterend", consentStatement);
+ configureForm(giftType, notificationType) {
+ this.giftType = giftType;
+ this.giftNotification = notificationType;
+ this.setFormLayout();
+ this.setFormHeadings();
+ this.setFieldLabels();
+ this.displayEcard(this.giftNotification === "ECARD" && this.ihmoCheckbox?.checked);
+ }
+ saveGiftDetails() {
+ const giftDetails = {
+ giftType: this.giftType,
+ giftNotification: this.giftNotification
+ };
+ sessionStorage.setItem("engrid_ihmo-gift-details", JSON.stringify(giftDetails));
+ this.setGiftDetailsAsDataAttributes();
+ }
+ clearGiftDetails() {
+ sessionStorage.removeItem("engrid_ihmo-gift-details");
+ this.setGiftDetailsAsDataAttributes();
+ }
+ setGiftDetailsAsDataAttributes() {
+ const giftDetails = sessionStorage.getItem("engrid_ihmo-gift-details");
+ if (!giftDetails) {
+ engrid_ENGrid.setBodyData("ihmo-gift-type", false);
+ engrid_ENGrid.setBodyData("ihmo-gift-notification", false);
+ return;
}
+ const {
+ giftType,
+ giftNotification
+ } = JSON.parse(giftDetails);
+ engrid_ENGrid.setBodyData("ihmo-gift-type", giftType);
+ engrid_ENGrid.setBodyData("ihmo-gift-notification", giftNotification);
}
+ setSourceCode(giftType) {
+ if (!this.sourceCodeField) return;
- /**
- * Get the value of a cookie by name
- */
- getCookie(cookieName) {
- const name = `${cookieName}=`;
- const decodedCookie = decodeURIComponent(document.cookie);
- const cookieArray = decodedCookie.split(";");
- for (let i = 0; i < cookieArray.length; i++) {
- let cookie = cookieArray[i];
- while (cookie.charAt(0) === " ") {
- cookie = cookie.substring(1);
- }
- if (cookie.indexOf(name) === 0) {
- return cookie.substring(name.length, cookie.length);
+ // If source code overriding is disabled, return early
+ if (window.EngridDisableIhmoSourceCodeOverriding && window.EngridDisableIhmoSourceCodeOverriding === true) {
+ return;
+ }
+ const sourceCodeContainer = this.sourceCodeField instanceof HTMLSelectElement ? this.sourceCodeField.options[this.sourceCodeField.selectedIndex] : this.sourceCodeField;
+ if (sourceCodeContainer.value === "AHOMAONLN21W0XXX01" && this.sourceCodeField instanceof HTMLSelectElement) {
+ // if "use my gift where it's needed most" option is selected, do not change the source code"
+ return;
+ }
+
+ // Determine the part of the source code to replace and the replacement value
+ const isUS = this.isUSState(sourceCodeContainer.value);
+ const endIndex = sourceCodeContainer.value.length;
+ let target, replacement;
+ if (giftType === "HONORARY" || giftType === "MEMORIAL") {
+ if (isUS) {
+ target = sourceCodeContainer.value.substring(endIndex - 6);
+ replacement = giftType === "HONORARY" ? "TRIHXX" : "TRIMXX";
+ } else {
+ target = sourceCodeContainer.value.substring(endIndex - 6, endIndex - 2);
+ replacement = giftType === "HONORARY" ? "TRIH" : "TRIM";
}
+ sourceCodeContainer.value = sourceCodeContainer.value.replace(target, replacement);
+ } else {
+ // Reset to default if not honorary or memorial
+ sourceCodeContainer.value = sourceCodeContainer.getAttribute("data-default-source-code") || "";
}
- return null;
+ engrid_ENGrid.setBodyData("source-code", this.sourceCodeField.value);
}
-
- /**
- * Actions for when EN form is submitted
- * @private
- */
- onSubmit() {
- this._form.onSubmit.subscribe(() => {
- // Save the GDCP fields state to session (for restoring in case of submission errors)
- this.gdcpFieldManager.saveStateToSession();
+ setFormLayout() {
+ const formLayout = this.formLayouts[this.giftType][this.giftNotification];
+ // Add fields to the top form section
+ formLayout.topFields.forEach(field => {
+ const el = document.querySelector(field);
+ if (el) {
+ this.topForm?.appendChild(el);
+ this.showField(el);
+ }
});
- }
- /**
- * Restore the state of the GDCP + Opt In fields from session storage
- * Used when the submission fails, instead of applying location-based rules again.
- */
- restoreFieldsStateFromSession() {
- this.logger.log("Detected submission failure. Restoring GDCP + Opt In field states.");
- this.gdcpFieldManager.applyStateFromSession();
- }
+ // Add fields to the bottom form section
+ formLayout.bottomFields.forEach(field => {
+ const el = document.querySelector(field);
+ if (el) {
+ this.bottomForm?.appendChild(el);
+ this.showField(el);
+ }
+ });
- /**
- * Clear the session storage state
- * @private
- */
- clearSessionState() {
- this.gdcpFieldManager.clearStateFromSession();
- }
+ // Hide unused fields in the top form section
+ const topFormFields = this.topForm?.children || [];
+ [...topFormFields].forEach(el => {
+ const classList = Array.from(el.classList);
+ const isActiveField = formLayout.topFields.some(field => classList.includes(field.slice(1)));
+ if (!isActiveField) {
+ this.hideField(el);
+ }
+ });
- /**
- * Send double opt in email if the user has opted in and the page is not the first page
- */
- handleDoubleOptInEmail() {
- const sessionData = JSON.parse(sessionStorage.getItem("gdcp-email-double-opt-in") || "{}");
- const shouldSendDoubleOptInEmail = sessionData.page && sessionData.page !== window.location.pathname && !this.submissionFailed;
- if (shouldSendDoubleOptInEmail) {
- // Set timeout because EN does not work properly if multiple forms are submitted in quick succession
- setTimeout(() => {
- const iframe = this.createChainedIframeForm(this.pages.double_opt_in_email_trigger, true);
- sessionStorage.removeItem("gdcp-email-double-opt-in");
- this.logger.log(`Sending double opt in email using form: ${iframe.getAttribute("src")}`);
- }, 1000);
- }
+ // Hide unused fields in the bottom form section
+ const bottomFormFields = this.bottomForm?.children || [];
+ [...bottomFormFields].forEach(el => {
+ const classList = Array.from(el.classList);
+ const isActiveField = formLayout.bottomFields.some(field => classList.includes(field.slice(1)));
+ if (!isActiveField) {
+ this.hideField(el);
+ }
+ });
}
-
- /**
- * Send QCB for postal mail if we have the session data to do that
- */
- handlePostalMailQcb() {
- const sessionData = JSON.parse(sessionStorage.getItem("gdcp-postal-mail-create-qcb") || "{}");
- const shouldCreateQcb = sessionData.page && sessionData.page !== window.location.pathname && !this.submissionFailed;
- if (shouldCreateQcb) {
- let url = this.pages.postal_mail_qcb;
- if (sessionData.state === "N") {
- url += "?supporter.questions.1942219=N";
+ setFormHeadings() {
+ const headings = document.querySelectorAll(".form-heading.ihmo-content h3");
+ if (headings.length === 0) return;
+ const firstHeading = headings[0];
+ const lastHeading = headings[headings.length - 1];
+ if (!firstHeading || !lastHeading) return;
+ if (this.giftType === "HONORARY") {
+ firstHeading.textContent = "PERSON TO BE HONORED";
+ lastHeading.textContent = "HONOREE'S PERSONAL INFORMATION";
+ if (this.giftNotification === "ECARD" || this.giftNotification === "NONE") {
+ lastHeading.closest(".form-heading")?.classList.add("hide");
+ } else {
+ lastHeading.closest(".form-heading")?.classList.remove("hide");
+ }
+ } else {
+ firstHeading.textContent = "PERSON TO BE REMEMBERED";
+ lastHeading.textContent = "PERSON TO BE NOTIFIED";
+ if (this.giftNotification === "NONE") {
+ lastHeading.closest(".form-heading")?.classList.add("hide");
+ } else {
+ lastHeading.closest(".form-heading")?.classList.remove("hide");
}
- // Set timeout because EN does not work properly if multiple forms are submitted in quick succession
- setTimeout(() => {
- const iframe = this.createChainedIframeForm(url, true);
- sessionStorage.removeItem("gdcp-postal-mail-create-qcb");
- this.logger.log(`Creating QCB for postal mail using form: ${iframe.getAttribute("src")}`);
- }, 3500);
}
}
-
- /**
- * Create an iframe form with autosubmit form
- */
- createChainedIframeForm(urlString, autoSubmit = false) {
- const url = new URL(urlString);
- url.searchParams.append("chain", "");
- if (autoSubmit) {
- url.searchParams.append("autosubmit", "Y");
+ setFieldLabels() {
+ const firstNameFieldLabel = document.querySelector(".en__field--honname > label");
+ const lastNameFieldLabel = document.querySelector(".en__field--othamt2 > label");
+ const cityFieldLabel = document.querySelector(".en__field--NOT_TAGGED_36 > label");
+ const stateFieldLabel = document.querySelector(".en__field--NOT_TAGGED_35 > label");
+ if (!firstNameFieldLabel || !lastNameFieldLabel || !cityFieldLabel || !stateFieldLabel) {
+ return;
+ }
+ if (this.giftType === "HONORARY") {
+ firstNameFieldLabel.textContent = "Honoree First Name";
+ lastNameFieldLabel.textContent = "Honoree Last Name";
+ cityFieldLabel.textContent = "Honoree City";
+ stateFieldLabel.textContent = "Honoree State";
+ } else {
+ firstNameFieldLabel.textContent = "Deceased Person's First Name";
+ lastNameFieldLabel.textContent = "Deceased Person's Last Name";
+ cityFieldLabel.textContent = "Deceased Person's City";
+ stateFieldLabel.textContent = "Deceased Person's State";
}
- const iframe = document.createElement("iframe");
- iframe.src = url.toString();
- iframe.style.display = "none";
- document.body.appendChild(iframe);
- return iframe;
}
-
- /**
- * Create a single opt in checkbox for the page
- */
- createSingleOptInCheckbox() {
- const field = `
- `;
- const formElement = document.querySelector(".en__submit");
- if (formElement) {
- formElement.closest(".en__component--formblock")?.insertAdjacentHTML("beforebegin", field);
+ displayEcard(show = true) {
+ const eCardCheckbox = document.getElementById("en__field_embedded-ecard");
+ eCardCheckbox.checked = show;
+ eCardCheckbox.dispatchEvent(new Event("change"));
+ }
+ hideAllFields() {
+ [".en__field--honname", ".en__field--othamt2", ".en__field--NOT_TAGGED_36", ".en__field--NOT_TAGGED_35", ".en__field--infname", ".en__field--othamt3", ".en__field--infcountry", ".en__field--infadd1", ".en__field--infadd2", ".en__field--infcity", ".en__field--infreg", ".en__field--infpostcd", ".en__field--infemail", ".en__field--NOT_TAGGED_38", ".en__field--NOT_TAGGED_33", ".en__field--NOT_TAGGED_34", ".en__field--NOT_TAGGED_37"].forEach(field => {
+ this.hideField(field);
+ });
+ }
+ hideField(field) {
+ const el = field instanceof Element ? field : document.querySelector(field);
+ if (el) {
+ const identifier = [...el.classList].find(c => c.match(/en__field--\d+/))?.replace("en__field--", "");
+ if (identifier) {
+ window.EngagingNetworks.require._defined.enjs.hideField(identifier);
+ }
}
- const input = document.querySelector(`[name="engrid.gdcp-single-opt-in"]`);
- if (input) {
- input.addEventListener("change", () => {
- this.gdcpFields.forEach(gdcpField => {
- this.gdcpFieldManager.setChecked(gdcpField.gdcpFieldName, input.checked, true);
- this.gdcpFieldManager.setTouched(gdcpField.gdcpFieldName);
- });
- });
+ }
+ showField(field) {
+ const el = field instanceof Element ? field : document.querySelector(field);
+ if (el) {
+ const identifier = [...el.classList].find(c => c.match(/en__field--\d+/))?.replace("en__field--", "");
+ if (identifier) {
+ window.EngagingNetworks.require._defined.enjs.showField(identifier);
+ }
}
- return input;
}
- /**
- * Set the initial state of the GDCP fields to unchecked in single opt in mode
- * Set them to touched so that any location rule change won't modify the checked state
- * We still want the location based rules to apply so we have the double opt in and no qcb rules
+ /*
+ * Set the default source codes as a data attribute
*/
- setSingleOptInModeInitialState() {
- if (this.singleOptInMode && !this.submissionFailed) {
- this.logger.log("Single Opt-In Mode - Setting all opt-ins to unchecked as initial state.");
- this.gdcpFields.forEach(gdcpField => {
- this.gdcpFieldManager.setChecked(gdcpField.gdcpFieldName, false, true);
- this.gdcpFieldManager.setTouched(gdcpField.gdcpFieldName);
- });
- }
- }
- createMobilePhoneSessionStorageListener() {
- const gdcpFieldName = this.gdcpFields.find(field => field.channel === "mobile_phone")?.gdcpFieldName;
- const mobilePhoneGdcpField = engrid_ENGrid.getField(gdcpFieldName || "");
- if (!mobilePhoneGdcpField) {
- // GDCP isn't enabled for mobile phone on this page
+ setDefaultSourceCodes() {
+ if (!this.sourceCodeField) return;
+ if (this.sourceCodeField instanceof HTMLInputElement) {
+ // If the source code field is an input, set the default source code as a data attribute
+ this.sourceCodeField.setAttribute("data-default-source-code", this.sourceCodeField.value);
return;
}
- const fields = [mobilePhoneGdcpField, engrid_ENGrid.getField("supporter.phoneNumber2"), engrid_ENGrid.getField("supporter.country")].filter(Boolean).flat();
- // Do an initial call to handle the current state (if pre-filled)
- this.setMobilePhoneSessionItem();
- fields.forEach(field => {
- field?.addEventListener("change", this.setMobilePhoneSessionItem.bind(this));
+ // If the source code field is a select, set the default source code as a data attribute on each option
+ this.sourceCodeField.querySelectorAll("option").forEach(option => {
+ if (option && option.value) {
+ option.setAttribute("data-default-source-code", option.value);
+ }
});
}
- setMobilePhoneSessionItem() {
- const gdcpFieldName = this.gdcpFields.find(field => field.channel === "mobile_phone")?.gdcpFieldName;
- const checked = this.gdcpFieldManager.getField(gdcpFieldName || "")?.checked;
- if (engrid_ENGrid.getFieldValue("supporter.phoneNumber2") !== "" && engrid_ENGrid.getFieldValue("supporter.country") === "US") {
- sessionStorage.setItem("gdcp-mobile-phone-create-qcb", JSON.stringify({
- state: checked ? "Y" : "N",
- page: window.location.pathname
- }));
- this.logger.log(`Mobile Phone channel will create QCB with status: ${checked ? "Y" : "N"}`);
+ isUSState(source) {
+ const state = source.substring(1, 3);
+ return ["AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"].includes(state);
+ }
+}
+;// CONCATENATED MODULE: ./src/scripts/widget-progress-bar.ts
+
+
+class WidgetProgressBar {
+ constructor() {
+ _defineProperty(this, "logger", new logger_EngridLogger("WidgetProgressBar", "black", "yellow", "π«"));
+ _defineProperty(this, "widget", document.querySelector(".en__component--widgetblock"));
+ _defineProperty(this, "increase", 1.25);
+ _defineProperty(this, "threshold", 80);
+ if (!this.shouldRun()) {
+ this.logger.log("Not running");
+ return;
+ }
+ const widget = document.querySelector(".enWidget--progressBar");
+ if (widget && widget.querySelector(".raised-remaining")) {
+ this.logger.log("Widget found via querySelector");
+ this.run(widget);
} else {
- sessionStorage.removeItem("gdcp-mobile-phone-create-qcb");
- this.logger.log(`Mobile Phone channel missing required data, won't create a QCB`);
+ this.addMutationObserver();
}
}
-
- /**
- * Send QCB for Mobile Phone if we have the session data to do that
- */
- handleMobilePhoneQcb() {
- const sessionData = JSON.parse(sessionStorage.getItem("gdcp-mobile-phone-create-qcb") || "{}");
- const shouldCreateQcb = sessionData.page && sessionData.page !== window.location.pathname && !this.submissionFailed;
- if (shouldCreateQcb) {
- let url = new URL(this.pages.mobile_phone_qcbs);
- if (sessionData.state === "N") {
- // Don't create Negative QCBs
+ addMutationObserver() {
+ // Watch for changes to the widget, until an element with the class "enWidget--progressBar" is found
+ const observer = new MutationObserver(mutations => {
+ mutations.forEach(mutation => {
+ if (mutation.addedNodes.length && mutation.addedNodes[0].querySelector(".remaining")) {
+ observer.disconnect();
+ // There's an additional script that runs after the widget is added to the DOM, so we need to wait a bit before running our code
+ window.setTimeout(() => {
+ this.logger.log("Widget found via MutationObserver");
+ this.widget = document.querySelector(".enWidget--progressBar");
+ this.run(this.widget);
+ }, 150);
+ return;
+ }
+ });
+ });
+ observer.observe(this.widget, {
+ childList: true,
+ subtree: true
+ });
+ }
+ run(widget) {
+ const fill = widget.querySelector(".enWidget__fill");
+ const percentage = fill ? parseInt(fill.style.width, 10) : 0;
+ this.logger.log("Percentage", percentage);
+ if (percentage >= this.threshold) {
+ this.logger.log("Incrementing goal");
+ const supporters = parseInt(widget.querySelector(".raised > div")?.textContent?.replace(/\,/g, "") || "0");
+ const newGoal = Math.ceil(supporters * this.increase);
+ // If new goal is NaN, don't alter progress bar and bail here
+ if (isNaN(newGoal)) {
+ this.logger.log("Error: New goal is NaN, not altering progress bar");
return;
- // url.searchParams.append("supporter.questions.848527", "N");
- // url.searchParams.append("supporter.questions.848528", "N");
}
- // Set timeout because EN does not work properly if multiple forms are submitted in quick succession
- setTimeout(() => {
- const iframe = this.createChainedIframeForm(url.toString(), true);
- sessionStorage.removeItem("gdcp-mobile-phone-create-qcb");
- this.logger.log(`Creating QCB for Mobile Phone using form: ${iframe.getAttribute("src")}`);
- }, 3500);
+ // Reset fill width so that animation runs once new width is set
+ fill.style.width = "0";
+ const remainingElement = widget.querySelector(".remaining > div:first-child span");
+ if (remainingElement) {
+ remainingElement.textContent = (newGoal - supporters).toLocaleString();
+ }
+ this.logger.log("New goal", newGoal);
+ fill.style.width = `${supporters / newGoal * 100}%`;
}
}
+ shouldRun() {
+ return engrid_ENGrid.getPageType() !== "DONATION" && !!this.widget;
+ }
}
;// CONCATENATED MODULE: ./src/scripts/add-daf-banner.ts
@@ -30966,6 +52875,7 @@ class MultistepForm {
// App,
// DonationFrequency,
// DonationAmount,
+// IframeQueue,
// } from "../../engrid/packages/scripts"; // Uses ENGrid via Visual Studio Workspace
@@ -31047,6 +52957,16 @@ const options = {
if (App.getBodyData("subtheme") === "multistep" || App.getBodyData("subtheme") === "one-step-lightbox") {
new DonationLightboxForm(DonationAmount, DonationFrequency, App);
}
+ // Iframe Queue β opt-in ENgrid component. Constructed explicitly
+ // here so the singleton (and its embedded-mode `message` listener,
+ // active on the QCB iframe pages which load this same TNC bundle)
+ // is initialised deliberately, rather than relying on the lazy
+ // construction triggered by the first `IframeQueue.getInstance()`
+ // call elsewhere. Also where any declarative
+ // `window.EngridIframeQueue` config β if a page ever sets it β
+ // gets picked up. Position within onLoad is not significant for
+ // correctness; placed near the top by convention.
+ new IframeQueue();
new BequestLightbox();
new Tooltip();
new IHMO();
diff --git a/dist/engrid.min.css b/dist/engrid.min.css
index b0ed157..8efccb5 100644
--- a/dist/engrid.min.css
+++ b/dist/engrid.min.css
@@ -18,7 +18,7 @@
*
* ENGRID PAGE TEMPLATE ASSETS
*
- * Date: Wednesday, May 13, 2026 @ 02:46:15 ET
+ * Date: Thursday, May 14, 2026 @ 13:36:49 ET
* By: fernando
* ENGrid styles: v0.25.0
* ENGrid scripts: v0.25.2
diff --git a/dist/engrid.min.js b/dist/engrid.min.js
index 9702ad0..07a78b3 100644
--- a/dist/engrid.min.js
+++ b/dist/engrid.min.js
@@ -17,7 +17,7 @@
*
* ENGRID PAGE TEMPLATE ASSETS
*
- * Date: Wednesday, May 13, 2026 @ 02:46:15 ET
+ * Date: Thursday, May 14, 2026 @ 13:36:49 ET
* By: fernando
* ENGrid styles: v0.25.0
* ENGrid scripts: v0.25.2
@@ -34,7 +34,7 @@
*
* Copyright Kees C. Bakker / KeesTalksTech
* Released under the MIT license
- */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(8441);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(3309);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(8901);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(4004);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(1289);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(6442);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(6580);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(6436);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(3707);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const h=n(956);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return h.SubscriptionChangeEventDispatcher}})},1289:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},71:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventDispatcher=void 0;const i=n(4604);class o extends i.DispatcherBase{constructor(){super()}dispatch(e,t){const n=this._dispatch(!1,this,arguments);if(null==n)throw new i.DispatchError("Got `null` back from dispatch.");return n}dispatchAsync(e,t){this._dispatch(!0,this,arguments)}asEvent(){return super.asEvent()}}t.EventDispatcher=o},2162:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventHandlingBase=void 0;const i=n(4604),o=n(338);class s extends i.HandlingBase{constructor(){super(new o.EventList)}}t.EventHandlingBase=s},338:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventList=void 0;const i=n(4604),o=n(71);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.EventDispatcher}}t.EventList=s},2293:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NonUniformEventList=void 0;const i=n(71);t.NonUniformEventList=class{constructor(){this._events={}}get(e){if(this._events[e])return this._events[e];const t=this.createDispatcher();return this._events[e]=t,t}remove(e){delete this._events[e]}createDispatcher(){return new i.EventDispatcher}}},4214:(e,t,n)=>{"use strict";
+ */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(8441);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(3309);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(8901);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(4004);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(1289);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(6442);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(6580);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(6436);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(3707);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const p=n(956);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return p.SubscriptionChangeEventDispatcher}})},1289:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},71:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventDispatcher=void 0;const i=n(4604);class o extends i.DispatcherBase{constructor(){super()}dispatch(e,t){const n=this._dispatch(!1,this,arguments);if(null==n)throw new i.DispatchError("Got `null` back from dispatch.");return n}dispatchAsync(e,t){this._dispatch(!0,this,arguments)}asEvent(){return super.asEvent()}}t.EventDispatcher=o},2162:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventHandlingBase=void 0;const i=n(4604),o=n(338);class s extends i.HandlingBase{constructor(){super(new o.EventList)}}t.EventHandlingBase=s},338:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventList=void 0;const i=n(4604),o=n(71);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.EventDispatcher}}t.EventList=s},2293:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NonUniformEventList=void 0;const i=n(71);t.NonUniformEventList=class{constructor(){this._events={}}get(e){if(this._events[e])return this._events[e];const t=this.createDispatcher();return this._events[e]=t,t}remove(e){delete this._events[e]}createDispatcher(){return new i.EventDispatcher}}},4214:(e,t,n)=>{"use strict";
/*!
* Strongly Typed Events for TypeScript - Core
* https://github.com/KeesCBakker/StronlyTypedEvents/
@@ -59,7 +59,7 @@
* Copyright Kees C. Bakker / KeesTalksTech
* Released under the MIT license
*/
-t.UD=t.IL=void 0;var i=n(4604);var o=n(4214);var s=n(6569);Object.defineProperty(t,"IL",{enumerable:!0,get:function(){return s.SimpleEventDispatcher}});var r=n(5010);Object.defineProperty(t,"UD",{enumerable:!0,get:function(){return r.SignalDispatcher}});var a=n(606);var l=n(6042);var c=n(4225)},2995:()=>{!function(e,t){!function(e,t,n,i){function o(){}function s(n){var i=t.exports.Promise,s=void 0!==i?i:e.Promise;return"function"==typeof s?new s(n):(n(o,o),null)}var r,a,l,c,d,u=(l=Math.floor(1e3/60),c={},d=0,"function"==typeof requestAnimationFrame&&"function"==typeof cancelAnimationFrame?(r=function(e){var t=Math.random();return c[t]=requestAnimationFrame((function n(i){d===i||d+l-1{var i=n(7180),o=n(3181),s=n(3031),r=n(9067),a=n(6833),l=n(3717),c=n(4801);c.alea=i,c.xor128=o,c.xorwow=s,c.xorshift7=r,c.xor4096=a,c.tychei=l,e.exports=c},7180:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n=function(){var e=4022871197,t=function(t){t=t.toString();for(var n=0;n>>0,e=(i*=e)>>>0,e+=4294967296*(i-=e)}return 2.3283064365386963e-10*(e>>>0)};return t}();t.next=function(){var e=2091639*t.s0+2.3283064365386963e-10*t.c;return t.s0=t.s1,t.s1=t.s2,t.s2=e-(t.c=0|e)},t.c=1,t.s0=n(" "),t.s1=n(" "),t.s2=n(" "),t.s0-=n(e),t.s0<0&&(t.s0+=1),t.s1-=n(e),t.s1<0&&(t.s1+=1),t.s2-=n(e),t.s2<0&&(t.s2+=1),n=null}function r(e,t){return t.c=e.c,t.s0=e.s0,t.s1=e.s1,t.s2=e.s2,t}function a(e,t){var n=new s(e),i=t&&t.state,o=n.next;return o.int32=function(){return 4294967296*n.next()|0},o.double=function(){return o()+11102230246251565e-32*(2097152*o()|0)},o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.alea=a}(0,e=n.nmd(e),n.amdD)},3717:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n="";t.next=function(){var e=t.b,n=t.c,i=t.d,o=t.a;return e=e<<25^e>>>7^n,n=n-i|0,i=i<<24^i>>>8^o,o=o-e|0,t.b=e=e<<20^e>>>12^n,t.c=n=n-i|0,t.d=i<<16^n>>>16^o,t.a=o-e|0},t.a=0,t.b=0,t.c=-1640531527,t.d=1367130551,e===Math.floor(e)?(t.a=e/4294967296|0,t.b=0|e):n+=e;for(var i=0;i>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.tychei=a}(0,e=n.nmd(e),n.amdD)},3181:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n="";t.x=0,t.y=0,t.z=0,t.w=0,t.next=function(){var e=t.x^t.x<<11;return t.x=t.y,t.y=t.z,t.z=t.w,t.w^=t.w>>>19^e^e>>>8},e===(0|e)?t.x=e:n+=e;for(var i=0;i>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xor128=a}(0,e=n.nmd(e),n.amdD)},6833:function(e,t,n){var i;!function(e,o){function s(e){var t=this;t.next=function(){var e,n,i=t.w,o=t.X,s=t.i;return t.w=i=i+1640531527|0,n=o[s+34&127],e=o[s=s+1&127],n^=n<<13,e^=e<<17,n^=n>>>15,e^=e>>>12,n=o[s]=n^e,t.i=s,n+(i^i>>>16)|0},function(e,t){var n,i,o,s,r,a=[],l=128;for(t===(0|t)?(i=t,t=null):(t+="\0",i=0,l=Math.max(l,t.length)),o=0,s=-32;s>>15,i^=i<<4,i^=i>>>13,s>=0&&(r=r+1640531527|0,o=0==(n=a[127&s]^=i+r)?o+1:0);for(o>=128&&(a[127&(t&&t.length||0)]=-1),o=127,s=512;s>0;--s)i=a[o+34&127],n=a[o=o+1&127],i^=i<<13,n^=n<<17,i^=i>>>15,n^=n>>>12,a[o]=i^n;e.w=r,e.X=a,e.i=o}(t,e)}function r(e,t){return t.i=e.i,t.w=e.w,t.X=e.X.slice(),t}function a(e,t){null==e&&(e=+new Date);var n=new s(e),i=t&&t.state,o=function(){return(n.next()>>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&(i.X&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xor4096=a}(0,e=n.nmd(e),n.amdD)},9067:function(e,t,n){var i;!function(e,o){function s(e){var t=this;t.next=function(){var e,n,i=t.x,o=t.i;return e=i[o],n=(e^=e>>>7)^e<<24,n^=(e=i[o+1&7])^e>>>10,n^=(e=i[o+3&7])^e>>>3,n^=(e=i[o+4&7])^e<<7,e=i[o+7&7],n^=(e^=e<<13)^e<<9,i[o]=n,t.i=o+1&7,n},function(e,t){var n,i=[];if(t===(0|t))i[0]=t;else for(t=""+t,n=0;n0;--n)e.next()}(t,e)}function r(e,t){return t.x=e.x.slice(),t.i=e.i,t}function a(e,t){null==e&&(e=+new Date);var n=new s(e),i=t&&t.state,o=function(){return(n.next()>>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&(i.x&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xorshift7=a}(0,e=n.nmd(e),n.amdD)},3031:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n="";t.next=function(){var e=t.x^t.x>>>2;return t.x=t.y,t.y=t.z,t.z=t.w,t.w=t.v,(t.d=t.d+362437|0)+(t.v=t.v^t.v<<4^e^e<<1)|0},t.x=0,t.y=0,t.z=0,t.w=0,t.v=0,e===(0|e)?t.x=e:n+=e;for(var i=0;i>>4),t.next()}function r(e,t){return t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w,t.v=e.v,t.d=e.d,t}function a(e,t){var n=new s(e),i=t&&t.state,o=function(){return(n.next()>>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xorwow=a}(0,e=n.nmd(e),n.amdD)},4801:(e,t,n)=>{var i;!function(o,s){var r,a=(0,eval)("this"),l=256,c="random",d=s.pow(l,6),u=s.pow(2,52),h=2*u,p=l-1;function g(e,t,n){var i=[],p=y(b((t=1==t?{entropy:!0}:t||{}).entropy?[e,v(o)]:null==e?function(){try{var e;return r&&(e=r.randomBytes)?e=e(l):(e=new Uint8Array(l),(a.crypto||a.msCrypto).getRandomValues(e)),v(e)}catch(e){var t=a.navigator,n=t&&t.plugins;return[+new Date,a,n,a.screen,v(o)]}}():e,3),i),g=new m(i),_=function(){for(var e=g.g(6),t=d,n=0;e=h;)e/=2,t/=2,n>>>=1;return(e+n)/t};return _.int32=function(){return 0|g.g(4)},_.quick=function(){return g.g(4)/4294967296},_.double=_,y(v(g.S),o),(t.pass||n||function(e,t,n,i){return i&&(i.S&&f(i,g),e.state=function(){return f(g,{})}),n?(s[c]=e,t):e})(_,p,"global"in t?t.global:this==s,t.state)}function m(e){var t,n=e.length,i=this,o=0,s=i.i=i.j=0,r=i.S=[];for(n||(e=[n++]);o{n(7391);var i=n(2287);e.exports=i},2287:function(e){(function(){var t={};Math.seedrandom&&(seedrandom=Math.seedrandom);var n=function(e){return"[object Array]"===Object.prototype.toString.call(e)},i=function(e){return/(number|string)/i.test(Object.prototype.toString.call(e).match(/^\[object (.*)\]$/)[1])?e:isNaN(e)?Number(String(this.strSeed=e).split("").map((function(e){return e.charCodeAt(0)})).join("")):e},o=function(e,t,n){return Math.floor(e()*(n-t+1))+t};t.shuffle=function(e,t){if(!n(e))return null;t=i(t)||"none";for(var s=e.length,r=seedrandom(t),a=[],l=[],c=0;c{!function(){"use strict";e.exports={polyfill:function(){var e=window,t=document;if(!("scrollBehavior"in t.documentElement.style)||!0===e.__forceSmoothScrollPolyfill__){var n,i=e.HTMLElement||e.Element,o=468,s={scroll:e.scroll||e.scrollTo,scrollBy:e.scrollBy,elementScroll:i.prototype.scroll||l,scrollIntoView:i.prototype.scrollIntoView},r=e.performance&&e.performance.now?e.performance.now.bind(e.performance):Date.now,a=(n=e.navigator.userAgent,new RegExp(["MSIE ","Trident/","Edge/"].join("|")).test(n)?1:0);e.scroll=e.scrollTo=function(){void 0!==arguments[0]&&(!0!==c(arguments[0])?g.call(e,t.body,void 0!==arguments[0].left?~~arguments[0].left:e.scrollX||e.pageXOffset,void 0!==arguments[0].top?~~arguments[0].top:e.scrollY||e.pageYOffset):s.scroll.call(e,void 0!==arguments[0].left?arguments[0].left:"object"!=typeof arguments[0]?arguments[0]:e.scrollX||e.pageXOffset,void 0!==arguments[0].top?arguments[0].top:void 0!==arguments[1]?arguments[1]:e.scrollY||e.pageYOffset))},e.scrollBy=function(){void 0!==arguments[0]&&(c(arguments[0])?s.scrollBy.call(e,void 0!==arguments[0].left?arguments[0].left:"object"!=typeof arguments[0]?arguments[0]:0,void 0!==arguments[0].top?arguments[0].top:void 0!==arguments[1]?arguments[1]:0):g.call(e,t.body,~~arguments[0].left+(e.scrollX||e.pageXOffset),~~arguments[0].top+(e.scrollY||e.pageYOffset)))},i.prototype.scroll=i.prototype.scrollTo=function(){if(void 0!==arguments[0])if(!0!==c(arguments[0])){var e=arguments[0].left,t=arguments[0].top;g.call(this,this,void 0===e?this.scrollLeft:~~e,void 0===t?this.scrollTop:~~t)}else{if("number"==typeof arguments[0]&&void 0===arguments[1])throw new SyntaxError("Value could not be converted");s.elementScroll.call(this,void 0!==arguments[0].left?~~arguments[0].left:"object"!=typeof arguments[0]?~~arguments[0]:this.scrollLeft,void 0!==arguments[0].top?~~arguments[0].top:void 0!==arguments[1]?~~arguments[1]:this.scrollTop)}},i.prototype.scrollBy=function(){void 0!==arguments[0]&&(!0!==c(arguments[0])?this.scroll({left:~~arguments[0].left+this.scrollLeft,top:~~arguments[0].top+this.scrollTop,behavior:arguments[0].behavior}):s.elementScroll.call(this,void 0!==arguments[0].left?~~arguments[0].left+this.scrollLeft:~~arguments[0]+this.scrollLeft,void 0!==arguments[0].top?~~arguments[0].top+this.scrollTop:~~arguments[1]+this.scrollTop))},i.prototype.scrollIntoView=function(){if(!0!==c(arguments[0])){var n=function(e){for(;e!==t.body&&!1===h(e);)e=e.parentNode||e.host;return e}(this),i=n.getBoundingClientRect(),o=this.getBoundingClientRect();n!==t.body?(g.call(this,n,n.scrollLeft+o.left-i.left,n.scrollTop+o.top-i.top),"fixed"!==e.getComputedStyle(n).position&&e.scrollBy({left:i.left,top:i.top,behavior:"smooth"})):e.scrollBy({left:o.left,top:o.top,behavior:"smooth"})}else s.scrollIntoView.call(this,void 0===arguments[0]||arguments[0])}}function l(e,t){this.scrollLeft=e,this.scrollTop=t}function c(e){if(null===e||"object"!=typeof e||void 0===e.behavior||"auto"===e.behavior||"instant"===e.behavior)return!0;if("object"==typeof e&&"smooth"===e.behavior)return!1;throw new TypeError("behavior member of ScrollOptions "+e.behavior+" is not a valid value for enumeration ScrollBehavior.")}function d(e,t){return"Y"===t?e.clientHeight+a1?1:l,n=.5*(1-Math.cos(Math.PI*a)),i=t.startX+(t.x-t.startX)*n,s=t.startY+(t.y-t.startY)*n,t.method.call(t.scrollable,i,s),i===t.x&&s===t.y||e.requestAnimationFrame(p.bind(e,t))}function g(n,i,o){var a,c,d,u,h=r();n===t.body?(a=e,c=e.scrollX||e.pageXOffset,d=e.scrollY||e.pageYOffset,u=s.scroll):(a=n,c=n.scrollLeft,d=n.scrollTop,u=l),p({scrollable:a,method:u,startTime:h,startX:c,startY:d,x:i,y:o})}}}}()},1246:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NonUniformPromiseEventList=void 0;const i=n(2330);t.NonUniformPromiseEventList=class{constructor(){this._events={}}get(e){if(this._events[e])return this._events[e];const t=this.createDispatcher();return this._events[e]=t,t}remove(e){delete this._events[e]}createDispatcher(){return new i.PromiseEventDispatcher}}},2330:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseEventDispatcher=void 0;const i=n(9184);class o extends i.PromiseDispatcherBase{constructor(){super()}async dispatch(e,t){const n=await this._dispatchAsPromise(!1,this,arguments);if(null==n)throw new i.DispatchError("Got `null` back from dispatch.");return n}dispatchAsync(e,t){this._dispatchAsPromise(!0,this,arguments)}asEvent(){return super.asEvent()}}t.PromiseEventDispatcher=o},3351:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseEventHandlingBase=void 0;const i=n(9184),o=n(4283);class s extends i.HandlingBase{constructor(){super(new o.PromiseEventList)}}t.PromiseEventHandlingBase=s},4283:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseEventList=void 0;const i=n(9184),o=n(2330);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.PromiseEventDispatcher}}t.PromiseEventList=s},606:(e,t,n)=>{"use strict";
+t.UD=t.IL=void 0;var i=n(4604);var o=n(4214);var s=n(6569);Object.defineProperty(t,"IL",{enumerable:!0,get:function(){return s.SimpleEventDispatcher}});var r=n(5010);Object.defineProperty(t,"UD",{enumerable:!0,get:function(){return r.SignalDispatcher}});var a=n(606);var l=n(6042);var c=n(4225)},2995:()=>{!function(e,t){!function(e,t,n,i){function o(){}function s(n){var i=t.exports.Promise,s=void 0!==i?i:e.Promise;return"function"==typeof s?new s(n):(n(o,o),null)}var r,a,l,c,d,u=(l=Math.floor(1e3/60),c={},d=0,"function"==typeof requestAnimationFrame&&"function"==typeof cancelAnimationFrame?(r=function(e){var t=Math.random();return c[t]=requestAnimationFrame((function n(i){d===i||d+l-1{var i=n(7180),o=n(3181),s=n(3031),r=n(9067),a=n(6833),l=n(3717),c=n(4801);c.alea=i,c.xor128=o,c.xorwow=s,c.xorshift7=r,c.xor4096=a,c.tychei=l,e.exports=c},7180:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n=function(){var e=4022871197,t=function(t){t=t.toString();for(var n=0;n>>0,e=(i*=e)>>>0,e+=4294967296*(i-=e)}return 2.3283064365386963e-10*(e>>>0)};return t}();t.next=function(){var e=2091639*t.s0+2.3283064365386963e-10*t.c;return t.s0=t.s1,t.s1=t.s2,t.s2=e-(t.c=0|e)},t.c=1,t.s0=n(" "),t.s1=n(" "),t.s2=n(" "),t.s0-=n(e),t.s0<0&&(t.s0+=1),t.s1-=n(e),t.s1<0&&(t.s1+=1),t.s2-=n(e),t.s2<0&&(t.s2+=1),n=null}function r(e,t){return t.c=e.c,t.s0=e.s0,t.s1=e.s1,t.s2=e.s2,t}function a(e,t){var n=new s(e),i=t&&t.state,o=n.next;return o.int32=function(){return 4294967296*n.next()|0},o.double=function(){return o()+11102230246251565e-32*(2097152*o()|0)},o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.alea=a}(0,e=n.nmd(e),n.amdD)},3717:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n="";t.next=function(){var e=t.b,n=t.c,i=t.d,o=t.a;return e=e<<25^e>>>7^n,n=n-i|0,i=i<<24^i>>>8^o,o=o-e|0,t.b=e=e<<20^e>>>12^n,t.c=n=n-i|0,t.d=i<<16^n>>>16^o,t.a=o-e|0},t.a=0,t.b=0,t.c=-1640531527,t.d=1367130551,e===Math.floor(e)?(t.a=e/4294967296|0,t.b=0|e):n+=e;for(var i=0;i>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.tychei=a}(0,e=n.nmd(e),n.amdD)},3181:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n="";t.x=0,t.y=0,t.z=0,t.w=0,t.next=function(){var e=t.x^t.x<<11;return t.x=t.y,t.y=t.z,t.z=t.w,t.w^=t.w>>>19^e^e>>>8},e===(0|e)?t.x=e:n+=e;for(var i=0;i>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xor128=a}(0,e=n.nmd(e),n.amdD)},6833:function(e,t,n){var i;!function(e,o){function s(e){var t=this;t.next=function(){var e,n,i=t.w,o=t.X,s=t.i;return t.w=i=i+1640531527|0,n=o[s+34&127],e=o[s=s+1&127],n^=n<<13,e^=e<<17,n^=n>>>15,e^=e>>>12,n=o[s]=n^e,t.i=s,n+(i^i>>>16)|0},function(e,t){var n,i,o,s,r,a=[],l=128;for(t===(0|t)?(i=t,t=null):(t+="\0",i=0,l=Math.max(l,t.length)),o=0,s=-32;s>>15,i^=i<<4,i^=i>>>13,s>=0&&(r=r+1640531527|0,o=0==(n=a[127&s]^=i+r)?o+1:0);for(o>=128&&(a[127&(t&&t.length||0)]=-1),o=127,s=512;s>0;--s)i=a[o+34&127],n=a[o=o+1&127],i^=i<<13,n^=n<<17,i^=i>>>15,n^=n>>>12,a[o]=i^n;e.w=r,e.X=a,e.i=o}(t,e)}function r(e,t){return t.i=e.i,t.w=e.w,t.X=e.X.slice(),t}function a(e,t){null==e&&(e=+new Date);var n=new s(e),i=t&&t.state,o=function(){return(n.next()>>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&(i.X&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xor4096=a}(0,e=n.nmd(e),n.amdD)},9067:function(e,t,n){var i;!function(e,o){function s(e){var t=this;t.next=function(){var e,n,i=t.x,o=t.i;return e=i[o],n=(e^=e>>>7)^e<<24,n^=(e=i[o+1&7])^e>>>10,n^=(e=i[o+3&7])^e>>>3,n^=(e=i[o+4&7])^e<<7,e=i[o+7&7],n^=(e^=e<<13)^e<<9,i[o]=n,t.i=o+1&7,n},function(e,t){var n,i=[];if(t===(0|t))i[0]=t;else for(t=""+t,n=0;n0;--n)e.next()}(t,e)}function r(e,t){return t.x=e.x.slice(),t.i=e.i,t}function a(e,t){null==e&&(e=+new Date);var n=new s(e),i=t&&t.state,o=function(){return(n.next()>>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&(i.x&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xorshift7=a}(0,e=n.nmd(e),n.amdD)},3031:function(e,t,n){var i;!function(e,o){function s(e){var t=this,n="";t.next=function(){var e=t.x^t.x>>>2;return t.x=t.y,t.y=t.z,t.z=t.w,t.w=t.v,(t.d=t.d+362437|0)+(t.v=t.v^t.v<<4^e^e<<1)|0},t.x=0,t.y=0,t.z=0,t.w=0,t.v=0,e===(0|e)?t.x=e:n+=e;for(var i=0;i>>4),t.next()}function r(e,t){return t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w,t.v=e.v,t.d=e.d,t}function a(e,t){var n=new s(e),i=t&&t.state,o=function(){return(n.next()>>>0)/4294967296};return o.double=function(){do{var e=((n.next()>>>11)+(n.next()>>>0)/4294967296)/(1<<21)}while(0===e);return e},o.int32=n.next,o.quick=o,i&&("object"==typeof i&&r(i,n),o.state=function(){return r(n,{})}),o}o&&o.exports?o.exports=a:n.amdD&&n.amdO?void 0===(i=function(){return a}.call(t,n,t,o))||(o.exports=i):this.xorwow=a}(0,e=n.nmd(e),n.amdD)},4801:(e,t,n)=>{var i;!function(o,s){var r,a=(0,eval)("this"),l=256,c="random",d=s.pow(l,6),u=s.pow(2,52),p=2*u,h=l-1;function g(e,t,n){var i=[],h=v(b((t=1==t?{entropy:!0}:t||{}).entropy?[e,y(o)]:null==e?function(){try{var e;return r&&(e=r.randomBytes)?e=e(l):(e=new Uint8Array(l),(a.crypto||a.msCrypto).getRandomValues(e)),y(e)}catch(e){var t=a.navigator,n=t&&t.plugins;return[+new Date,a,n,a.screen,y(o)]}}():e,3),i),g=new m(i),_=function(){for(var e=g.g(6),t=d,n=0;e=p;)e/=2,t/=2,n>>>=1;return(e+n)/t};return _.int32=function(){return 0|g.g(4)},_.quick=function(){return g.g(4)/4294967296},_.double=_,v(y(g.S),o),(t.pass||n||function(e,t,n,i){return i&&(i.S&&f(i,g),e.state=function(){return f(g,{})}),n?(s[c]=e,t):e})(_,h,"global"in t?t.global:this==s,t.state)}function m(e){var t,n=e.length,i=this,o=0,s=i.i=i.j=0,r=i.S=[];for(n||(e=[n++]);o{n(7391);var i=n(2287);e.exports=i},2287:function(e){(function(){var t={};Math.seedrandom&&(seedrandom=Math.seedrandom);var n=function(e){return"[object Array]"===Object.prototype.toString.call(e)},i=function(e){return/(number|string)/i.test(Object.prototype.toString.call(e).match(/^\[object (.*)\]$/)[1])?e:isNaN(e)?Number(String(this.strSeed=e).split("").map((function(e){return e.charCodeAt(0)})).join("")):e},o=function(e,t,n){return Math.floor(e()*(n-t+1))+t};t.shuffle=function(e,t){if(!n(e))return null;t=i(t)||"none";for(var s=e.length,r=seedrandom(t),a=[],l=[],c=0;c{!function(){"use strict";e.exports={polyfill:function(){var e=window,t=document;if(!("scrollBehavior"in t.documentElement.style)||!0===e.__forceSmoothScrollPolyfill__){var n,i=e.HTMLElement||e.Element,o=468,s={scroll:e.scroll||e.scrollTo,scrollBy:e.scrollBy,elementScroll:i.prototype.scroll||l,scrollIntoView:i.prototype.scrollIntoView},r=e.performance&&e.performance.now?e.performance.now.bind(e.performance):Date.now,a=(n=e.navigator.userAgent,new RegExp(["MSIE ","Trident/","Edge/"].join("|")).test(n)?1:0);e.scroll=e.scrollTo=function(){void 0!==arguments[0]&&(!0!==c(arguments[0])?g.call(e,t.body,void 0!==arguments[0].left?~~arguments[0].left:e.scrollX||e.pageXOffset,void 0!==arguments[0].top?~~arguments[0].top:e.scrollY||e.pageYOffset):s.scroll.call(e,void 0!==arguments[0].left?arguments[0].left:"object"!=typeof arguments[0]?arguments[0]:e.scrollX||e.pageXOffset,void 0!==arguments[0].top?arguments[0].top:void 0!==arguments[1]?arguments[1]:e.scrollY||e.pageYOffset))},e.scrollBy=function(){void 0!==arguments[0]&&(c(arguments[0])?s.scrollBy.call(e,void 0!==arguments[0].left?arguments[0].left:"object"!=typeof arguments[0]?arguments[0]:0,void 0!==arguments[0].top?arguments[0].top:void 0!==arguments[1]?arguments[1]:0):g.call(e,t.body,~~arguments[0].left+(e.scrollX||e.pageXOffset),~~arguments[0].top+(e.scrollY||e.pageYOffset)))},i.prototype.scroll=i.prototype.scrollTo=function(){if(void 0!==arguments[0])if(!0!==c(arguments[0])){var e=arguments[0].left,t=arguments[0].top;g.call(this,this,void 0===e?this.scrollLeft:~~e,void 0===t?this.scrollTop:~~t)}else{if("number"==typeof arguments[0]&&void 0===arguments[1])throw new SyntaxError("Value could not be converted");s.elementScroll.call(this,void 0!==arguments[0].left?~~arguments[0].left:"object"!=typeof arguments[0]?~~arguments[0]:this.scrollLeft,void 0!==arguments[0].top?~~arguments[0].top:void 0!==arguments[1]?~~arguments[1]:this.scrollTop)}},i.prototype.scrollBy=function(){void 0!==arguments[0]&&(!0!==c(arguments[0])?this.scroll({left:~~arguments[0].left+this.scrollLeft,top:~~arguments[0].top+this.scrollTop,behavior:arguments[0].behavior}):s.elementScroll.call(this,void 0!==arguments[0].left?~~arguments[0].left+this.scrollLeft:~~arguments[0]+this.scrollLeft,void 0!==arguments[0].top?~~arguments[0].top+this.scrollTop:~~arguments[1]+this.scrollTop))},i.prototype.scrollIntoView=function(){if(!0!==c(arguments[0])){var n=function(e){for(;e!==t.body&&!1===p(e);)e=e.parentNode||e.host;return e}(this),i=n.getBoundingClientRect(),o=this.getBoundingClientRect();n!==t.body?(g.call(this,n,n.scrollLeft+o.left-i.left,n.scrollTop+o.top-i.top),"fixed"!==e.getComputedStyle(n).position&&e.scrollBy({left:i.left,top:i.top,behavior:"smooth"})):e.scrollBy({left:o.left,top:o.top,behavior:"smooth"})}else s.scrollIntoView.call(this,void 0===arguments[0]||arguments[0])}}function l(e,t){this.scrollLeft=e,this.scrollTop=t}function c(e){if(null===e||"object"!=typeof e||void 0===e.behavior||"auto"===e.behavior||"instant"===e.behavior)return!0;if("object"==typeof e&&"smooth"===e.behavior)return!1;throw new TypeError("behavior member of ScrollOptions "+e.behavior+" is not a valid value for enumeration ScrollBehavior.")}function d(e,t){return"Y"===t?e.clientHeight+a1?1:l,n=.5*(1-Math.cos(Math.PI*a)),i=t.startX+(t.x-t.startX)*n,s=t.startY+(t.y-t.startY)*n,t.method.call(t.scrollable,i,s),i===t.x&&s===t.y||e.requestAnimationFrame(h.bind(e,t))}function g(n,i,o){var a,c,d,u,p=r();n===t.body?(a=e,c=e.scrollX||e.pageXOffset,d=e.scrollY||e.pageYOffset,u=s.scroll):(a=n,c=n.scrollLeft,d=n.scrollTop,u=l),h({scrollable:a,method:u,startTime:p,startX:c,startY:d,x:i,y:o})}}}}()},1246:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NonUniformPromiseEventList=void 0;const i=n(2330);t.NonUniformPromiseEventList=class{constructor(){this._events={}}get(e){if(this._events[e])return this._events[e];const t=this.createDispatcher();return this._events[e]=t,t}remove(e){delete this._events[e]}createDispatcher(){return new i.PromiseEventDispatcher}}},2330:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseEventDispatcher=void 0;const i=n(9184);class o extends i.PromiseDispatcherBase{constructor(){super()}async dispatch(e,t){const n=await this._dispatchAsPromise(!1,this,arguments);if(null==n)throw new i.DispatchError("Got `null` back from dispatch.");return n}dispatchAsync(e,t){this._dispatchAsPromise(!0,this,arguments)}asEvent(){return super.asEvent()}}t.PromiseEventDispatcher=o},3351:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseEventHandlingBase=void 0;const i=n(9184),o=n(4283);class s extends i.HandlingBase{constructor(){super(new o.PromiseEventList)}}t.PromiseEventHandlingBase=s},4283:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseEventList=void 0;const i=n(9184),o=n(2330);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.PromiseEventDispatcher}}t.PromiseEventList=s},606:(e,t,n)=>{"use strict";
/*!
* Strongly Typed Events for TypeScript - Core
* https://github.com/KeesCBakker/StronlyTypedEvents/
@@ -75,7 +75,7 @@ t.UD=t.IL=void 0;var i=n(4604);var o=n(4214);var s=n(6569);Object.defineProperty
*
* Copyright Kees C. Bakker / KeesTalksTech
* Released under the MIT license
- */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(4645);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(3729);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(7569);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(7672);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(6413);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(278);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(4995);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(7744);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(455);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const h=n(3512);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return h.SubscriptionChangeEventDispatcher}})},6413:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},4450:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSignalDispatcher=void 0;const i=n(7852);class o extends i.PromiseDispatcherBase{constructor(){super()}async dispatch(){const e=await this._dispatchAsPromise(!1,this,arguments);if(null==e)throw new i.DispatchError("Got `null` back from dispatch.");return e}dispatchAsync(){this._dispatchAsPromise(!0,this,arguments)}asEvent(){return super.asEvent()}}t.PromiseSignalDispatcher=o},5871:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSignalHandlingBase=void 0;const i=n(7852),o=n(131);class s extends i.HandlingBase{constructor(){super(new o.PromiseSignalList)}}t.PromiseSignalHandlingBase=s},131:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSignalList=void 0;const i=n(7852),o=n(6042);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.PromiseSignalDispatcher}}t.PromiseSignalList=s},6042:(e,t,n)=>{"use strict";
+ */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(4645);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(3729);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(7569);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(7672);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(6413);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(278);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(4995);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(7744);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(455);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const p=n(3512);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return p.SubscriptionChangeEventDispatcher}})},6413:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},4450:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSignalDispatcher=void 0;const i=n(7852);class o extends i.PromiseDispatcherBase{constructor(){super()}async dispatch(){const e=await this._dispatchAsPromise(!1,this,arguments);if(null==e)throw new i.DispatchError("Got `null` back from dispatch.");return e}dispatchAsync(){this._dispatchAsPromise(!0,this,arguments)}asEvent(){return super.asEvent()}}t.PromiseSignalDispatcher=o},5871:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSignalHandlingBase=void 0;const i=n(7852),o=n(131);class s extends i.HandlingBase{constructor(){super(new o.PromiseSignalList)}}t.PromiseSignalHandlingBase=s},131:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSignalList=void 0;const i=n(7852),o=n(6042);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.PromiseSignalDispatcher}}t.PromiseSignalList=s},6042:(e,t,n)=>{"use strict";
/*!
* Strongly Typed Events for TypeScript - Promise Signals
* https://github.com/KeesCBakker/StronlyTypedEvents/
@@ -91,7 +91,7 @@ t.UD=t.IL=void 0;var i=n(4604);var o=n(4214);var s=n(6569);Object.defineProperty
*
* Copyright Kees C. Bakker / KeesTalksTech
* Released under the MIT license
- */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(9737);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(8589);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(8661);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(5636);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(1385);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(5722);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(6372);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(6484);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(8859);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const h=n(3324);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return h.SubscriptionChangeEventDispatcher}})},1385:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},5829:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NonUniformPromiseSimpleEventList=void 0;const i=n(3677);t.NonUniformPromiseSimpleEventList=class{constructor(){this._events={}}get(e){if(this._events[e])return this._events[e];const t=this.createDispatcher();return this._events[e]=t,t}remove(e){delete this._events[e]}createDispatcher(){return new i.PromiseSimpleEventDispatcher}}},3677:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSimpleEventDispatcher=void 0;const i=n(5575);class o extends i.PromiseDispatcherBase{constructor(){super()}async dispatch(e){const t=await this._dispatchAsPromise(!1,this,arguments);if(null==t)throw new i.DispatchError("Got `null` back from dispatch.");return t}dispatchAsync(e){this._dispatchAsPromise(!0,this,arguments)}asEvent(){return super.asEvent()}}t.PromiseSimpleEventDispatcher=o},8648:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSimpleEventHandlingBase=void 0;const i=n(5575),o=n(5536);class s extends i.HandlingBase{constructor(){super(new o.PromiseSimpleEventList)}}t.PromiseSimpleEventHandlingBase=s},5536:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSimpleEventList=void 0;const i=n(5575),o=n(3677);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.PromiseSimpleEventDispatcher}}t.PromiseSimpleEventList=s},4225:(e,t,n)=>{"use strict";
+ */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(9737);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(8589);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(8661);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(5636);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(1385);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(5722);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(6372);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(6484);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(8859);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const p=n(3324);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return p.SubscriptionChangeEventDispatcher}})},1385:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},5829:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NonUniformPromiseSimpleEventList=void 0;const i=n(3677);t.NonUniformPromiseSimpleEventList=class{constructor(){this._events={}}get(e){if(this._events[e])return this._events[e];const t=this.createDispatcher();return this._events[e]=t,t}remove(e){delete this._events[e]}createDispatcher(){return new i.PromiseSimpleEventDispatcher}}},3677:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSimpleEventDispatcher=void 0;const i=n(5575);class o extends i.PromiseDispatcherBase{constructor(){super()}async dispatch(e){const t=await this._dispatchAsPromise(!1,this,arguments);if(null==t)throw new i.DispatchError("Got `null` back from dispatch.");return t}dispatchAsync(e){this._dispatchAsPromise(!0,this,arguments)}asEvent(){return super.asEvent()}}t.PromiseSimpleEventDispatcher=o},8648:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSimpleEventHandlingBase=void 0;const i=n(5575),o=n(5536);class s extends i.HandlingBase{constructor(){super(new o.PromiseSimpleEventList)}}t.PromiseSimpleEventHandlingBase=s},5536:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PromiseSimpleEventList=void 0;const i=n(5575),o=n(3677);class s extends i.EventListBase{constructor(){super()}createDispatcher(){return new o.PromiseSimpleEventDispatcher}}t.PromiseSimpleEventList=s},4225:(e,t,n)=>{"use strict";
/*!
* Strongly Typed Events for TypeScript - Core
* https://github.com/KeesCBakker/StronlyTypedEvents/
@@ -107,4 +107,61 @@ t.UD=t.IL=void 0;var i=n(4604);var o=n(4214);var s=n(6569);Object.defineProperty
*
* Copyright Kees C. Bakker / KeesTalksTech
* Released under the MIT license
- */Object.defineProperty(t,"__esModule",{value:!0}),t.SubscriptionChangeEventDispatcher=t.HandlingBase=t.PromiseDispatcherBase=t.PromiseSubscription=t.DispatchError=t.EventManagement=t.EventListBase=t.DispatcherWrapper=t.DispatcherBase=t.Subscription=void 0;const i=n(5072);Object.defineProperty(t,"DispatcherBase",{enumerable:!0,get:function(){return i.DispatcherBase}});const o=n(2210);Object.defineProperty(t,"DispatchError",{enumerable:!0,get:function(){return o.DispatchError}});const s=n(1050);Object.defineProperty(t,"DispatcherWrapper",{enumerable:!0,get:function(){return s.DispatcherWrapper}});const r=n(4211);Object.defineProperty(t,"EventListBase",{enumerable:!0,get:function(){return r.EventListBase}});const a=n(3504);Object.defineProperty(t,"EventManagement",{enumerable:!0,get:function(){return a.EventManagement}});const l=n(5537);Object.defineProperty(t,"HandlingBase",{enumerable:!0,get:function(){return l.HandlingBase}});const c=n(3787);Object.defineProperty(t,"PromiseDispatcherBase",{enumerable:!0,get:function(){return c.PromiseDispatcherBase}});const d=n(5485);Object.defineProperty(t,"PromiseSubscription",{enumerable:!0,get:function(){return d.PromiseSubscription}});const u=n(8080);Object.defineProperty(t,"Subscription",{enumerable:!0,get:function(){return u.Subscription}});const h=n(1789);Object.defineProperty(t,"SubscriptionChangeEventDispatcher",{enumerable:!0,get:function(){return h.SubscriptionChangeEventDispatcher}})},3504:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.EventManagement=void 0;t.EventManagement=class{constructor(e){this.unsub=e,this.propagationStopped=!1}stopPropagation(){this.propagationStopped=!0}}},9244:(e,t,n)=>{"use strict";function i(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function o(e){return e instanceof i(e).Element||e instanceof Element}function s(e){return e instanceof i(e).HTMLElement||e instanceof HTMLElement}function r(e){return"undefined"!=typeof ShadowRoot&&(e instanceof i(e).ShadowRoot||e instanceof ShadowRoot)}n.d(t,{Ay:()=>ut});var a=Math.max,l=Math.min,c=Math.round;function d(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function u(){return!/^((?!chrome|android).)*safari/i.test(d())}function h(e,t,n){void 0===t&&(t=!1),void 0===n&&(n=!1);var r=e.getBoundingClientRect(),a=1,l=1;t&&s(e)&&(a=e.offsetWidth>0&&c(r.width)/e.offsetWidth||1,l=e.offsetHeight>0&&c(r.height)/e.offsetHeight||1);var d=(o(e)?i(e):window).visualViewport,h=!u()&&n,p=(r.left+(h&&d?d.offsetLeft:0))/a,g=(r.top+(h&&d?d.offsetTop:0))/l,m=r.width/a,f=r.height/l;return{width:m,height:f,top:g,right:p+m,bottom:g+f,left:p,x:p,y:g}}function p(e){var t=i(e);return{scrollLeft:t.pageXOffset,scrollTop:t.pageYOffset}}function g(e){return e?(e.nodeName||"").toLowerCase():null}function m(e){return((o(e)?e.ownerDocument:e.document)||window.document).documentElement}function f(e){return h(m(e)).left+p(e).scrollLeft}function b(e){return i(e).getComputedStyle(e)}function y(e){var t=b(e),n=t.overflow,i=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+i)}function v(e,t,n){void 0===n&&(n=!1);var o,r,a=s(t),l=s(t)&&function(e){var t=e.getBoundingClientRect(),n=c(t.width)/e.offsetWidth||1,i=c(t.height)/e.offsetHeight||1;return 1!==n||1!==i}(t),d=m(t),u=h(e,l,n),b={scrollLeft:0,scrollTop:0},v={x:0,y:0};return(a||!a&&!n)&&(("body"!==g(t)||y(d))&&(b=(o=t)!==i(o)&&s(o)?{scrollLeft:(r=o).scrollLeft,scrollTop:r.scrollTop}:p(o)),s(t)?((v=h(t,!0)).x+=t.clientLeft,v.y+=t.clientTop):d&&(v.x=f(d))),{x:u.left+b.scrollLeft-v.x,y:u.top+b.scrollTop-v.y,width:u.width,height:u.height}}function _(e){var t=h(e),n=e.offsetWidth,i=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-i)<=1&&(i=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:i}}function S(e){return"html"===g(e)?e:e.assignedSlot||e.parentNode||(r(e)?e.host:null)||m(e)}function w(e){return["html","body","#document"].indexOf(g(e))>=0?e.ownerDocument.body:s(e)&&y(e)?e:w(S(e))}function E(e,t){var n;void 0===t&&(t=[]);var o=w(e),s=o===(null==(n=e.ownerDocument)?void 0:n.body),r=i(o),a=s?[r].concat(r.visualViewport||[],y(o)?o:[]):o,l=t.concat(a);return s?l:l.concat(E(S(a)))}function A(e){return["table","td","th"].indexOf(g(e))>=0}function C(e){return s(e)&&"fixed"!==b(e).position?e.offsetParent:null}function k(e){for(var t=i(e),n=C(e);n&&A(n)&&"static"===b(n).position;)n=C(n);return n&&("html"===g(n)||"body"===g(n)&&"static"===b(n).position)?t:n||function(e){var t=/firefox/i.test(d());if(/Trident/i.test(d())&&s(e)&&"fixed"===b(e).position)return null;var n=S(e);for(r(n)&&(n=n.host);s(n)&&["html","body"].indexOf(g(n))<0;){var i=b(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||t}var L="top",F="bottom",q="right",N="left",x="auto",T=[L,F,q,N],P="start",O="end",D="clippingParents",I="viewport",M="popper",B="reference",R=T.reduce((function(e,t){return e.concat([t+"-"+P,t+"-"+O])}),[]),V=[].concat(T,[x]).reduce((function(e,t){return e.concat([t,t+"-"+P,t+"-"+O])}),[]),U=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function H(e){var t=new Map,n=new Set,i=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var i=t.get(e);i&&o(i)}})),i.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),i}var j={placement:"bottom",modifiers:[],strategy:"absolute"};function G(){for(var e=arguments.length,t=new Array(e),n=0;n=0?"x":"y"}function X(e){var t,n=e.reference,i=e.element,o=e.placement,s=o?z(o):null,r=o?Y(o):null,a=n.x+n.width/2-i.width/2,l=n.y+n.height/2-i.height/2;switch(s){case L:t={x:a,y:n.y-i.height};break;case F:t={x:a,y:n.y+n.height};break;case q:t={x:n.x+n.width,y:l};break;case N:t={x:n.x-i.width,y:l};break;default:t={x:n.x,y:n.y}}var c=s?J(s):null;if(null!=c){var d="y"===c?"height":"width";switch(r){case P:t[c]=t[c]-(n[d]/2-i[d]/2);break;case O:t[c]=t[c]+(n[d]/2-i[d]/2)}}return t}var K={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Q(e){var t,n=e.popper,o=e.popperRect,s=e.placement,r=e.variation,a=e.offsets,l=e.position,d=e.gpuAcceleration,u=e.adaptive,h=e.roundOffsets,p=e.isFixed,g=a.x,f=void 0===g?0:g,y=a.y,v=void 0===y?0:y,_="function"==typeof h?h({x:f,y:v}):{x:f,y:v};f=_.x,v=_.y;var S=a.hasOwnProperty("x"),w=a.hasOwnProperty("y"),E=N,A=L,C=window;if(u){var x=k(n),T="clientHeight",P="clientWidth";if(x===i(n)&&"static"!==b(x=m(n)).position&&"absolute"===l&&(T="scrollHeight",P="scrollWidth"),s===L||(s===N||s===q)&&r===O)A=F,v-=(p&&x===C&&C.visualViewport?C.visualViewport.height:x[T])-o.height,v*=d?1:-1;if(s===N||(s===L||s===F)&&r===O)E=q,f-=(p&&x===C&&C.visualViewport?C.visualViewport.width:x[P])-o.width,f*=d?1:-1}var D,I=Object.assign({position:l},u&&K),M=!0===h?function(e,t){var n=e.x,i=e.y,o=t.devicePixelRatio||1;return{x:c(n*o)/o||0,y:c(i*o)/o||0}}({x:f,y:v},i(n)):{x:f,y:v};return f=M.x,v=M.y,d?Object.assign({},I,((D={})[A]=w?"0":"",D[E]=S?"0":"",D.transform=(C.devicePixelRatio||1)<=1?"translate("+f+"px, "+v+"px)":"translate3d("+f+"px, "+v+"px, 0)",D)):Object.assign({},I,((t={})[A]=w?v+"px":"",t[E]=S?f+"px":"",t.transform="",t))}const Z={name:"applyStyles",enabled:!0,phase:"write",fn:function(e){var t=e.state;Object.keys(t.elements).forEach((function(e){var n=t.styles[e]||{},i=t.attributes[e]||{},o=t.elements[e];s(o)&&g(o)&&(Object.assign(o.style,n),Object.keys(i).forEach((function(e){var t=i[e];!1===t?o.removeAttribute(e):o.setAttribute(e,!0===t?"":t)})))}))},effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach((function(e){var i=t.elements[e],o=t.attributes[e]||{},r=Object.keys(t.styles.hasOwnProperty(e)?t.styles[e]:n[e]).reduce((function(e,t){return e[t]="",e}),{});s(i)&&g(i)&&(Object.assign(i.style,r),Object.keys(o).forEach((function(e){i.removeAttribute(e)})))}))}},requires:["computeStyles"]};const ee={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(e){var t=e.state,n=e.options,i=e.name,o=n.offset,s=void 0===o?[0,0]:o,r=V.reduce((function(e,n){return e[n]=function(e,t,n){var i=z(e),o=[N,L].indexOf(i)>=0?-1:1,s="function"==typeof n?n(Object.assign({},t,{placement:e})):n,r=s[0],a=s[1];return r=r||0,a=(a||0)*o,[N,q].indexOf(i)>=0?{x:a,y:r}:{x:r,y:a}}(n,t.rects,s),e}),{}),a=r[t.placement],l=a.x,c=a.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=l,t.modifiersData.popperOffsets.y+=c),t.modifiersData[i]=r}};var te={left:"right",right:"left",bottom:"top",top:"bottom"};function ne(e){return e.replace(/left|right|bottom|top/g,(function(e){return te[e]}))}var ie={start:"end",end:"start"};function oe(e){return e.replace(/start|end/g,(function(e){return ie[e]}))}function se(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&r(n)){var i=t;do{if(i&&e.isSameNode(i))return!0;i=i.parentNode||i.host}while(i)}return!1}function re(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function ae(e,t,n){return t===I?re(function(e,t){var n=i(e),o=m(e),s=n.visualViewport,r=o.clientWidth,a=o.clientHeight,l=0,c=0;if(s){r=s.width,a=s.height;var d=u();(d||!d&&"fixed"===t)&&(l=s.offsetLeft,c=s.offsetTop)}return{width:r,height:a,x:l+f(e),y:c}}(e,n)):o(t)?function(e,t){var n=h(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(t,n):re(function(e){var t,n=m(e),i=p(e),o=null==(t=e.ownerDocument)?void 0:t.body,s=a(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),r=a(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),l=-i.scrollLeft+f(e),c=-i.scrollTop;return"rtl"===b(o||n).direction&&(l+=a(n.clientWidth,o?o.clientWidth:0)-s),{width:s,height:r,x:l,y:c}}(m(e)))}function le(e,t,n,i){var r="clippingParents"===t?function(e){var t=E(S(e)),n=["absolute","fixed"].indexOf(b(e).position)>=0&&s(e)?k(e):e;return o(n)?t.filter((function(e){return o(e)&&se(e,n)&&"body"!==g(e)})):[]}(e):[].concat(t),c=[].concat(r,[n]),d=c[0],u=c.reduce((function(t,n){var o=ae(e,n,i);return t.top=a(o.top,t.top),t.right=l(o.right,t.right),t.bottom=l(o.bottom,t.bottom),t.left=a(o.left,t.left),t}),ae(e,d,i));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function ce(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function de(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function ue(e,t){void 0===t&&(t={});var n=t,i=n.placement,s=void 0===i?e.placement:i,r=n.strategy,a=void 0===r?e.strategy:r,l=n.boundary,c=void 0===l?D:l,d=n.rootBoundary,u=void 0===d?I:d,p=n.elementContext,g=void 0===p?M:p,f=n.altBoundary,b=void 0!==f&&f,y=n.padding,v=void 0===y?0:y,_=ce("number"!=typeof v?v:de(v,T)),S=g===M?B:M,w=e.rects.popper,E=e.elements[b?S:g],A=le(o(E)?E:E.contextElement||m(e.elements.popper),c,u,a),C=h(e.elements.reference),k=X({reference:C,element:w,strategy:"absolute",placement:s}),N=re(Object.assign({},w,k)),x=g===M?N:C,P={top:A.top-x.top+_.top,bottom:x.bottom-A.bottom+_.bottom,left:A.left-x.left+_.left,right:x.right-A.right+_.right},O=e.modifiersData.offset;if(g===M&&O){var R=O[s];Object.keys(P).forEach((function(e){var t=[q,F].indexOf(e)>=0?1:-1,n=[L,F].indexOf(e)>=0?"y":"x";P[e]+=R[n]*t}))}return P}function he(e,t,n){return a(e,l(t,n))}const pe={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,i=e.name,o=n.mainAxis,s=void 0===o||o,r=n.altAxis,c=void 0!==r&&r,d=n.boundary,u=n.rootBoundary,h=n.altBoundary,p=n.padding,g=n.tether,m=void 0===g||g,f=n.tetherOffset,b=void 0===f?0:f,y=ue(t,{boundary:d,rootBoundary:u,padding:p,altBoundary:h}),v=z(t.placement),S=Y(t.placement),w=!S,E=J(v),A="x"===E?"y":"x",C=t.modifiersData.popperOffsets,x=t.rects.reference,T=t.rects.popper,O="function"==typeof b?b(Object.assign({},t.rects,{placement:t.placement})):b,D="number"==typeof O?{mainAxis:O,altAxis:O}:Object.assign({mainAxis:0,altAxis:0},O),I=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,M={x:0,y:0};if(C){if(s){var B,R="y"===E?L:N,V="y"===E?F:q,U="y"===E?"height":"width",H=C[E],j=H+y[R],G=H-y[V],$=m?-T[U]/2:0,W=S===P?x[U]:T[U],X=S===P?-T[U]:-x[U],K=t.elements.arrow,Q=m&&K?_(K):{width:0,height:0},Z=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},ee=Z[R],te=Z[V],ne=he(0,x[U],Q[U]),ie=w?x[U]/2-$-ne-ee-D.mainAxis:W-ne-ee-D.mainAxis,oe=w?-x[U]/2+$+ne+te+D.mainAxis:X+ne+te+D.mainAxis,se=t.elements.arrow&&k(t.elements.arrow),re=se?"y"===E?se.clientTop||0:se.clientLeft||0:0,ae=null!=(B=null==I?void 0:I[E])?B:0,le=H+oe-ae,ce=he(m?l(j,H+ie-ae-re):j,H,m?a(G,le):G);C[E]=ce,M[E]=ce-H}if(c){var de,pe="x"===E?L:N,ge="x"===E?F:q,me=C[A],fe="y"===A?"height":"width",be=me+y[pe],ye=me-y[ge],ve=-1!==[L,N].indexOf(v),_e=null!=(de=null==I?void 0:I[A])?de:0,Se=ve?be:me-x[fe]-T[fe]-_e+D.altAxis,we=ve?me+x[fe]+T[fe]-_e-D.altAxis:ye,Ee=m&&ve?function(e,t,n){var i=he(e,t,n);return i>n?n:i}(Se,me,we):he(m?Se:be,me,m?we:ye);C[A]=Ee,M[A]=Ee-me}t.modifiersData[i]=M}},requiresIfExists:["offset"]};const ge={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,i=e.name,o=e.options,s=n.elements.arrow,r=n.modifiersData.popperOffsets,a=z(n.placement),l=J(a),c=[N,q].indexOf(a)>=0?"height":"width";if(s&&r){var d=function(e,t){return ce("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:de(e,T))}(o.padding,n),u=_(s),h="y"===l?L:N,p="y"===l?F:q,g=n.rects.reference[c]+n.rects.reference[l]-r[l]-n.rects.popper[c],m=r[l]-n.rects.reference[l],f=k(s),b=f?"y"===l?f.clientHeight||0:f.clientWidth||0:0,y=g/2-m/2,v=d[h],S=b-u[c]-d[p],w=b/2-u[c]/2+y,E=he(v,w,S),A=l;n.modifiersData[i]=((t={})[A]=E,t.centerOffset=E-w,t)}},effect:function(e){var t=e.state,n=e.options.element,i=void 0===n?"[data-popper-arrow]":n;null!=i&&("string"!=typeof i||(i=t.elements.popper.querySelector(i)))&&se(t.elements.popper,i)&&(t.elements.arrow=i)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function me(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function fe(e){return[L,q,F,N].some((function(t){return e[t]>=0}))}var be=$({defaultModifiers:[{name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(e){var t=e.state,n=e.instance,o=e.options,s=o.scroll,r=void 0===s||s,a=o.resize,l=void 0===a||a,c=i(t.elements.popper),d=[].concat(t.scrollParents.reference,t.scrollParents.popper);return r&&d.forEach((function(e){e.addEventListener("scroll",n.update,W)})),l&&c.addEventListener("resize",n.update,W),function(){r&&d.forEach((function(e){e.removeEventListener("scroll",n.update,W)})),l&&c.removeEventListener("resize",n.update,W)}},data:{}},{name:"popperOffsets",enabled:!0,phase:"read",fn:function(e){var t=e.state,n=e.name;t.modifiersData[n]=X({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})},data:{}},{name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(e){var t=e.state,n=e.options,i=n.gpuAcceleration,o=void 0===i||i,s=n.adaptive,r=void 0===s||s,a=n.roundOffsets,l=void 0===a||a,c={placement:z(t.placement),variation:Y(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:o,isFixed:"fixed"===t.options.strategy};null!=t.modifiersData.popperOffsets&&(t.styles.popper=Object.assign({},t.styles.popper,Q(Object.assign({},c,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:r,roundOffsets:l})))),null!=t.modifiersData.arrow&&(t.styles.arrow=Object.assign({},t.styles.arrow,Q(Object.assign({},c,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})},data:{}},Z,ee,{name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,i=e.name;if(!t.modifiersData[i]._skip){for(var o=n.mainAxis,s=void 0===o||o,r=n.altAxis,a=void 0===r||r,l=n.fallbackPlacements,c=n.padding,d=n.boundary,u=n.rootBoundary,h=n.altBoundary,p=n.flipVariations,g=void 0===p||p,m=n.allowedAutoPlacements,f=t.options.placement,b=z(f),y=l||(b===f||!g?[ne(f)]:function(e){if(z(e)===x)return[];var t=ne(e);return[oe(e),t,oe(t)]}(f)),v=[f].concat(y).reduce((function(e,n){return e.concat(z(n)===x?function(e,t){void 0===t&&(t={});var n=t,i=n.placement,o=n.boundary,s=n.rootBoundary,r=n.padding,a=n.flipVariations,l=n.allowedAutoPlacements,c=void 0===l?V:l,d=Y(i),u=d?a?R:R.filter((function(e){return Y(e)===d})):T,h=u.filter((function(e){return c.indexOf(e)>=0}));0===h.length&&(h=u);var p=h.reduce((function(t,n){return t[n]=ue(e,{placement:n,boundary:o,rootBoundary:s,padding:r})[z(n)],t}),{});return Object.keys(p).sort((function(e,t){return p[e]-p[t]}))}(t,{placement:n,boundary:d,rootBoundary:u,padding:c,flipVariations:g,allowedAutoPlacements:m}):n)}),[]),_=t.rects.reference,S=t.rects.popper,w=new Map,E=!0,A=v[0],C=0;C=0,M=I?"width":"height",B=ue(t,{placement:k,boundary:d,rootBoundary:u,altBoundary:h,padding:c}),U=I?D?q:N:D?F:L;_[M]>S[M]&&(U=ne(U));var H=ne(U),j=[];if(s&&j.push(B[O]<=0),a&&j.push(B[U]<=0,B[H]<=0),j.every((function(e){return e}))){A=k,E=!1;break}w.set(k,j)}if(E)for(var G=function(e){var t=v.find((function(t){var n=w.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return A=t,"break"},$=g?3:1;$>0;$--){if("break"===G($))break}t.placement!==A&&(t.modifiersData[i]._skip=!0,t.placement=A,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}},pe,ge,{name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,i=t.rects.reference,o=t.rects.popper,s=t.modifiersData.preventOverflow,r=ue(t,{elementContext:"reference"}),a=ue(t,{altBoundary:!0}),l=me(r,i),c=me(a,o,s),d=fe(l),u=fe(c);t.modifiersData[n]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:d,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":d,"data-popper-escaped":u})}}]}),ye="tippy-content",ve="tippy-backdrop",_e="tippy-arrow",Se="tippy-svg-arrow",we={passive:!0,capture:!0},Ee=function(){return document.body};function Ae(e,t,n){if(Array.isArray(e)){var i=e[t];return null==i?Array.isArray(n)?n[t]:n:i}return e}function Ce(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function ke(e,t){return"function"==typeof e?e.apply(void 0,t):e}function Le(e,t){return 0===t?e:function(i){clearTimeout(n),n=setTimeout((function(){e(i)}),t)};var n}function Fe(e){return[].concat(e)}function qe(e,t){-1===e.indexOf(t)&&e.push(t)}function Ne(e){return e.split("-")[0]}function xe(e){return[].slice.call(e)}function Te(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function Pe(){return document.createElement("div")}function Oe(e){return["Element","Fragment"].some((function(t){return Ce(e,t)}))}function De(e){return Ce(e,"MouseEvent")}function Ie(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function Me(e){return Oe(e)?[e]:function(e){return Ce(e,"NodeList")}(e)?xe(e):Array.isArray(e)?e:xe(document.querySelectorAll(e))}function Be(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function Re(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function Ve(e){var t,n=Fe(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function Ue(e,t,n){var i=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[i](t,n)}))}function He(e,t){for(var n=t;n;){var i;if(e.contains(n))return!0;n=null==n.getRootNode||null==(i=n.getRootNode())?void 0:i.host}return!1}var je={isTouch:!1},Ge=0;function $e(){je.isTouch||(je.isTouch=!0,window.performance&&document.addEventListener("mousemove",We))}function We(){var e=performance.now();e-Ge<20&&(je.isTouch=!1,document.removeEventListener("mousemove",We)),Ge=e}function ze(){var e=document.activeElement;if(Ie(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var Ye=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto;var Je={animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},Xe=Object.assign({appendTo:Ee,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},Je,{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),Ke=Object.keys(Xe);function Qe(e){var t=(e.plugins||[]).reduce((function(t,n){var i,o=n.name,s=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(i=Xe[o])?i:s);return t}),{});return Object.assign({},e,t)}function Ze(e,t){var n=Object.assign({},t,{content:ke(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(Qe(Object.assign({},Xe,{plugins:t}))):Ke).reduce((function(t,n){var i=(e.getAttribute("data-tippy-"+n)||"").trim();if(!i)return t;if("content"===n)t[n]=i;else try{t[n]=JSON.parse(i)}catch(e){t[n]=i}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},Xe.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}var et=function(){return"innerHTML"};function tt(e,t){e[et()]=t}function nt(e){var t=Pe();return!0===e?t.className=_e:(t.className=Se,Oe(e)?t.appendChild(e):tt(t,e)),t}function it(e,t){Oe(t.content)?(tt(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?tt(e,t.content):e.textContent=t.content)}function ot(e){var t=e.firstElementChild,n=xe(t.children);return{box:t,content:n.find((function(e){return e.classList.contains(ye)})),arrow:n.find((function(e){return e.classList.contains(_e)||e.classList.contains(Se)})),backdrop:n.find((function(e){return e.classList.contains(ve)}))}}function st(e){var t=Pe(),n=Pe();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var i=Pe();function o(n,i){var o=ot(t),s=o.box,r=o.content,a=o.arrow;i.theme?s.setAttribute("data-theme",i.theme):s.removeAttribute("data-theme"),"string"==typeof i.animation?s.setAttribute("data-animation",i.animation):s.removeAttribute("data-animation"),i.inertia?s.setAttribute("data-inertia",""):s.removeAttribute("data-inertia"),s.style.maxWidth="number"==typeof i.maxWidth?i.maxWidth+"px":i.maxWidth,i.role?s.setAttribute("role",i.role):s.removeAttribute("role"),n.content===i.content&&n.allowHTML===i.allowHTML||it(r,e.props),i.arrow?a?n.arrow!==i.arrow&&(s.removeChild(a),s.appendChild(nt(i.arrow))):s.appendChild(nt(i.arrow)):a&&s.removeChild(a)}return i.className=ye,i.setAttribute("data-state","hidden"),it(i,e.props),t.appendChild(n),n.appendChild(i),o(e.props,e.props),{popper:t,onUpdate:o}}st.$$tippy=!0;var rt=1,at=[],lt=[];function ct(e,t){var n,i,o,s,r,a,l,c,d=Ze(e,Object.assign({},Xe,Qe(Te(t)))),u=!1,h=!1,p=!1,g=!1,m=[],f=Le(z,d.interactiveDebounce),b=rt++,y=(c=d.plugins).filter((function(e,t){return c.indexOf(e)===t})),v={id:b,reference:e,popper:Pe(),popperInstance:null,props:d,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:y,clearDelayTimeouts:function(){clearTimeout(n),clearTimeout(i),cancelAnimationFrame(o)},setProps:function(t){0;if(v.state.isDestroyed)return;P("onBeforeUpdate",[v,t]),$();var n=v.props,i=Ze(e,Object.assign({},n,Te(t),{ignoreAttributes:!0}));v.props=i,G(),n.interactiveDebounce!==i.interactiveDebounce&&(I(),f=Le(z,i.interactiveDebounce));n.triggerTarget&&!i.triggerTarget?Fe(n.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):i.triggerTarget&&e.removeAttribute("aria-expanded");D(),T(),w&&w(n,i);v.popperInstance&&(K(),Z().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));P("onAfterUpdate",[v,t])},setContent:function(e){v.setProps({content:e})},show:function(){0;var e=v.state.isVisible,t=v.state.isDestroyed,n=!v.state.isEnabled,i=je.isTouch&&!v.props.touch,o=Ae(v.props.duration,0,Xe.duration);if(e||t||n||i)return;if(F().hasAttribute("disabled"))return;if(P("onShow",[v],!1),!1===v.props.onShow(v))return;v.state.isVisible=!0,L()&&(S.style.visibility="visible");T(),V(),v.state.isMounted||(S.style.transition="none");if(L()){var s=N();Be([s.box,s.content],0)}a=function(){var e;if(v.state.isVisible&&!g){if(g=!0,S.offsetHeight,S.style.transition=v.props.moveTransition,L()&&v.props.animation){var t=N(),n=t.box,i=t.content;Be([n,i],o),Re([n,i],"visible")}O(),D(),qe(lt,v),null==(e=v.popperInstance)||e.forceUpdate(),P("onMount",[v]),v.props.animation&&L()&&function(e,t){H(e,t)}(o,(function(){v.state.isShown=!0,P("onShown",[v])}))}},function(){var e,t=v.props.appendTo,n=F();e=v.props.interactive&&t===Ee||"parent"===t?n.parentNode:ke(t,[n]);e.contains(S)||e.appendChild(S);v.state.isMounted=!0,K(),!1}()},hide:function(){0;var e=!v.state.isVisible,t=v.state.isDestroyed,n=!v.state.isEnabled,i=Ae(v.props.duration,1,Xe.duration);if(e||t||n)return;if(P("onHide",[v],!1),!1===v.props.onHide(v))return;v.state.isVisible=!1,v.state.isShown=!1,g=!1,u=!1,L()&&(S.style.visibility="hidden");if(I(),U(),T(!0),L()){var o=N(),s=o.box,r=o.content;v.props.animation&&(Be([s,r],i),Re([s,r],"hidden"))}O(),D(),v.props.animation?L()&&function(e,t){H(e,(function(){!v.state.isVisible&&S.parentNode&&S.parentNode.contains(S)&&t()}))}(i,v.unmount):v.unmount()},hideWithInteractivity:function(e){0;q().addEventListener("mousemove",f),qe(at,f),f(e)},enable:function(){v.state.isEnabled=!0},disable:function(){v.hide(),v.state.isEnabled=!1},unmount:function(){0;v.state.isVisible&&v.hide();if(!v.state.isMounted)return;Q(),Z().forEach((function(e){e._tippy.unmount()})),S.parentNode&&S.parentNode.removeChild(S);lt=lt.filter((function(e){return e!==v})),v.state.isMounted=!1,P("onHidden",[v])},destroy:function(){0;if(v.state.isDestroyed)return;v.clearDelayTimeouts(),v.unmount(),$(),delete e._tippy,v.state.isDestroyed=!0,P("onDestroy",[v])}};if(!d.render)return v;var _=d.render(v),S=_.popper,w=_.onUpdate;S.setAttribute("data-tippy-root",""),S.id="tippy-"+v.id,v.popper=S,e._tippy=v,S._tippy=v;var E=y.map((function(e){return e.fn(v)})),A=e.hasAttribute("aria-expanded");return G(),D(),T(),P("onCreate",[v]),d.showOnCreate&&ee(),S.addEventListener("mouseenter",(function(){v.props.interactive&&v.state.isVisible&&v.clearDelayTimeouts()})),S.addEventListener("mouseleave",(function(){v.props.interactive&&v.props.trigger.indexOf("mouseenter")>=0&&q().addEventListener("mousemove",f)})),v;function C(){var e=v.props.touch;return Array.isArray(e)?e:[e,0]}function k(){return"hold"===C()[0]}function L(){var e;return!(null==(e=v.props.render)||!e.$$tippy)}function F(){return l||e}function q(){var e=F().parentNode;return e?Ve(e):document}function N(){return ot(S)}function x(e){return v.state.isMounted&&!v.state.isVisible||je.isTouch||s&&"focus"===s.type?0:Ae(v.props.delay,e?0:1,Xe.delay)}function T(e){void 0===e&&(e=!1),S.style.pointerEvents=v.props.interactive&&!e?"":"none",S.style.zIndex=""+v.props.zIndex}function P(e,t,n){var i;(void 0===n&&(n=!0),E.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(i=v.props)[e].apply(i,t)}function O(){var t=v.props.aria;if(t.content){var n="aria-"+t.content,i=S.id;Fe(v.props.triggerTarget||e).forEach((function(e){var t=e.getAttribute(n);if(v.state.isVisible)e.setAttribute(n,t?t+" "+i:i);else{var o=t&&t.replace(i,"").trim();o?e.setAttribute(n,o):e.removeAttribute(n)}}))}}function D(){!A&&v.props.aria.expanded&&Fe(v.props.triggerTarget||e).forEach((function(e){v.props.interactive?e.setAttribute("aria-expanded",v.state.isVisible&&e===F()?"true":"false"):e.removeAttribute("aria-expanded")}))}function I(){q().removeEventListener("mousemove",f),at=at.filter((function(e){return e!==f}))}function M(t){if(!je.isTouch||!p&&"mousedown"!==t.type){var n=t.composedPath&&t.composedPath()[0]||t.target;if(!v.props.interactive||!He(S,n)){if(Fe(v.props.triggerTarget||e).some((function(e){return He(e,n)}))){if(je.isTouch)return;if(v.state.isVisible&&v.props.trigger.indexOf("click")>=0)return}else P("onClickOutside",[v,t]);!0===v.props.hideOnClick&&(v.clearDelayTimeouts(),v.hide(),h=!0,setTimeout((function(){h=!1})),v.state.isMounted||U())}}}function B(){p=!0}function R(){p=!1}function V(){var e=q();e.addEventListener("mousedown",M,!0),e.addEventListener("touchend",M,we),e.addEventListener("touchstart",R,we),e.addEventListener("touchmove",B,we)}function U(){var e=q();e.removeEventListener("mousedown",M,!0),e.removeEventListener("touchend",M,we),e.removeEventListener("touchstart",R,we),e.removeEventListener("touchmove",B,we)}function H(e,t){var n=N().box;function i(e){e.target===n&&(Ue(n,"remove",i),t())}if(0===e)return t();Ue(n,"remove",r),Ue(n,"add",i),r=i}function j(t,n,i){void 0===i&&(i=!1),Fe(v.props.triggerTarget||e).forEach((function(e){e.addEventListener(t,n,i),m.push({node:e,eventType:t,handler:n,options:i})}))}function G(){var e;k()&&(j("touchstart",W,{passive:!0}),j("touchend",Y,{passive:!0})),(e=v.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(j(e,W),e){case"mouseenter":j("mouseleave",Y);break;case"focus":j(Ye?"focusout":"blur",J);break;case"focusin":j("focusout",J)}}))}function $(){m.forEach((function(e){var t=e.node,n=e.eventType,i=e.handler,o=e.options;t.removeEventListener(n,i,o)})),m=[]}function W(e){var t,n=!1;if(v.state.isEnabled&&!X(e)&&!h){var i="focus"===(null==(t=s)?void 0:t.type);s=e,l=e.currentTarget,D(),!v.state.isVisible&&De(e)&&at.forEach((function(t){return t(e)})),"click"===e.type&&(v.props.trigger.indexOf("mouseenter")<0||u)&&!1!==v.props.hideOnClick&&v.state.isVisible?n=!0:ee(e),"click"===e.type&&(u=!n),n&&!i&&te(e)}}function z(e){var t=e.target,n=F().contains(t)||S.contains(t);if("mousemove"!==e.type||!n){var i=Z().concat(S).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:d}:null})).filter(Boolean);(function(e,t){var n=t.clientX,i=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,s=e.props.interactiveBorder,r=Ne(o.placement),a=o.modifiersData.offset;if(!a)return!0;var l="bottom"===r?a.top.y:0,c="top"===r?a.bottom.y:0,d="right"===r?a.left.x:0,u="left"===r?a.right.x:0,h=t.top-i+l>s,p=i-t.bottom-c>s,g=t.left-n+d>s,m=n-t.right-u>s;return h||p||g||m}))})(i,e)&&(I(),te(e))}}function Y(e){X(e)||v.props.trigger.indexOf("click")>=0&&u||(v.props.interactive?v.hideWithInteractivity(e):te(e))}function J(e){v.props.trigger.indexOf("focusin")<0&&e.target!==F()||v.props.interactive&&e.relatedTarget&&S.contains(e.relatedTarget)||te(e)}function X(e){return!!je.isTouch&&k()!==e.type.indexOf("touch")>=0}function K(){Q();var t=v.props,n=t.popperOptions,i=t.placement,o=t.offset,s=t.getReferenceClientRect,r=t.moveTransition,l=L()?ot(S).arrow:null,c=s?{getBoundingClientRect:s,contextElement:s.contextElement||F()}:e,d={name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(L()){var n=N().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}},u=[{name:"offset",options:{offset:o}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!r}},d];L()&&l&&u.push({name:"arrow",options:{element:l,padding:3}}),u.push.apply(u,(null==n?void 0:n.modifiers)||[]),v.popperInstance=be(c,S,Object.assign({},n,{placement:i,onFirstUpdate:a,modifiers:u}))}function Q(){v.popperInstance&&(v.popperInstance.destroy(),v.popperInstance=null)}function Z(){return xe(S.querySelectorAll("[data-tippy-root]"))}function ee(e){v.clearDelayTimeouts(),e&&P("onTrigger",[v,e]),V();var t=x(!0),i=C(),o=i[0],s=i[1];je.isTouch&&"hold"===o&&s&&(t=s),t?n=setTimeout((function(){v.show()}),t):v.show()}function te(e){if(v.clearDelayTimeouts(),P("onUntrigger",[v,e]),v.state.isVisible){if(!(v.props.trigger.indexOf("mouseenter")>=0&&v.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&u)){var t=x(!1);t?i=setTimeout((function(){v.state.isVisible&&v.hide()}),t):o=requestAnimationFrame((function(){v.hide()}))}}else U()}}function dt(e,t){void 0===t&&(t={});var n=Xe.plugins.concat(t.plugins||[]);document.addEventListener("touchstart",$e,we),window.addEventListener("blur",ze);var i=Object.assign({},t,{plugins:n}),o=Me(e).reduce((function(e,t){var n=t&&ct(t,i);return n&&e.push(n),e}),[]);return Oe(e)?o[0]:o}dt.defaultProps=Xe,dt.setDefaultProps=function(e){Object.keys(e).forEach((function(t){Xe[t]=e[t]}))},dt.currentInput=je;Object.assign({},Z,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}});dt.setDefaultProps({render:st});const ut=dt},1234:()=>{}},t={};function n(i){var o=t[i];if(void 0!==o)return o.exports;var s=t[i]={id:i,loaded:!1,exports:{}};return e[i].call(s.exports,s,s.exports,n),s.loaded=!0,s.exports}n.amdD=function(){throw new Error("define cannot be used indirect")},n.amdO={},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{"use strict";const e={backgroundImage:"",MediaAttribution:!0,applePay:!1,CapitalizeFields:!1,ClickToExpand:!0,CurrencySymbol:"$",CurrencyCode:"USD",AddCurrencySymbol:!0,ThousandsSeparator:"",DecimalSeparator:".",DecimalPlaces:2,MinAmount:1,MaxAmount:1e5,MinAmountMessage:"Amount must be at least $1",MaxAmountMessage:"Amount must be less than $100,000",UseAmountValidatorFromEN:!1,SkipToMainContentLink:!0,SrcDefer:!0,SuppressPurchaseEcard:!1,NeverBounceAPI:null,NeverBounceDateField:null,NeverBounceStatusField:null,NeverBounceDateFormat:"MM/DD/YYYY",NeverBounceTimeout:1e4,FreshAddress:!1,ProgressBar:!1,AutoYear:!1,TranslateFields:!0,Debug:!1,RememberMe:!1,TidyContact:!1,RegionLongFormat:"",CountryDisable:[],Placeholders:!1,ENValidators:!1,MobileCTA:!1,CustomCurrency:!1,CustomPremium:!1,VGS:!1,PostalCodeValidator:!1,CountryRedirect:!1,WelcomeBack:!1,OptInLadder:!1,StickyNSG:!1,StickyPrepopulation:!1,PreferredPaymentMethod:!1,PageLayouts:["leftleft1col","centerleft1col","centercenter1col","centercenter2col","centerright1col","rightright1col","none"]},t={image:"https://picsum.photos/480/650",imagePosition:"left",title:"Will you change your gift to just {new-amount} a month to boost your impact?",paragraph:"Make a monthly pledge today to support us with consistent, reliable resources during emergency moments.",yesLabel:"Yes! Process My {new-amount} monthly gift",noLabel:"No, thanks. Continue with my {old-amount} one-time gift",otherAmount:!0,otherLabel:"Or enter a different monthly amount:",upsellOriginalGiftAmountFieldName:"",amountRange:[{max:10,suggestion:5},{max:15,suggestion:7},{max:20,suggestion:8},{max:25,suggestion:9},{max:30,suggestion:10},{max:35,suggestion:11},{max:40,suggestion:12},{max:50,suggestion:14},{max:100,suggestion:15},{max:200,suggestion:19},{max:300,suggestion:29},{max:500,suggestion:"Math.ceil((amount / 12)/5)*5"}],minAmount:0,canClose:!0,submitOnClose:!1,oneTime:!0,annual:!1,disablePaymentMethods:[],skipUpsell:!1,conversionField:"",upsellCheckbox:!1},i=[{field:"supporter.firstName",translation:"Nome"},{field:"supporter.lastName",translation:"Sobrenome"},{field:"supporter.phoneNumber",translation:"Celular"},{field:"supporter.address1",translation:"EndereΓ§o"},{field:"supporter.address2",translation:"Complemento"},{field:"supporter.postcode",translation:"CEP"},{field:"supporter.city",translation:"Cidade"},{field:"supporter.region",translation:"Estado"},{field:"supporter.country",translation:"PaΓs"}],o=[{field:"supporter.address1",translation:"StraΓe, Hausnummer"},{field:"supporter.postcode",translation:"Postleitzahl"},{field:"supporter.city",translation:"Ort"},{field:"supporter.region",translation:"Bundesland"},{field:"supporter.country",translation:"Land"}],s=[{field:"supporter.address1",translation:"Adresse"},{field:"supporter.postcode",translation:"Code Postal"},{field:"supporter.city",translation:"Ville"},{field:"supporter.region",translation:"RΓ©gion"},{field:"supporter.country",translation:"Country"}],r=[{field:"supporter.address1",translation:"Adres"},{field:"supporter.postcode",translation:"Postcode"},{field:"supporter.city",translation:"Woonplaats"},{field:"supporter.region",translation:"Provincie"},{field:"supporter.country",translation:"Country"}],a={BR:i,BRA:i,DE:o,DEU:o,FR:s,FRA:s,NL:r,NLD:r},l={enabled:!1,title:"We are sad that you are leaving",text:"Would you mind telling us why you are leaving this page?",buttonText:"Send us your comments",buttonLink:"https://www.4sitestudios.com/",cookieName:"engrid-exit-intent-lightbox",cookieDuration:30,triggers:{visibilityState:!0,mousePosition:!0}},c={title:"Before we process your donation...",paragraph:"Would you like to make it an annual gift?",yesButton:"YES! Process my gift as an annual gift of ${upsell_amount}",noButton:"NO! Process my gift as a one-time gift of ${current_amount}",upsellFrequency:"annual",upsellFromFrequency:["onetime"],customClass:"",upsellAmount:e=>e,onOpen:()=>{},onAccept:()=>{},onDecline:()=>{}};class d{constructor(){this.logger=new ye("Loader","gold","black","π"),this.cssElement=document.querySelector('link[href*="engrid."][rel="stylesheet"]'),this.jsElement=document.querySelector('script[src*="engrid."]')}reload(){var e,t,n;const i=this.getOption("assets"),o=g.getBodyData("loaded");let s="false"===this.getOption("engridcss"),r="false"===this.getOption("engridjs");if(o||!i)return s&&this.cssElement&&(this.logger.log("engridcss=false | Removing original stylesheet:",this.cssElement),this.cssElement.remove()),r&&this.jsElement&&(this.logger.log("engridjs=false | Removing original script:",this.jsElement),this.jsElement.remove()),s&&(this.logger.log("engridcss=false | adding top banner CSS"),this.addENgridCSSUnloadedCSS()),r?(this.logger.log("engridjs=false | Skipping JS load."),this.logger.success("LOADED"),!0):(this.logger.success("LOADED"),!1);this.logger.log("RELOADING"),g.setBodyData("loaded","true");const a=g.getBodyData("theme"),l=null!==(e=this.getOption("repo-name"))&&void 0!==e?e:`engrid-${a}`;let c="",d="";switch(i){case"local":this.logger.log("LOADING LOCAL"),g.setBodyData("assets","local"),c=`https://${l}.test/dist/engrid.js`,d=`https://${l}.test/dist/engrid.css`;break;case"flush":this.logger.log("FLUSHING CACHE");const e=Date.now(),o=new URL((null===(t=this.jsElement)||void 0===t?void 0:t.getAttribute("src"))||"");o.searchParams.set("v",e.toString()),c=o.toString();const s=new URL((null===(n=this.cssElement)||void 0===n?void 0:n.getAttribute("href"))||"");s.searchParams.set("v",e.toString()),d=s.toString();break;default:this.logger.log("LOADING EXTERNAL"),c=`https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${l}/${i}/engrid.js`,d=`https://s3.amazonaws.com/engrid-dev.4sitestudios.com/${l}/${i}/engrid.css`}return s&&this.cssElement&&(this.logger.log("engridcss=false | Removing original stylesheet:",this.cssElement),this.cssElement.remove()),s&&d&&""!==d&&this.logger.log("engridcss=false | Skipping injection of stylesheet:",d),s?(this.logger.log("engridcss=false | adding top banner CSS"),this.addENgridCSSUnloadedCSS()):this.setCssFile(d),r&&this.jsElement&&(this.logger.log("engridjs=false | Removing original script:",this.jsElement),this.jsElement.remove()),r&&c&&""!==c&&this.logger.log("engridjs=false | Skipping injection of script:",c),r||this.setJsFile(c),!!i}getOption(e){const t=g.getUrlParameter(e);return t&&["assets","engridcss","engridjs"].includes(e)?t:window.EngridLoader&&window.EngridLoader.hasOwnProperty(e)?window.EngridLoader[e]:this.jsElement&&this.jsElement.hasAttribute("data-"+e)?this.jsElement.getAttribute("data-"+e):null}setCssFile(e){if(""!==e)if(this.cssElement)this.logger.log("Replacing stylesheet:",e),this.cssElement.setAttribute("href",e);else{this.logger.log("Injecting stylesheet:",e);const t=document.createElement("link");t.setAttribute("rel","stylesheet"),t.setAttribute("type","text/css"),t.setAttribute("media","all"),t.setAttribute("href",e),document.head.appendChild(t)}}setJsFile(e){if(""===e)return;this.logger.log("Injecting script:",e);const t=document.createElement("script");t.setAttribute("src",e),document.head.appendChild(t)}addENgridCSSUnloadedCSS(){document.body.insertAdjacentHTML("beforeend",'')}}var u=n(3199);class h{constructor(){this.logger=new ye("EnForm"),this._onIntentSubmit=new u.UD,this._onSubmit=new u.UD,this._onValidate=new u.UD,this._onError=new u.UD,this.submit=!0,this.submitPromise=!1,this.validate=!0,this.validatePromise=!1}static getInstance(){return h.instance||(h.instance=new h),h.instance}dispatchIntentSubmit(){this._onIntentSubmit.dispatch(),this.logger.log("dispatchIntentSubmit")}dispatchSubmit(){this._onSubmit.dispatch(),this.logger.log("dispatchSubmit")}dispatchValidate(){this._onValidate.dispatch(),this.logger.log("dispatchValidate")}dispatchError(){this._onError.dispatch(),this.logger.log("dispatchError")}submitForm(){const e=document.querySelector("form .en__submit button");if(e){const t=document.getElementById("enModal");t&&t.classList.add("is-submitting"),e.click(),this.logger.log("submitForm")}}get onIntentSubmit(){return this._onIntentSubmit.asEvent()}get onSubmit(){return this._onSubmit.asEvent()}get onValidate(){return this._onValidate.asEvent()}get onError(){return this._onError.asEvent()}}class p{constructor(e="transaction.donationAmt",t="transaction.donationAmt.other"){this._onAmountChange=new u.IL,this._amount=0,this._radios="",this._other="",this._dispatch=!0,this._other=t,this._radios=e,document.addEventListener("change",(n=>{const i=n.target;if(i)if(i.name==e)this.amount=parseFloat(i.value);else if(i.name==t){const e=g.cleanAmount(i.value);i.value=e%1!=0?e.toFixed(2):e.toString(),this.amount=e}}));const n=document.querySelector(`[name='${this._other}']`);n&&n.addEventListener("keyup",(e=>{this.amount=g.cleanAmount(n.value)})),this.load()}static getInstance(e="transaction.donationAmt",t="transaction.donationAmt.other"){return p.instance||(p.instance=new p(e,t)),p.instance}get amount(){return this._amount}set amount(e){this._amount=e||0,this._dispatch&&this._onAmountChange.dispatch(this._amount)}get onAmountChange(){return this._onAmountChange.asEvent()}load(){const e=document.querySelector('input[name="'+this._radios+'"]:checked');if(e){let t=parseFloat(e.value||"");if(t>0)this.amount=parseFloat(e.value);else{const e=document.querySelector('input[name="'+this._other+'"]');t=g.cleanAmount(e.value),this.amount=t}}else if(g.checkNested(window.EngagingNetworks,"require","_defined","enjs","getDonationTotal")&&g.checkNested(window.EngagingNetworks,"require","_defined","enjs","getDonationFee")){const e=window.EngagingNetworks.require._defined.enjs.getDonationTotal()-window.EngagingNetworks.require._defined.enjs.getDonationFee();e&&(this.amount=e)}}setAmount(e,t=!0){if(!document.getElementsByName(this._radios).length)return;this._dispatch=t;let n=Array.from(document.querySelectorAll('input[name="'+this._radios+'"]')).filter((t=>t instanceof HTMLInputElement&&parseInt(t.value)==e));if(n.length){const e=n[0];e.checked=!0;const t=new Event("change",{bubbles:!0,cancelable:!0});e.dispatchEvent(t),this.clearOther()}else{const t=document.querySelector('input[name="'+this._other+'"]');if(t){const n=document.querySelector(`.en__field--donationAmt.en__field--withOther .en__field__item:nth-last-child(2) input[name="${this._radios}"]`);n&&(n.checked=!0),t.value=parseFloat(e.toString()).toFixed(2);const i=new Event("change",{bubbles:!0,cancelable:!0});t.dispatchEvent(i);t.parentNode.classList.remove("en__field__item--hidden")}}this.amount=e,this._dispatch=!0}clearOther(){const e=document.querySelector('input[name="'+this._other+'"]');e.value="";e.parentNode.classList.add("en__field__item--hidden")}}class g{constructor(){if(!g.enForm)throw new Error("Engaging Networks Form Not Found!")}static get enForm(){return document.querySelector("form.en__component")}static get debug(){return!!this.getOption("Debug")}static get demo(){return"DEMO"===this.getUrlParameter("mode")}static getUrlParameter(e){const t=new URLSearchParams(window.location.search);if(e.endsWith("[]")){let n=[];return t.forEach(((t,i)=>{i.startsWith(e.replace("[]",""))&&n.push(new Object({[i]:t}))})),n.length>0?n:null}return t.has(e)?t.get(e)||!0:null}static getField(e){return document.querySelector(`[name="${e}"]`)}static getFieldValue(e){return new FormData(this.enForm).getAll(e).join(",")}static setFieldValue(e,t,n=!0,i=!1){t!==g.getFieldValue(e)&&(document.getElementsByName(e).forEach((e=>{if("type"in e){switch(e.type){case"select-one":case"select-multiple":for(const n of e.options)n.value==t&&(n.selected=!0,i&&e.dispatchEvent(new Event("change",{bubbles:!0})));break;case"checkbox":case"radio":e.value==t&&(e.checked=!0,i&&e.dispatchEvent(new Event("change",{bubbles:!0})));break;default:e.value=t,i&&(e.dispatchEvent(new Event("change",{bubbles:!0})),e.dispatchEvent(new Event("blur",{bubbles:!0})))}e.setAttribute("engrid-value-changed","")}})),n&&this.enParseDependencies())}static createHiddenInput(e,t=""){var n;const i=document.createElement("div");i.classList.add("en__component","en__component--formblock","hide");const o=document.createElement("div");o.classList.add("en__field","en__field--text");const s=document.createElement("div");s.classList.add("en__field__element","en__field__element--text");const r=document.createElement("input");r.classList.add("en__field__input","en__field__input--text","engrid-added-input"),r.setAttribute("name",e),r.setAttribute("type","hidden"),r.setAttribute("value",t),s.appendChild(r),o.appendChild(s),i.appendChild(o);const a=document.querySelector(".en__submit");if(a){const e=a.closest(".en__component");e&&(null===(n=e.parentNode)||void 0===n||n.insertBefore(i,e.nextSibling))}else g.enForm.appendChild(i);return r}static enParseDependencies(){var e,t,n,i,o,s;if(window.EngagingNetworks&&"function"==typeof(null===(o=null===(i=null===(n=null===(t=null===(e=window.EngagingNetworks)||void 0===e?void 0:e.require)||void 0===t?void 0:t._defined)||void 0===n?void 0:n.enDependencies)||void 0===i?void 0:i.dependencies)||void 0===o?void 0:o.parseDependencies)){const e=[];if("dependencies"in window.EngagingNetworks){const t=document.querySelector(".en__field--donationAmt");if(t){let n=(null===(s=[...t.classList.values()].filter((e=>e.startsWith("en__field--")&&Number(e.substring(11))>0)).toString().match(/\d/g))||void 0===s?void 0:s.join(""))||"";n&&(window.EngagingNetworks.dependencies.forEach((t=>{if("actions"in t&&t.actions.length>0){let i=!1;t.actions.forEach((e=>{"target"in e&&e.target==n&&(i=!0)})),i||e.push(t)}})),e.length>0&&(window.EngagingNetworks.require._defined.enDependencies.dependencies.parseDependencies(e),g.getOption("Debug")&&console.log("EN Dependencies Triggered",e)))}}}}static getGiftProcess(){return"pageJson"in window?window.pageJson.giftProcess:null}static getPageCount(){return"pageJson"in window?window.pageJson.pageCount:null}static getPageNumber(){return"pageJson"in window?window.pageJson.pageNumber:null}static isThankYouPage(){return this.getPageNumber()===this.getPageCount()}static getPageID(){return"pageJson"in window?window.pageJson.campaignPageId:0}static getPageIdFromUrl(e){if(!e)return 0;const t=e.match(/\/page\/(\d+)(?:\/|$|\?|#)/);if(!t)return 0;const n=parseInt(t[1],10);return Number.isFinite(n)?n:0}static getClientID(){return"pageJson"in window?window.pageJson.clientId:0}static getDataCenter(){return g.getClientID()>=1e4?"us":"ca"}static getPageType(){if(!("pageJson"in window)||!("pageType"in window.pageJson))return"UNKNOWN";switch(window.pageJson.pageType){case"p2pcheckout":case"p2pdonation":case"donation":case"premiumgift":return"DONATION";case"e-card":return"ECARD";case"otherdatacapture":case"survey":return"SURVEY";case"emailtotarget":return"EMAILTOTARGET";case"advocacypetition":return"ADVOCACY";case"emailsubscribeform":return"SUBSCRIBEFORM";case"event":return"EVENT";case"supporterhub":return"SUPPORTERHUB";case"unsubscribe":return"UNSUBSCRIBE";case"tweetpage":return"TWEETPAGE";default:return"UNKNOWN"}}static setBodyData(e,t){const n=document.querySelector("body");"boolean"!=typeof t||!1!==t?n.setAttribute(`data-engrid-${e}`,t.toString()):n.removeAttribute(`data-engrid-${e}`)}static getBodyData(e){return document.querySelector("body").getAttribute(`data-engrid-${e}`)}static hasBodyData(e){return document.querySelector("body").hasAttribute(`data-engrid-${e}`)}static getOption(e){return window.EngridOptions[e]||null}static loadJS(e,t=null,n=!0){const i=document.createElement("script");i.src=e,i.onload=t,n?document.head.appendChild(i):document.body.appendChild(i)}static formatNumber(e,t=2,n=".",i=","){e=(e+"").replace(/[^0-9+\-Ee.]/g,"");const o=isFinite(+e)?+e:0,s=isFinite(+t)?Math.abs(t):0,r=void 0===i?",":i,a=void 0===n?".":n;let l=[];return l=(s?function(e,t){const n=Math.pow(10,t);return""+Math.round(e*n)/n}(o,s):""+Math.round(o)).split("."),l[0].length>3&&(l[0]=l[0].replace(/\B(?=(?:\d{3})+(?!\d))/g,r)),(l[1]||"").lengthn>0&&n+1!==t.length&&3!==e.length)).includes(!0))return 0;if(n.length>1&&!n.includes("."))return 0;if([...new Set(n.slice(0,-1))].length>1)return 0;if(t[t.length-1].length<=2){const e=t.pop()||"00";return parseInt(e)>0?parseFloat(Number(parseInt(t.join(""))+"."+e).toFixed(2)):parseInt(t.join(""))}return parseInt(t.join(""))}static disableSubmit(e=""){const t=document.querySelector(".en__submit button");if(!t)return!1;let n=`${e} `;return!t.innerHTML.includes("loader-wrapper")&&(t.dataset.originalText=t.innerHTML,t.disabled=!0,t.innerHTML=n,!0)}static enableSubmit(){const e=document.querySelector(".en__submit button");return!!e&&(!!e.dataset.originalText&&(e.disabled=!1,e.innerHTML=e.dataset.originalText,delete e.dataset.originalText,!0))}static formatDate(e,t="MM/DD/YYYY"){const n=e.toLocaleDateString("en-US",{year:"numeric",month:"2-digit",day:"2-digit"}).split("/");return t.replace(/YYYY/g,n[2]).replace(/MM/g,n[0]).replace(/DD/g,n[1]).replace(/YY/g,n[2].substr(2,2))}static checkNested(e,...t){for(let n=0;n0&&(n=n.substring(0,n.indexOf("("))),n=n.replace(/[^a-zA-Z0-9]/g,""),n=n.substring(0,20),n="engrid"+((i=n).charAt(0).toUpperCase()+i.slice(1)),t&&!t.dataset[n]){t.dataset[n]="true";new MutationObserver((function(t){t.forEach((function(t){"childList"===t.type&&t.addedNodes.length>0&&e()}))})).observe(t,{childList:!0})}}static getPaymentType(){return g.getFieldValue("transaction.paymenttype")}static setPaymentType(e){const t=g.getField("transaction.paymenttype");if(t){const n=Array.from(t.options).find((t=>"card"===e.toLowerCase()?["card","visa","vi"].includes(t.value.toLowerCase()):e.toLowerCase()===t.value.toLowerCase()));n?(n.selected=!0,t.value=n.value):t.value=e;const i=new Event("change",{bubbles:!0,cancelable:!0});t.dispatchEvent(i)}}static isInViewport(e){const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)}}class m{constructor(){this._onFrequencyChange=new u.IL,this._frequency="onetime",this._recurring="n",this._dispatch=!0,document.addEventListener("change",(e=>{const t=e.target;t&&"transaction.recurrpay"==t.name&&(this.recurring=t.value,"radio"==t.type&&(this.frequency="n"==t.value.toLowerCase()?"onetime":"monthly",g.setFieldValue("transaction.recurrfreq",this.frequency.toUpperCase()))),t&&"transaction.recurrfreq"==t.name&&(this.frequency=t.value)})),g.getGiftProcess()&&(g.setBodyData("transaction-recurring-frequency",sessionStorage.getItem("engrid-transaction-recurring-frequency")||"onetime"),g.setBodyData("transaction-recurring",window.pageJson.recurring?"y":"n"))}static getInstance(){return m.instance||(m.instance=new m),m.instance}get frequency(){return this._frequency}set frequency(e){this._frequency=e.toLowerCase()||"onetime",this._dispatch&&this._onFrequencyChange.dispatch(this._frequency),g.setBodyData("transaction-recurring-frequency",this._frequency),sessionStorage.setItem("engrid-transaction-recurring-frequency",this._frequency)}get recurring(){return this._recurring}set recurring(e){this._recurring=e.toLowerCase()||"n",g.setBodyData("transaction-recurring",this._recurring)}get onFrequencyChange(){return this._onFrequencyChange.asEvent()}load(){var e;this.frequency=g.getFieldValue("transaction.recurrfreq")||sessionStorage.getItem("engrid-transaction-recurring-frequency")||"onetime";g.getField("transaction.recurrpay")?this.recurring=g.getFieldValue("transaction.recurrpay"):g.checkNested(window.EngagingNetworks,"require","_defined","enjs","getSupporterData")&&(this.recurring=(null===(e=window.EngagingNetworks.require._defined.enjs.getSupporterData("recurrpay"))||void 0===e?void 0:e.toLowerCase())||"n")}setRecurrency(e,t=!0){document.getElementsByName("transaction.recurrpay").length&&(this._dispatch=t,g.setFieldValue("transaction.recurrpay",e.toUpperCase()),this._dispatch=!0)}setFrequency(e,t=!0){if(!document.getElementsByName("transaction.recurrfreq").length)return;this._dispatch=t;let n=Array.from(document.querySelectorAll('input[name="transaction.recurrfreq"]')).filter((t=>t instanceof HTMLInputElement&&t.value==e.toUpperCase()));if(n.length){n[0].checked=!0,this.frequency=e.toLowerCase(),"onetime"===this.frequency?this.setRecurrency("N",t):this.setRecurrency("Y",t)}this._dispatch=!0}}class f{constructor(){this._onFeeChange=new u.IL,this._amount=p.getInstance(),this._form=h.getInstance(),this._fee=0,this._field=null,document.getElementsByName("transaction.donationAmt").length&&(this._field=this.isENfeeCover()?document.querySelector("#en__field_transaction_feeCover"):document.querySelector('input[name="supporter.processing_fees"]'),this._field instanceof HTMLInputElement&&this._field.addEventListener("change",(e=>{this._field instanceof HTMLInputElement&&this._field.checked&&!this._subscribe&&(this._subscribe=this._form.onSubmit.subscribe((()=>this.addFees()))),this._onFeeChange.dispatch(this.fee)})))}static getInstance(){return f.instance||(f.instance=new f),f.instance}get onFeeChange(){return this._onFeeChange.asEvent()}get fee(){return this.calculateFees()}set fee(e){this._fee=e,this._onFeeChange.dispatch(this._fee)}calculateFees(e=0){var t;if(this._field instanceof HTMLInputElement&&this._field.checked){if(this.isENfeeCover())return e>0?window.EngagingNetworks.require._defined.enjs.feeCover.fee(e):window.EngagingNetworks.require._defined.enjs.getDonationFee();const n=Object.assign({processingfeepercentadded:"0",processingfeefixedamountadded:"0"},null===(t=this._field)||void 0===t?void 0:t.dataset),i=e>0?e:this._amount.amount,o=parseFloat(n.processingfeepercentadded)/100*i+parseFloat(n.processingfeefixedamountadded);return Math.round(100*o)/100}return 0}addFees(){this._form.submit&&!this.isENfeeCover()&&this._amount.setAmount(this._amount.amount+this.fee,!1)}removeFees(){this.isENfeeCover()||this._amount.setAmount(this._amount.amount-this.fee)}isENfeeCover(){if("feeCover"in window.EngagingNetworks)for(const e in window.EngagingNetworks.feeCover)if(window.EngagingNetworks.feeCover.hasOwnProperty(e))return!0;return!1}}class b{constructor(){this.logger=new ye("RememberMeEvents"),this._onLoad=new u.IL,this._onClear=new u.UD,this.hasData=!1}static getInstance(){return b.instance||(b.instance=new b),b.instance}dispatchLoad(e){this.hasData=e,this._onLoad.dispatch(e),this.logger.log(`dispatchLoad: ${e}`)}dispatchClear(){this._onClear.dispatch(),this.logger.log("dispatchClear")}get onLoad(){return this._onLoad.asEvent()}get onClear(){return this._onClear.asEvent()}}class y{constructor(){this._onCountryChange=new u.IL,this._country="",this._field=null,this._field=document.getElementById("en__field_supporter_country"),this._field&&(document.addEventListener("change",(e=>{const t=e.target;t&&"supporter.country"==t.name&&(this.country=t.value)})),this.country=g.getFieldValue("supporter.country"))}static getInstance(){return y.instance||(y.instance=new y),y.instance}get countryField(){return this._field}get onCountryChange(){return this._onCountryChange.asEvent()}get country(){return this._country}set country(e){this._country=e,this._onCountryChange.dispatch(this._country)}}class v extends g{constructor(t){super(),this._form=h.getInstance(),this._fees=f.getInstance(),this._amount=p.getInstance("transaction.donationAmt","transaction.donationAmt.other"),this._frequency=m.getInstance(),this._country=y.getInstance(),this.logger=new ye("App","black","white","π");const n=new d;this.options=Object.assign(Object.assign({},e),t),window.EngridOptions=this.options,this._dataLayer=we.getInstance(),!0!==g.getUrlParameter("pbedit")&&"true"!==g.getUrlParameter("pbedit")?n.reload()||("local"===g.getBodyData("assets")&&"false"!==g.getUrlParameter("debug")&&"log"!==g.getUrlParameter("debug")&&(window.EngridOptions.Debug=!0),"loading"!==document.readyState?this.run():document.addEventListener("DOMContentLoaded",(()=>{this.run()})),window.onresize=()=>{this.onResize()}):window.location.href=`https://${g.getDataCenter()}.engagingnetworks.app/index.html#pages/${g.getPageID()}/edit`}run(){if(!g.checkNested(window.EngagingNetworks,"require","_defined","enjs"))return this.logger.danger("Engaging Networks JS Framework NOT FOUND"),void setTimeout((()=>{this.run()}),100);window.hasOwnProperty("EngridPageOptions")&&(this.options=Object.assign(Object.assign({},this.options),window.EngridPageOptions),window.EngridOptions=this.options),g.checkNested(window,"pageJson","pageType")||window.setTimeout((()=>{console.log("%c βοΈ pageJson.pageType NOT FOUND - Go to the Account Settings and Expose the Transaction Details %s","background-color: red; color: white; font-size: 22px; font-weight: bold;","https://knowledge.engagingnetworks.net/datareports/expose-transaction-details-pagejson")}),2e3),(this.options.Debug||"true"==v.getUrlParameter("debug"))&&v.setBodyData("debug",""),new H,new W,new $,new Ye,new Q("transaction.giveBySelect","giveBySelect-"),new Q("transaction.inmem","inmem-"),new Q("transaction.recurrpay","recurrpay-"),new Q("transaction.shipenabled","shipenabled-");let e=[];document.querySelectorAll("input[type=radio]").forEach((t=>{"name"in t&&!1===e.includes(t.name)&&e.push(t.name)})),e.forEach((e=>{new Q(e,"engrid__"+e.replace(/\./g,"")+"-")}));document.querySelectorAll("input[type=checkbox]").forEach((e=>{"name"in e&&new Q(e.name,"engrid__"+e.name.replace(/\./g,"")+"-")})),this._form.onIntentSubmit.subscribe((()=>this.onIntentSubmit())),this._form.onSubmit.subscribe((()=>this.onSubmit())),this._form.onError.subscribe((()=>this.onError())),this._form.onValidate.subscribe((()=>this.onValidate())),this._amount.onAmountChange.subscribe((e=>this.logger.success(`Live Amount: ${e}`))),this._frequency.onFrequencyChange.subscribe((e=>{this.logger.success(`Live Frequency: ${e}`),setTimeout((()=>{this._amount.load()}),150)})),this._form.onSubmit.subscribe((e=>this.logger.success("Submit: "+JSON.stringify(e)))),this._form.onError.subscribe((e=>this.logger.danger("Error: "+JSON.stringify(e)))),this._country.onCountryChange.subscribe((e=>this.logger.success(`Country: ${e}`))),window.enOnSubmit=()=>(this._form.submit=!0,this._form.submitPromise=!1,this._form.dispatchIntentSubmit(),this._form.dispatchSubmit(),g.watchForError(g.enableSubmit),!!this._form.submit&&(this._form.submitPromise?this._form.submitPromise:(this.logger.success("enOnSubmit Success"),!0))),window.enOnError=()=>{this._form.dispatchError()},window.enOnValidate=()=>(this._form.validate=!0,this._form.validatePromise=!1,this._form.dispatchValidate(),!!this._form.validate&&(this._form.validatePromise?this._form.validatePromise:(this.logger.success("Validation Passed"),!0))),new j,new st,new G,new J(this.options),new ce,new K,new X,new _,new Ee,new Ae,new Pe,new Oe,new bt,new De,window.setTimeout((()=>{this._frequency.load()}),1e3),new Qe,new xe,new Te,new re,this.options.MediaAttribution&&new Y,this.options.applePay&&new D,this.options.CapitalizeFields&&new M,this.options.AutoYear&&new B,new R,new V,this.options.ClickToExpand&&new U,this.options.SkipToMainContentLink&&new ae,this.options.SrcDefer&&new le,this.options.ProgressBar&&new pe;try{this.options.RememberMe&&"object"==typeof this.options.RememberMe&&window.localStorage&&new me(this.options.RememberMe)}catch(e){}this.options.NeverBounceAPI&&new ue(this.options.NeverBounceAPI,this.options.NeverBounceDateField,this.options.NeverBounceStatusField,this.options.NeverBounceDateFormat),this.options.FreshAddress&&new he,new fe,new be,new ve,new _e,new I,new Ce,new ke,new de,new Le,new Fe,new tt,this.options.Debug&&new Me,this.options.TidyContact&&new Ne,this.options.TranslateFields&&new se,new Ve,new Ue,new He,new Ke,"DONATION"===g.getPageType()&&(new je,new _t),new Ge,new $e,new We,new ze,new Xe,new Je,new Ze,new et,new it,new ot,new rt,new lt,new ut,new ht,new dt,new pt,new gt,new ft,new vt;let t=this.options.Debug;try{!t&&window.sessionStorage.hasOwnProperty(Ie.debugSessionStorageKey)&&(t=!0)}catch(e){}t&&new Ie(this.options.PageLayouts),"branding"===g.getUrlParameter("development")&&(new Re).show(),g.setBodyData("js-loading","finished"),window.EngridVersion=St,this.logger.success(`VERSION: ${St}`);let n="function"==typeof window.onload?window.onload:null;"loading"!==document.readyState?this.onLoad():window.onload=e=>{this.onLoad(),n&&n.bind(window,e)}}onLoad(){this.options.onLoad&&this.options.onLoad()}onResize(){this.options.onResize&&this.options.onResize()}onValidate(){this.options.onValidate&&(this.logger.log("Client onValidate Triggered"),this.options.onValidate())}onIntentSubmit(){this.options.onIntentSubmit&&(this.logger.log("Client onIntentSubmit Triggered"),this.options.onIntentSubmit())}onSubmit(){this.options.onSubmit&&(this.logger.log("Client onSubmit Triggered"),this.options.onSubmit())}onError(){this.options.onError&&(this.logger.danger("Client onError Triggered"),this.options.onError())}static log(e){new ye("Client","brown","aliceblue","πͺ").log(e)}}class _{constructor(){this._frequency=m.getInstance(),this.shouldRun()&&(this._frequency.onFrequencyChange.subscribe((e=>window.setTimeout(this.fixAmountLabels.bind(this),100))),window.setTimeout(this.fixAmountLabels.bind(this),300))}shouldRun(){return!("DONATION"!==g.getPageType()||!g.getOption("AddCurrencySymbol"))}fixAmountLabels(){let e=document.querySelectorAll(".en__field--donationAmt label");const t=g.getCurrencySymbol()||"";e.forEach((e=>{const n=e.innerText.replace(/,/g,"").replace(/\./g,"");isNaN(n)||(e.innerText=t+e.innerText)}))}}var S=function(e,t,n,i){return new(n||(n=Promise))((function(o,s){function r(e){try{l(i.next(e))}catch(e){s(e)}}function a(e){try{l(i.throw(e))}catch(e){s(e)}}function l(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}l((i=i.apply(e,t||[])).next())}))};const w=window.ApplePaySession,E=window.merchantIdentifier,A=window.merchantDomainName,C=window.merchantDisplayName,k=window.merchantSessionIdentifier,L=window.merchantNonce,F=window.merchantEpochTimestamp,q=window.merchantSignature,N=window.merchantCountryCode,x=window.merchantCurrencyCode,T=window.merchantSupportedNetworks,P=window.merchantCapabilities,O=window.merchantTotalLabel;class D{constructor(){this.applePay=document.querySelector('.en__field__input.en__field__input--radio[value="applepay"]'),this._amount=p.getInstance(),this._fees=f.getInstance(),this._form=h.getInstance(),this.checkApplePay()}checkApplePay(){return S(this,void 0,void 0,(function*(){const e=document.querySelector("form.en__component--page");if(!this.applePay||!window.hasOwnProperty("ApplePaySession")){const e=document.querySelector(".en__field__item.applepay");return e&&e.remove(),g.debug&&console.log("Apple Pay DISABLED"),!1}const t=w.canMakePaymentsWithActiveCard(E);let n=!1;yield t.then((t=>{if(n=t,t){let t=document.createElement("input");t.setAttribute("type","hidden"),t.setAttribute("name","PkPaymentToken"),t.setAttribute("id","applePayToken"),e.appendChild(t),this._form.onSubmit.subscribe((()=>this.onPayClicked()))}})),g.debug&&console.log("applePayEnabled",n);let i=this.applePay.closest(".en__field__item");return n?null==i||i.classList.add("applePayWrapper"):i&&(i.style.display="none"),n}))}performValidation(e){return new Promise((function(t,n){var i={};i.merchantIdentifier=E,i.merchantSessionIdentifier=k,i.nonce=L,i.domainName=A,i.epochTimestamp=F,i.signature=q;var o="/ea-dataservice/rest/applepay/validateurl?url="+e+("&merchantIdentifier="+E+"&merchantDomain="+A+"&displayName="+C),s=new XMLHttpRequest;s.onload=function(){var e=JSON.parse(this.responseText);g.debug&&console.log("Apple Pay Validation",e),t(e)},s.onerror=n,s.open("GET",o),s.send()}))}log(e,t){var n=new XMLHttpRequest;n.open("GET","/ea-dataservice/rest/applepay/log?name="+e+"&msg="+t),n.send()}sendPaymentToken(e){return new Promise((function(e,t){e(!0)}))}onPayClicked(){if(!this._form.submit)return;const e=document.querySelector("#en__field_transaction_paymenttype"),t=document.getElementById("applePayToken"),n=this._form;if("applepay"==e.value&&""==t.value)try{let e=this._amount.amount+this._fees.fee;var i=new w(1,{supportedNetworks:T,merchantCapabilities:P,countryCode:N,currencyCode:x,total:{label:O,amount:e}}),o=this;return i.onvalidatemerchant=function(e){o.performValidation(e.validationURL).then((function(e){g.debug&&console.log("Apple Pay merchantSession",e),i.completeMerchantValidation(e)}))},i.onpaymentauthorized=function(e){o.sendPaymentToken(e.payment.token).then((function(t){g.debug&&console.log("Apple Pay Token",e.payment.token),document.getElementById("applePayToken").value=JSON.stringify(e.payment.token),n.submitForm()}))},i.oncancel=function(e){g.debug&&console.log("Cancelled",e),alert("You cancelled. Sorry it didn't work out."),n.dispatchError()},i.begin(),this._form.submit=!1,!1}catch(e){alert("Developer mistake: '"+e.message+"'"),n.dispatchError()}return this._form.submit=!0,!0}}class I{constructor(){this.addRequired(),this.addLabel(),this.addGroupRole(),this.updateFrequencyLabel();const e=document.querySelectorAll(".en__ecarditems__list img");this.setAutoGeneratedAltTags(e),this.manageErrorListAlertRole()}addGroupRole(){document.querySelectorAll(".en__field--radio").forEach((e=>{e.setAttribute("role","group");const t=e.querySelector("label");t&&(t.setAttribute("id",`en__field__label--${Math.random().toString(36).slice(2,7)}`),e.setAttribute("aria-labelledby",t.id))}))}addRequired(){document.querySelectorAll(".en__mandatory .en__field__input").forEach((e=>{e.setAttribute("aria-required","true")}))}addLabel(){const e=document.querySelector(".en__field__input--otheramount");e&&e.setAttribute("aria-label","Enter your custom donation amount");document.querySelectorAll(".en__field__input--splitselect").forEach((e=>{var t,n,i,o;const s=e.querySelector("option");!s||""!==s.value||(null===(n=null===(t=s.textContent)||void 0===t?void 0:t.toLowerCase())||void 0===n?void 0:n.includes("select"))||(null===(o=null===(i=s.textContent)||void 0===i?void 0:i.toLowerCase())||void 0===o?void 0:o.includes("choose"))||e.setAttribute("aria-label",s.textContent||"")}))}updateFrequencyLabel(){const e=document.querySelectorAll('div.en__field__item input[id^="en__field_transaction_recurrfreq"]'),t=document.querySelector('label[for="en__field_transaction_recurrfreq"]');e.forEach((e=>{e&&(e.checked&&(null==t||t.setAttribute("for",e.id)),e.addEventListener("click",(()=>{let n=e.id;null==t||t.setAttribute("for",n)})))}))}setAutoGeneratedAltTags(e){e.forEach((e=>{var t;if(!e.alt)try{const n=e.src;if(!n)throw new Error("Image src is null or undefined");const i=new URL(n).pathname.split("/").pop();if(!i)throw new Error("No filename found in src");let o=(null===(t=i.split(".").shift())||void 0===t?void 0:t.replace(/[-_]/g," "))||"";o=o.replace(/\d+x\d+.*$/,"").trim(),o=`This is an auto-generated alt tag from the filename: ${o}`,e.alt=o}catch(t){console.error(`Error processing image: ${e.src}`,t)}}))}manageErrorListAlertRole(){const e=document.querySelector("ul.en__errorList");if(!e)return;const t=()=>Boolean(e.querySelector("li")),n=()=>{e.hasAttribute("role")||e.setAttribute("role","alert")},i=()=>{e.hasAttribute("role")&&e.removeAttribute("role")};t()?n():i(),new MutationObserver((e=>{for(const o of e)if("childList"===o.type){t()?n():i();break}})).observe(e,{childList:!0})}}class M{constructor(){this._form=h.getInstance(),this._form.onSubmit.subscribe((()=>this.capitalizeFields("en__field_supporter_firstName","en__field_supporter_lastName","en__field_supporter_address1","en__field_supporter_city")))}capitalizeFields(...e){e.forEach((e=>this.capitalize(e)))}capitalize(e){let t=document.getElementById(e);return t&&(t.value=t.value.replace(/\w\S*/g,(e=>e.replace(/^\w/,(e=>e.toUpperCase())))),g.debug&&console.log("Capitalized",t.value)),!0}}class B{constructor(){if(this.yearField=document.querySelector("select[name='transaction.ccexpire']:not(#en__field_transaction_ccexpire)"),this.years=20,this.yearLength=2,this.yearField){this.clearFieldOptions();for(let e=0;e{var t;if(""!==e.value&&!isNaN(Number(e.value))){const n=[...this.yearField.options].findIndex((t=>t.value===e.value));null===(t=this.yearField)||void 0===t||t.remove(n)}})))}}class R{constructor(){this.logger=new ye("Autocomplete","#330033","#f0f0f0","π"),this.autoCompleteField('[name="supporter.firstName"]',"given-name"),this.autoCompleteField('[name="supporter.lastName"]',"family-name"),this.autoCompleteField("#en__field_transaction_ccexpire","cc-exp-month"),this.autoCompleteField('[name="transaction.ccexpire"]:not(#en__field_transaction_ccexpire)',"cc-exp-year"),this.autoCompleteField('[name="supporter.emailAddress"]',"email"),this.autoCompleteField('[name="supporter.phoneNumber"]',"tel"),this.autoCompleteField('[name="supporter.country"]',"country"),this.autoCompleteField('[name="supporter.address1"]',"address-line1"),this.autoCompleteField('[name="supporter.address2"]',"address-line2"),this.autoCompleteField('[name="supporter.city"]',"address-level2"),this.autoCompleteField('[name="supporter.region"]',"address-level1"),this.autoCompleteField('[name="supporter.postcode"]',"postal-code"),this.autoCompleteField('[name="transaction.honname"]',"none"),this.autoCompleteField('[name="transaction.infemail"]',"none"),this.autoCompleteField('[name="transaction.infname"]',"none"),this.autoCompleteField('[name="transaction.infadd1"]',"none"),this.autoCompleteField('[name="transaction.infadd2"]',"none"),this.autoCompleteField('[name="transaction.infcity"]',"none"),this.autoCompleteField('[name="transaction.infpostcd"]',"none")}autoCompleteField(e,t){let n=document.querySelector(e);return n?(n.autocomplete=t,!0):("none"!==t&&this.logger.log("Field Not Found",e),!1)}}class V{constructor(){if(this._form=h.getInstance(),this.logger=new ye("Ecard","red","#f5f5f5","πͺͺ"),!this.shouldRun())return;this._form.onValidate.subscribe((()=>this.checkRecipientFields()));const e=g.getUrlParameter("engrid_ecard.schedule"),t=g.getField("ecard.schedule"),n=g.getUrlParameter("engrid_ecard.name"),i=document.querySelector(".en__ecardrecipients__name input"),o=g.getUrlParameter("engrid_ecard.email"),s=document.querySelector(".en__ecardrecipients__email input");if(e&&t){const n=new Date(e.toString()),i=new Date;n.setHours(0,0,0,0){const t='
'+e.innerHTML+"
";e.innerHTML=t,e.addEventListener("click",(t=>{t&&(g.debug&&console.log("A click-to-expand div was clicked"),e.classList.add("expanded"))})),e.addEventListener("keydown",(t=>{"Enter"===t.key?(g.debug&&console.log("A click-to-expand div had the 'Enter' key pressed on it"),e.classList.add("expanded")):" "===t.key&&(g.debug&&console.log("A click-to-expand div had the 'Spacebar' key pressed on it"),e.classList.add("expanded"),t.preventDefault(),t.stopPropagation())}))}))}}class H{constructor(){this.logger=new ye("Advocacy","#232323","#f7b500","π¨ββοΈ"),this.shoudRun()&&this.setClickableLabels()}shoudRun(){return["ADVOCACY","EMAILTOTARGET"].includes(g.getPageType())}setClickableLabels(){const e=document.querySelectorAll(".en__contactDetails__rows");e&&e.forEach((e=>{e.addEventListener("click",(t=>{this.toggleCheckbox(e)}))}))}toggleCheckbox(e){const t=e.closest(".en__contactDetails");if(!t)return;const n=t.querySelector("input[type='checkbox']");n&&(this.logger.log("toggleCheckbox",n.checked),n.checked=!n.checked)}}class j{constructor(){this.logger=new ye("Data Attribute Changed","#FFFFFF","#4d9068","π οΈ"),this._country=y.getInstance(),this._frequency=m.getInstance(),this.setDataAttributes()}setDataAttributes(){window.hasOwnProperty("ApplePaySession")?g.setBodyData("apple-pay-available","true"):g.setBodyData("apple-pay-available","false"),g.checkNested(window,"pageJson","pageType")&&g.setBodyData("page-type",window.pageJson.pageType),g.setBodyData("currency-code",g.getCurrencyCode()),document.querySelector(".body-banner img, .body-banner video")||g.setBodyData("body-banner","empty"),document.querySelector(".page-alert *")||g.setBodyData("no-page-alert",""),document.querySelector(".content-header *")||g.setBodyData("no-content-header",""),document.querySelector(".body-headerOutside *")||g.setBodyData("no-body-headerOutside",""),document.querySelector(".body-header *")||g.setBodyData("no-body-header",""),document.querySelector(".body-title *")||g.setBodyData("no-body-title",""),document.querySelector(".body-banner *")||g.setBodyData("no-body-banner",""),document.querySelector(".body-bannerOverlay *")||g.setBodyData("no-body-bannerOverlay",""),document.querySelector(".body-top *")||g.setBodyData("no-body-top",""),document.querySelector(".body-main *")||g.setBodyData("no-body-main",""),document.querySelector(".body-bottom *")||g.setBodyData("no-body-bottom",""),document.querySelector(".body-footer *")||g.setBodyData("no-body-footer",""),document.querySelector(".body-footerOutside *")||g.setBodyData("no-body-footerOutside",""),document.querySelector(".content-footerSpacer *")||g.setBodyData("no-content-footerSpacer",""),document.querySelector(".content-preFooter *")||g.setBodyData("no-content-preFooter",""),document.querySelector(".content-footer *")||g.setBodyData("no-content-footer",""),document.querySelector(".page-backgroundImage img, .page-backgroundImage video")||g.setBodyData("no-page-backgroundImage",""),document.querySelector(".page-backgroundImageOverlay *")||g.setBodyData("no-page-backgroundImageOverlay",""),document.querySelector(".page-customCode *")||g.setBodyData("no-page-customCode",""),this._country.country&&(g.setBodyData("country",this._country.country),this._country.onCountryChange.subscribe((e=>{g.setBodyData("country",e)})));const e=document.querySelector(".en__field--donationAmt .en__field__item--other");e&&e.setAttribute("data-currency-symbol",g.getCurrencySymbol());const t=g.getField("transaction.paymenttype");t&&(g.setBodyData("payment-type",t.value),t.addEventListener("change",(()=>{g.setBodyData("payment-type",t.value)})));const n=document.querySelector(".content-footer");n&&g.isInViewport(n)?g.setBodyData("footer-above-fold",""):g.setBodyData("footer-below-fold",""),g.demo&&g.setBodyData("demo",""),1===g.getPageNumber()&&g.setBodyData("first-page",""),g.getPageNumber()===g.getPageCount()&&g.setBodyData("last-page",""),CSS.supports("selector(:has(*))")||g.setBodyData("css-has-selector","false"),"DONATION"===g.getPageType()&&(this.addFrequencyDataAttribute(),this.addGiftAmountDataAttribute())}addFrequencyDataAttribute(){const e=document.querySelectorAll(".en__field--recurrfreq .en__field__item label.en__field__label");let t=0;e.forEach((e=>{g.isVisible(e)&&t++})),g.setBodyData("visible-frequency",t.toString())}addGiftAmountDataAttribute(){const e=()=>{const e=document.querySelectorAll(".en__field--donationAmt .en__field__element .en__field__item");let t=0;e.forEach((e=>{g.isVisible(e)&&t++})),g.setBodyData("visible-gift-amount",t.toString()),this.logger.log("Visible Gift Amount Changed to: "+t.toString())};e();const t=new MutationObserver(e),n=document.querySelector(".en__field--donationAmt");n&&t.observe(n,{childList:!0,subtree:!0,attributes:!0}),this._frequency.onFrequencyChange.subscribe((()=>{setTimeout((()=>{e()}),10)}))}}class G{constructor(){if(this._form=h.getInstance(),this.logger=new ye("iFrame","brown","gray","π‘"),this.inIframe()){g.setBodyData("embedded","");const e=/\/page\/\d+\/[^\/]+\/(\d+)(\?|$)/,t=(()=>{try{return window.parent.location.href}catch(e){return document.referrer}})().match(e);if(t){parseInt(t[1],10)>1&&(g.setBodyData("embedded","thank-you-page-donation"),this.hideFormComponents(),this.logger.log("iFrame Event - Set embedded attribute to thank-you-page-donation"))}this.logger.log("iFrame Event - Begin Resizing"),console.log("document.readyState",document.readyState),"loading"!==document.readyState?this.onLoaded():document.addEventListener("DOMContentLoaded",(()=>{this.onLoaded()})),window.setTimeout((()=>{this.sendIframeHeight()}),300),window.addEventListener("resize",this.debounceWithImmediate((()=>{this.logger.log("iFrame Event - window resized"),this.sendIframeHeight()}))),this._form.onSubmit.subscribe((e=>{this.logger.log("iFrame Event - onSubmit"),this.sendIframeFormStatus("submit")})),this.isChained()&&g.getPaymentType()&&(this.logger.log("iFrame Event - Chained iFrame"),this.sendIframeFormStatus("chained"));const n=document.querySelector(".skip-link");n&&n.remove(),this._form.onError.subscribe((()=>{const e=document.querySelector(".en__field--validationFailed"),t=e?e.getBoundingClientRect().top:0;this.logger.log(`iFrame Event 'scrollTo' - Position of top of first error ${t} px`),window.parent.postMessage({scrollTo:t},"*"),window.setTimeout((()=>{this.sendIframeHeight()}),100)}))}else this._form.onError.subscribe((()=>{const e=document.querySelector(".en__field--validationFailed");e&&e.scrollIntoView({behavior:"smooth"})})),window.addEventListener("message",(e=>{const t=this.getIFrameByEvent(e);if(t)if(e.data.hasOwnProperty("frameHeight"))t.style.height=e.data.frameHeight+"px",e.data.frameHeight>0?t.classList.add("loaded"):t.classList.remove("loaded");else if(e.data.hasOwnProperty("scroll")&&e.data.scroll>0){let n=window.pageYOffset+t.getBoundingClientRect().top+e.data.scroll;window.scrollTo({top:n,left:0,behavior:"smooth"}),this.logger.log("iFrame Event - Scrolling Window to "+n)}else if(e.data.hasOwnProperty("scrollTo")){const n=e.data.scrollTo+window.scrollY+t.getBoundingClientRect().top;window.scrollTo({top:n,left:0,behavior:"smooth"}),this.logger.log("iFrame Event - Scrolling Window to "+n)}}))}onLoaded(){this.logger.log("iFrame Event - window.onload"),this.sendIframeHeight(),window.parent.postMessage({scroll:this.shouldScroll()},"*"),this.sendIframeQueueThankYouPing(),document.addEventListener("click",(e=>{this.logger.log("iFrame Event - click"),setTimeout((()=>{this.sendIframeHeight()}),100)})),g.watchForError(this.sendIframeHeight.bind(this))}sendIframeQueueThankYouPing(){if(!g.isThankYouPage())return;const e=g.getPageID(),t={type:"engrid-iframe-queue:thank-you",pageId:e,pageNumber:g.getPageNumber(),pageCount:g.getPageCount(),url:window.location.href};this.logger.log(`iFrame Event - Iframe Queue thank-you ping (pageId=${e})`),window.parent.postMessage(t,"*")}sendIframeHeight(){let e=document.body.offsetHeight;this.logger.log("iFrame Event - Sending iFrame height of: "+e+"px"),window.parent.postMessage({frameHeight:e,pageNumber:g.getPageNumber(),pageCount:g.getPageCount(),giftProcess:g.getGiftProcess()},"*")}sendIframeFormStatus(e){window.parent.postMessage({status:e,pageNumber:g.getPageNumber(),pageCount:g.getPageCount(),giftProcess:g.getGiftProcess()},"*")}getIFrameByEvent(e){return[].slice.call(document.getElementsByTagName("iframe")).filter((t=>t.contentWindow===e.source))[0]}shouldScroll(){if(document.querySelector(".en__errorHeader"))return!0;if(this.isChained())return!1;let e=document.referrer;return new RegExp(/^(.*)\/(page)\/(\d+.*)/).test(e)}inIframe(){try{return window.self!==window.top}catch(e){return!0}}isChained(){return!!g.getUrlParameter("chain")}hideFormComponents(){this.logger.log("iFrame Event - Hiding Form Components");const e=["giveBySelect-Card","en__field--ccnumber","en__field--survey","en__component--ecardblock","give-by-select","give-by-select-header","en__submit","en__captcha","force-visibility","hide","hide-iframe","radio-to-buttons_donationAmt"],t=["en__digitalWallet"];Array.from(document.querySelectorAll(".body-main:not(.force-visibility) > div:not(:last-child)")).forEach((n=>{e.some((e=>n.classList.contains(e)||n.querySelector(`:scope > .${e}`)))||t.some((e=>n.querySelector(`#${e}`)))||n.classList.add("hide-iframe","hide-chained")})),this.sendIframeHeight()}showFormComponents(){this.logger.log("iFrame Event - Showing Form Components");document.querySelectorAll(".body-main > div.hide-chained").forEach((e=>{e.classList.remove("hide-iframe"),e.classList.remove("hide-chained")})),this.sendIframeHeight()}debounceWithImmediate(e,t=1e3){let n,i=!0;return(...o)=>{clearTimeout(n),i&&(e.apply(this,o),i=!1),n=setTimeout((()=>{e.apply(this,o),i=!0}),t)}}}class ${constructor(){this.logger=new ye("InputHasValueAndFocus","yellow","#333","π"),this.formInputs=document.querySelectorAll(".en__field--text, .en__field--email:not(.en__field--checkbox), .en__field--telephone, .en__field--number, .en__field--textarea, .en__field--select, .en__field--checkbox"),this.shouldRun()&&this.run()}shouldRun(){return this.formInputs.length>0}run(){this.formInputs.forEach((e=>{const t=e.querySelector("input, textarea, select");t&&t.value&&e.classList.add("has-value"),this.bindEvents(e)}))}bindEvents(e){const t=e.querySelector("input, textarea, select");t&&(t.addEventListener("focus",(()=>{this.log("Focus added",t),e.classList.add("has-focus")})),t.addEventListener("blur",(()=>{this.log("Focus removed",t),e.classList.remove("has-focus")})),t.addEventListener("input",(()=>{t.value?(this.log("Value added",t),e.classList.add("has-value")):(this.log("Value removed",t),e.classList.remove("has-value"))})))}log(e,t){this.logger.log(`${e} on ${t.name}: ${t.value}`)}}class W{constructor(){if(this.defaultPlaceholders={"input#en__field_supporter_firstName":"First Name","input#en__field_supporter_lastName":"Last Name","input#en__field_supporter_emailAddress":"Email Address","input#en__field_supporter_phoneNumber":"Phone Number (Optional)",".en__mandatory input#en__field_supporter_phoneNumber":"Phone Number",".i-required input#en__field_supporter_phoneNumber":"Phone Number","input#en__field_supporter_phoneNumber2":"000-000-0000 (Optional)",".en__mandatory input#en__field_supporter_phoneNumber2":"000-000-0000",".i-required input#en__field_supporter_phoneNumber2":"000-000-0000","input#en__field_supporter_country":"Country","input#en__field_supporter_address1":"Street Address","input#en__field_supporter_address2":"Apt., Ste., Bldg.","input#en__field_supporter_city":"City","input#en__field_supporter_region":"Region","input#en__field_supporter_postcode":"ZIP Code",".en__field--donationAmt.en__field--withOther .en__field__input--other":"Other","input#en__field_transaction_ccexpire":"MM / YY","input#en__field_supporter_bankAccountNumber":"Bank Account Number","input#en__field_supporter_bankRoutingNumber":"Bank Routing Number","input#en__field_transaction_honname":"Honoree Name","input#en__field_transaction_infname":"Recipient Name","input#en__field_transaction_infemail":"Recipient Email Address","input#en__field_transaction_infcountry":"Country","input#en__field_transaction_infadd1":"Recipient Street Address","input#en__field_transaction_infadd2":"Recipient Apt., Ste., Bldg.","input#en__field_transaction_infcity":"Recipient City","input#en__field_transaction_infpostcd":"Recipient Postal Code","input#en__field_transaction_gftrsn":"Reason for your gift","input#en__field_transaction_shipfname":"Shipping First Name","input#en__field_transaction_shiplname":"Shipping Last Name","input#en__field_transaction_shipemail":"Shipping Email Address","input#en__field_transaction_shipcountry":"Shipping Country","input#en__field_transaction_shipadd1":"Shipping Street Address","input#en__field_transaction_shipadd2":"Shipping Apt., Ste., Bldg.","input#en__field_transaction_shipcity":"Shipping City","input#en__field_transaction_shipregion":"Shipping Region","input#en__field_transaction_shippostcode":"Shipping Postal Code","input#en__field_supporter_billingCountry":"Billing Country","input#en__field_supporter_billingAddress1":"Billing Street Address","input#en__field_supporter_billingAddress2":"Billing Apt., Ste., Bldg.","input#en__field_supporter_billingCity":"Billing City","input#en__field_supporter_billingRegion":"Billing Region","input#en__field_supporter_billingPostcode":"Billing Postal Code"},this.shouldRun()){const e=g.getOption("Placeholders");e&&(this.defaultPlaceholders=Object.assign(Object.assign({},this.defaultPlaceholders),e)),this.run()}}shouldRun(){return g.hasBodyData("add-input-placeholders")}run(){Object.keys(this.defaultPlaceholders).forEach((e=>{e in this.defaultPlaceholders&&this.addPlaceholder(e,this.defaultPlaceholders[e])}))}addPlaceholder(e,t){const n=document.querySelector(e);n&&(n.placeholder=t)}}const z=n(9244).Ay;class Y{constructor(){this.mediaWithAttribution=document.querySelectorAll("img[data-attribution-source]:not([data-attribution-hide-overlay]), video[data-attribution-source]:not([data-attribution-hide-overlay])"),this.mediaWithAttribution.forEach((e=>{g.debug&&console.log("The following image was found with data attribution fields on it. It's markup will be changed to add caption support.",e);let t=document.createElement("figure");t.classList.add("media-with-attribution");let n=e.parentNode;if(n){n.insertBefore(t,e),t.appendChild(e);let i=e,o=i.dataset.attributionSource;if(o){let e=i.dataset.attributionSourceLink;e?i.insertAdjacentHTML("afterend",''+o+" "):i.insertAdjacentHTML("afterend",""+o+"");const t="attributionSourceTooltip"in i.dataset&&i.dataset.attributionSourceTooltip;t&&z(i.nextSibling,{content:t,arrow:!0,arrowType:"default",placement:"left",trigger:"click mouseenter focus",interactive:!0})}}}))}}class J{constructor(t){var n;this._amount=p.getInstance(),this._fees=f.getInstance(),this._frequency=m.getInstance(),this._form=h.getInstance(),this.multiplier=1/12,this.options=Object.assign(Object.assign({},e),t),this.submitLabel=(null===(n=document.querySelector(".en__submit button"))||void 0===n?void 0:n.innerHTML)||"Donate",this._amount.onAmountChange.subscribe((()=>this.changeSubmitButton())),this._amount.onAmountChange.subscribe((()=>this.changeLiveAmount())),this._amount.onAmountChange.subscribe((()=>this.changeLiveUpsellAmount())),this._fees.onFeeChange.subscribe((()=>this.changeLiveAmount())),this._fees.onFeeChange.subscribe((()=>this.changeLiveUpsellAmount())),this._fees.onFeeChange.subscribe((()=>this.changeSubmitButton())),this._frequency.onFrequencyChange.subscribe((()=>this.changeLiveFrequency())),this._frequency.onFrequencyChange.subscribe((()=>this.changeRecurrency())),this._frequency.onFrequencyChange.subscribe((()=>this.changeSubmitButton())),this._form.onSubmit.subscribe((()=>{"SUPPORTERHUB"!==g.getPageType()&&g.disableSubmit("Processing...")})),this._form.onError.subscribe((()=>g.enableSubmit())),document.addEventListener("click",(e=>{const t=e.target;t&&(t.classList.contains("monthly-upsell")?this.upsold(e):t.classList.contains("form-submit")&&(e.preventDefault(),this._form.submitForm()))}))}getAmountTxt(e=0){var t,n,i,o;const s=null!==(t=g.getCurrencySymbol())&&void 0!==t?t:"$",r=null!==(n=this.options.DecimalSeparator)&&void 0!==n?n:".",a=null!==(i=this.options.ThousandsSeparator)&&void 0!==i?i:"",l=e%1==0?0:null!==(o=this.options.DecimalPlaces)&&void 0!==o?o:2,c=g.formatNumber(e,l,r,a);return e>0?`${s} ${c} `:""}getUpsellAmountTxt(e=0){var t,n,i,o;const s=null!==(t=g.getCurrencySymbol())&&void 0!==t?t:"$",r=null!==(n=this.options.DecimalSeparator)&&void 0!==n?n:".",a=null!==(i=this.options.ThousandsSeparator)&&void 0!==i?i:"",l=e%1==0?0:null!==(o=this.options.DecimalPlaces)&&void 0!==o?o:2,c=g.formatNumber(5*Math.ceil(e/5),l,r,a);return e>0?s+c:""}getUpsellAmountRaw(e=0){const t=5*Math.ceil(e/5);return e>0?t.toString():""}changeSubmitButton(){const e=document.querySelector(".en__submit button"),t=this.getAmountTxt(this._amount.amount+this._fees.fee),n="onetime"==this._frequency.frequency?"":"annual"==this._frequency.frequency?"annually":this._frequency.frequency;let i=this.submitLabel;t?(i=i.replace("$AMOUNT",t),i=i.replace("$FREQUENCY",`${n} `)):(i=i.replace("$AMOUNT",""),i=i.replace("$FREQUENCY","")),e&&i&&(e.innerHTML=i)}changeLiveAmount(){const e=this._amount.amount+this._fees.fee;document.querySelectorAll(".live-giving-amount").forEach((t=>t.innerHTML=this.getAmountTxt(e)))}changeLiveUpsellAmount(){const e=(this._amount.amount+this._fees.fee)*this.multiplier;document.querySelectorAll(".live-giving-upsell-amount").forEach((t=>t.innerHTML=this.getUpsellAmountTxt(e)));document.querySelectorAll(".live-giving-upsell-amount-raw").forEach((t=>t.innerHTML=this.getUpsellAmountRaw(e)))}changeLiveFrequency(){document.querySelectorAll(".live-giving-frequency").forEach((e=>e.innerHTML="onetime"==this._frequency.frequency?"":this._frequency.frequency))}changeRecurrency(){const e=document.querySelector("[name='transaction.recurrpay']");if(e&&"radio"!=e.type){e.value="onetime"==this._frequency.frequency?"N":"Y",this._frequency.recurring=e.value,g.getOption("Debug")&&console.log("Recurpay Changed!");const t=new Event("change",{bubbles:!0});e.dispatchEvent(t)}}upsold(e){const t=document.querySelector(".en__field--recurrpay input[value='Y']");t&&(t.checked=!0);const n=document.querySelector(".en__field--donationAmt input[value='other']");n&&(n.checked=!0);const i=document.querySelector("input[name='transaction.donationAmt.other']");i&&(i.value=this.getUpsellAmountRaw(this._amount.amount*this.multiplier),this._amount.load(),this._frequency.load(),i.parentElement&&i.parentElement.classList.remove("en__field__item--hidden"));const o=e.target;o&&o.classList.contains("form-submit")&&(e.preventDefault(),this._form.submitForm())}}class X{constructor(){this.overlay=document.createElement("div"),this._form=h.getInstance(),this._amount=p.getInstance(),this._fees=f.getInstance(),this._frequency=m.getInstance(),this._dataLayer=we.getInstance(),this._suggestAmount=0,this.logger=new ye("UpsellLightbox","black","pink","πͺ");let e="EngridUpsell"in window?window.EngridUpsell:{};this.options=Object.assign(Object.assign({},t),e),this.options.disablePaymentMethods.push("applepay"),this.shouldRun()?(this.overlay.id="enModal",this.overlay.classList.add("is-hidden"),this.overlay.classList.add("image-"+this.options.imagePosition),this.renderLightbox(),this._form.onSubmit.subscribe((()=>this.open()))):this.logger.log("Upsell script should NOT run")}renderLightbox(){const e=this.options.title.replace("{new-amount}"," ").replace("{old-amount}"," ").replace("{old-frequency}"," "),t=this.options.paragraph.replace("{new-amount}"," ").replace("{old-amount}"," ").replace("{old-frequency}"," "),n=this.options.yesLabel.replace("{new-amount}"," ").replace("{old-amount}"," ").replace("{old-frequency}"," "),i=this.options.noLabel.replace("{new-amount}"," ").replace("{old-amount}"," ").replace("{old-frequency}"," "),o=`\n \n \x3c!-- ideal image size is 480x650 pixels --\x3e\n
\n
\n ${this.options.canClose?'
':""}\n
\n ${e}\n \n ${this.options.otherAmount?`\n
\n
\n
\n ${this.options.otherLabel}\n
\n
\n
\n \n Minimum ${this.getAmountTxt(this.options.minAmount)} \n
\n
\n `:""}\n\n
\n ${t}\n
\n \x3c!-- YES BUTTON --\x3e\n
\n \x3c!-- NO BUTTON --\x3e\n
\n
\n
\n `;this.overlay.innerHTML=o;const s=this.overlay.querySelector("#goMonthlyClose"),r=this.overlay.querySelector("#upsellYesButton a"),a=this.overlay.querySelector("#upsellNoButton button");r.addEventListener("click",this.continue.bind(this)),a.addEventListener("click",this.continue.bind(this)),s&&s.addEventListener("click",this.close.bind(this)),this.overlay.addEventListener("click",(e=>{e.target instanceof Element&&e.target.id==this.overlay.id&&this.options.canClose&&this.close(e)})),document.addEventListener("keyup",(e=>{"Escape"===e.key&&s&&s.click()})),document.body.appendChild(this.overlay);const l=document.querySelector("#secondOtherField");l&&l.addEventListener("keyup",this.popupOtherField.bind(this)),this.logger.log("Upsell script rendered")}shouldRun(){return!this.shouldSkip()&&"EngridUpsell"in window&&!!window.pageJson&&1==window.pageJson.pageNumber&&["donation","premiumgift"].includes(window.pageJson.pageType)}shouldSkip(){return!(!("EngridUpsell"in window)||!window.EngridUpsell.skipUpsell)||this.options.skipUpsell}popupOtherField(){var e,t;const n=parseFloat(null!==(t=null===(e=this.overlay.querySelector("#secondOtherField"))||void 0===e?void 0:e.value)&&void 0!==t?t:""),i=document.querySelectorAll("#upsellYesButton .upsell_suggestion"),o=this.getUpsellAmount();!isNaN(n)&&n>0?this.checkOtherAmount(n):this.checkOtherAmount(o),i.forEach((e=>e.innerHTML=this.getAmountTxt(o+this._fees.calculateFees(o))))}liveAmounts(){const e=document.querySelectorAll(".upsell_suggestion"),t=document.querySelectorAll(".upsell_amount"),n=this.getUpsellAmount(),i=n+this._fees.calculateFees(n);e.forEach((e=>e.innerHTML=this.getAmountTxt(i))),t.forEach((e=>e.innerHTML=this.getAmountTxt(this._amount.amount+this._fees.fee)))}liveFrequency(){document.querySelectorAll(".upsell_frequency").forEach((e=>e.innerHTML=this.getFrequencyTxt()))}getUpsellAmount(){var e,t;const n=this._amount.amount,i=parseFloat(null!==(t=null===(e=this.overlay.querySelector("#secondOtherField"))||void 0===e?void 0:e.value)&&void 0!==t?t:"");if(i>0)return i>this.options.minAmount?i:this.options.minAmount;let o=0;for(let e=0;ethis.options.minAmount?o:this.options.minAmount}shouldOpen(){const e=this.getUpsellAmount(),t=g.getFieldValue("transaction.paymenttype")||"";return this._suggestAmount=e,!(!this.freqAllowed()||this.shouldSkip()||this.options.disablePaymentMethods.includes(t.toLowerCase())||this.overlay.classList.contains("is-submitting")||!(e>0))&&(this.logger.log("Upsell Frequency "+this._frequency.frequency),this.logger.log("Upsell Amount "+this._amount.amount),this.logger.log("Upsell Suggested Amount "+e),!0)}freqAllowed(){const e=this._frequency.frequency,t=[];return this.options.oneTime&&t.push("onetime"),this.options.annual&&t.push("annual"),t.includes(e)}open(){if(this.logger.log("Upsell script opened"),!this.shouldOpen()){let e=window.sessionStorage.getItem("original");return e&&document.querySelectorAll(".en__errorList .en__error").length>0&&this.setOriginalAmount(e),this._form.submit=!0,!0}return this.liveAmounts(),this.liveFrequency(),this.overlay.classList.remove("is-hidden"),this._form.submit=!1,g.setBodyData("has-lightbox",""),!1}setOriginalAmount(e){if(this.options.upsellOriginalGiftAmountFieldName){let t=document.querySelector(".en__field__input.en__field__input--hidden[name='"+this.options.upsellOriginalGiftAmountFieldName+"']");if(!t){let e=document.querySelector("form.en__component--page");if(e){let n=document.createElement("input");n.setAttribute("type","hidden"),n.setAttribute("name",this.options.upsellOriginalGiftAmountFieldName),n.classList.add("en__field__input","en__field__input--hidden"),e.appendChild(n),t=document.querySelector('.en__field__input.en__field__input--hidden[name="'+this.options.upsellOriginalGiftAmountFieldName+'"]')}}t&&(window.sessionStorage.setItem("original",e),t.setAttribute("value",e))}}continue(e){var t;if(e.preventDefault(),e.target instanceof Element&&(null===(t=document.querySelector("#upsellYesButton"))||void 0===t?void 0:t.contains(e.target))){this.logger.success("Upsold"),this.setOriginalAmount(this._amount.amount.toString());const e=this.getUpsellAmount(),t=this._amount.amount;this._frequency.setFrequency("monthly"),this._amount.setAmount(e),this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL",{eventValue:!0,originalAmount:t,upsoldAmount:e,frequency:"monthly"}),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL",!0),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT",t),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY","MONTHLY"),this.renderConversionField("upsellSuccess","onetime",t,"monthly",this._suggestAmount,"monthly",e)}else this.setOriginalAmount(""),window.sessionStorage.removeItem("original"),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL",!1),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY","ONE-TIME"),this.renderConversionField("upsellFail",this._frequency.frequency,this._amount.amount,"monthly",this._suggestAmount,this._frequency.frequency,this._amount.amount);this._form.submitForm()}close(e){e.preventDefault(),this.overlay.classList.add("is-hidden"),g.setBodyData("has-lightbox",!1),this.options.submitOnClose?(this.renderConversionField("upsellFail",this._frequency.frequency,this._amount.amount,"monthly",this._suggestAmount,this._frequency.frequency,this._amount.amount),this._form.submitForm()):this._form.dispatchError()}getAmountTxt(e=0){var t,n,i,o;const s=null!==(t=g.getCurrencySymbol())&&void 0!==t?t:"$",r=null!==(n=g.getOption("DecimalSeparator"))&&void 0!==n?n:".",a=null!==(i=g.getOption("ThousandsSeparator"))&&void 0!==i?i:"",l=e%1==0?0:null!==(o=g.getOption("DecimalPlaces"))&&void 0!==o?o:2,c=g.formatNumber(e,l,r,a);return e>0?s+c:""}getFrequencyTxt(){const e={onetime:"one-time",monthly:"monthly",annual:"annual"},t=this._frequency.frequency;return t in e?e[t]:t}checkOtherAmount(e){const t=document.querySelector(".upsellOtherAmountInput");t&&(e>=this.options.minAmount?t.classList.remove("is-invalid"):t.classList.add("is-invalid"))}renderConversionField(e,t,n,i,o,s,r){if(""===this.options.conversionField)return;const a=document.querySelector("input[name='"+this.options.conversionField+"']")||g.createHiddenInput(this.options.conversionField);if(!a)return void this.logger.error("Could not find or create the conversion field");const l=`event:${e},freq:${t},amt:${n},sugFreq:${i},sugAmt:${o},subFreq:${s},subAmt:${r}`;a.value=l,this.logger.log(`Conversion Field ${e}`,l)}}class K{constructor(){this.checkboxOptions=!1,this.checkboxOptionsDefaults={label:"Make my gift a monthly gift of {new-amount}/mo ",location:"before .en__component .en__submit",cssClass:""},this._amount=p.getInstance(),this._fees=f.getInstance(),this._frequency=m.getInstance(),this._dataLayer=we.getInstance(),this.checkboxContainer=null,this.oldAmount=0,this.oldFrequency="one-time",this.resetCheckbox=!1,this.logger=new ye("UpsellCheckbox","black","LemonChiffon","β
");let e="EngridUpsell"in window?window.EngridUpsell:{};this.options=Object.assign(Object.assign({},t),e),!1!==this.options.upsellCheckbox?("upsellCheckbox"in e&&!1!==e.upsellCheckbox&&(window.EngridUpsell.skipUpsell=!0),this.checkboxOptions=Object.assign(Object.assign({},this.checkboxOptionsDefaults),this.options.upsellCheckbox),this.shouldRun()?(this.renderCheckbox(),this.updateLiveData(),this._frequency.onFrequencyChange.subscribe((()=>this.updateLiveData())),this._frequency.onFrequencyChange.subscribe((()=>this.resetUpsellCheckbox())),this._amount.onAmountChange.subscribe((()=>this.updateLiveData())),this._amount.onAmountChange.subscribe((()=>this.resetUpsellCheckbox())),this._fees.onFeeChange.subscribe((()=>this.updateLiveData()))):this.logger.log("should NOT run")):this.logger.log("Skipped")}updateLiveData(){this.liveAmounts(),this.liveFrequency()}resetUpsellCheckbox(){var e,t;if(!this.resetCheckbox)return;this.logger.log("Reset");const n=null===(e=this.checkboxContainer)||void 0===e?void 0:e.querySelector("#upsellCheckbox");n&&(n.checked=!1),null===(t=this.checkboxContainer)||void 0===t||t.classList.add("recurring-frequency-y-hide"),this.oldAmount=0,this.oldFrequency="one-time",this.resetCheckbox=!1}renderCheckbox(){if(!1===this.checkboxOptions)return;const e=this.checkboxOptions.label.replace("{new-amount}"," ").replace("{old-amount}"," ").replace("{old-frequency}"," "),t=document.createElement("div");t.classList.add("en__component","en__component--formblock","recurring-frequency-y-hide","engrid-upsell-checkbox"),this.checkboxOptions.cssClass&&t.classList.add(this.checkboxOptions.cssClass),t.innerHTML=`\n `;const n=t.querySelector("#upsellCheckbox");n&&n.addEventListener("change",this.toggleCheck.bind(this));const i=this.checkboxOptions.location.split(" ")[0],o=this.checkboxOptions.location.split(" ").slice(1).join(" ").trim(),s=document.querySelector(o);this.checkboxContainer=t,s?"before"===i?(this.logger.log("rendered before"),s.before(t)):(this.logger.log("rendered after"),s.after(t)):this.logger.error("could not render - target not found")}shouldRun(){return 1===g.getPageNumber()&&"DONATION"===g.getPageType()}showCheckbox(){this.checkboxContainer&&this.checkboxContainer.classList.remove("hide")}hideCheckbox(){this.checkboxContainer&&this.checkboxContainer.classList.add("hide")}liveAmounts(){if("onetime"!==this._frequency.frequency)return;const e=document.querySelectorAll(".upsell_suggestion"),t=document.querySelectorAll(".upsell_amount"),n=this.getUpsellAmount(),i=n+this._fees.calculateFees(n);i>0?this.showCheckbox():this.hideCheckbox(),e.forEach((e=>e.innerHTML=this.getAmountTxt(i))),t.forEach((e=>e.innerHTML=this.getAmountTxt(this._amount.amount+this._fees.fee)))}liveFrequency(){document.querySelectorAll(".upsell_frequency").forEach((e=>e.innerHTML=this.getFrequencyTxt()))}getUpsellAmount(){const e=this._amount.amount;let t=0;for(let n=0;nthis.options.minAmount?t:this.options.minAmount}toggleCheck(e){var t,n;if(e.preventDefault(),e.target.checked){this.logger.success("Upsold");const e=this.getUpsellAmount(),n=this._amount.amount;this.oldAmount=n,this.oldFrequency=this._frequency.frequency,null===(t=this.checkboxContainer)||void 0===t||t.classList.remove("recurring-frequency-y-hide"),this._frequency.setFrequency("monthly"),this._amount.setAmount(e),this._dataLayer.addEndOfGiftProcessEvent("ENGRID_UPSELL_CHECKBOX",{eventValue:!0,originalAmount:n,upsoldAmount:e,frequency:"monthly"}),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX",!0),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_ORIGINAL_AMOUNT",n),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY","MONTHLY"),this.renderConversionField("upsellSuccess","onetime",n,"monthly",e,"monthly",e),window.setTimeout((()=>{this.resetCheckbox=!0}),500)}else this.resetCheckbox=!1,this.logger.success("Not Upsold"),this._amount.setAmount(this.oldAmount),this._frequency.setFrequency(this.oldFrequency),null===(n=this.checkboxContainer)||void 0===n||n.classList.add("recurring-frequency-y-hide"),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_CHECKBOX",!1),this._dataLayer.addEndOfGiftProcessVariable("ENGRID_UPSELL_DONATION_FREQUENCY","ONE-TIME"),this.renderConversionField("upsellFail",this._frequency.frequency,this._amount.amount,"monthly",this._amount.amount,this._frequency.frequency,this._amount.amount)}getAmountTxt(e=0){var t,n,i,o;const s=null!==(t=g.getCurrencySymbol())&&void 0!==t?t:"$",r=null!==(n=g.getOption("DecimalSeparator"))&&void 0!==n?n:".",a=null!==(i=g.getOption("ThousandsSeparator"))&&void 0!==i?i:"",l=e%1==0?0:null!==(o=g.getOption("DecimalPlaces"))&&void 0!==o?o:2,c=g.formatNumber(e,l,r,a);return e>0?s+c:""}getFrequencyTxt(){const e={onetime:"one-time",monthly:"monthly",annual:"annual"},t=this._frequency.frequency;return t in e?e[t]:t}renderConversionField(e,t,n,i,o,s,r){if(""===this.options.conversionField)return;const a=document.querySelector("input[name='"+this.options.conversionField+"']")||g.createHiddenInput(this.options.conversionField);if(!a)return void this.logger.error("Could not find or create the conversion field");const l=`event:${e},freq:${t},amt:${n},sugFreq:${i},sugAmt:${o},subFreq:${s},subAmt:${r}`;a.value=l,this.logger.log(`Conversion Field ${e}`,l)}}class Q{createDataAttributes(){this.elements.forEach((e=>{if(e instanceof HTMLInputElement){let t=e.value.replace(/\W/g,"");document.querySelectorAll("."+this.classes+t).forEach((e=>{if(e instanceof HTMLElement){const t=e.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");t.length>0&&t.forEach((e=>{(e instanceof HTMLInputElement||e instanceof HTMLSelectElement)&&(e.hasAttribute("data-original-value")||e.setAttribute("data-original-value",e.value),e.hasAttribute("data-value")||e.setAttribute("data-value",e.value))}))}}))}}))}hideAll(){this.elements.forEach(((e,t)=>{e instanceof HTMLInputElement&&this.hide(e)}))}hide(e){let t=e.value.replace(/\W/g,"");document.querySelectorAll("."+this.classes+t).forEach((e=>{if(e instanceof HTMLElement){this.toggleValue(e,"hide"),e.style.display="none",this.logger.log("Hiding",e);const t=e.querySelector("input");t instanceof HTMLInputElement&&(t.setAttribute("aria-required","false"),this.logger.log("aria-required set to FALSE",t))}}))}show(e){let t=e.value.replace(/\W/g,"");document.querySelectorAll("."+this.classes+t).forEach((e=>{if(e instanceof HTMLElement){this.toggleValue(e,"show"),e.style.display="",this.logger.log("Showing",e);const t=e.querySelector("input");t instanceof HTMLInputElement&&(t.setAttribute("aria-required","true"),this.logger.log("aria-required set to TRUE",t))}})),"checkbox"!=e.type||e.checked||this.hide(e)}toggleValue(e,t){if("hide"==t&&!g.isVisible(e))return;this.logger.log(`toggleValue: ${t}`);const n=e.querySelectorAll("input[type='text'], input[type='number'], input[type='email'], select, textarea");n.length>0&&n.forEach((e=>{var n;if((e instanceof HTMLInputElement||e instanceof HTMLSelectElement)&&e.name){const i=g.getFieldValue(e.name),o=e.getAttribute("data-original-value"),s=null!==(n=e.getAttribute("data-value"))&&void 0!==n?n:"";"hide"===t?(e.setAttribute("data-value",i),g.setFieldValue(e.name,o)):g.setFieldValue(e.name,s)}}))}getSessionState(){var e;try{const t=null!==(e=window.sessionStorage.getItem("engrid_ShowHideRadioCheckboxesState"))&&void 0!==e?e:"";return JSON.parse(t)}catch(e){return[]}}storeSessionState(){const e=this.getSessionState();[...this.elements].forEach((t=>{var n,i;t instanceof HTMLInputElement&&("radio"==t.type&&t.checked&&(e.forEach(((t,n)=>{t.class==this.classes&&e.splice(n,1)})),e.push({page:g.getPageID(),class:this.classes,value:t.value}),this.logger.log("storing radio state",e[e.length-1])),"checkbox"==t.type&&(e.forEach(((t,n)=>{t.class==this.classes&&e.splice(n,1)})),e.push({page:g.getPageID(),class:this.classes,value:null!==(i=null===(n=[...this.elements].find((e=>e.checked)))||void 0===n?void 0:n.value)&&void 0!==i?i:"N"}),this.logger.log("storing checkbox state",e[e.length-1])))})),window.sessionStorage.setItem("engrid_ShowHideRadioCheckboxesState",JSON.stringify(e))}constructor(e,t){this.logger=new ye("ShowHideRadioCheckboxes","black","lightblue","π"),this.elements=document.getElementsByName(e),this.classes=t,this.createDataAttributes(),this.hideAll(),this.storeSessionState();for(let e=0;e{this.hideAll(),this.show(t),this.storeSessionState()}))}}}function Z(e,t){if(!t)return"";let n="; "+e;return!0===t?n:n+"="+t}function ee(e,t,n){return encodeURIComponent(e).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/\(/g,"%28").replace(/\)/g,"%29")+"="+encodeURIComponent(t).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent)+function(e){if("number"==typeof e.expires){let t=new Date;t.setMilliseconds(t.getMilliseconds()+864e5*e.expires),e.expires=t}return Z("Expires",e.expires?e.expires.toUTCString():"")+Z("Domain",e.domain)+Z("Path",e.path)+Z("Secure",e.secure)+Z("SameSite",e.sameSite)}(n)}function te(){return function(e){let t={},n=e?e.split("; "):[],i=/(%[\dA-F]{2})+/gi;for(let e=0;e0){this.countriesSelect.forEach((e=>{e.addEventListener("change",this.translateFields.bind(this,e.name)),e.value&&(t[e.name]=e.value);const n=document.querySelector(`select[name="${this.countryToStateFields[e.name]}"]`);n&&(n.addEventListener("change",this.rememberState.bind(this,e.name)),n.value&&(t[n.name]=n.value))})),this.translateFields("supporter.country");if(!!(!g.checkNested(window.EngagingNetworks,"require","_defined","enjs","checkSubmissionFailed")||!window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed()))for(let e in t)g.setFieldValue(e,t[e],!1)}}translateFields(e="supporter.country"){this.resetTranslatedFields();const t=g.getFieldValue(e);if(this.setStateField(t,this.countryToStateFields[e]),"supporter.country"===e){t in this.options&&this.options[t].forEach((e=>{this.translateField(e.field,e.translation)}));const e=document.querySelectorAll(".recipient-block");if(e.length)switch(t){case"FR":case"FRA":case"France":e.forEach((e=>e.innerHTML="Γ:"));break;case"DE":case"DEU":case"Germany":e.forEach((e=>e.innerHTML="Zu:"));break;case"NL":case"NLD":case"Netherlands":e.forEach((e=>e.innerHTML="Aan:"))}}}translateField(e,t){const n=document.querySelector(`[name="${e}"]`);if(n){const e=n.closest(".en__field");if(e){const i=e.querySelector(".en__field__label"),o=i.querySelector(".engrid-simple-country");let s=o?o.cloneNode(!0):null;n instanceof HTMLInputElement&&""!=n.placeholder&&(i&&i.innerHTML!=n.placeholder||(n.dataset.original=n.placeholder,n.placeholder=t)),i&&(i.dataset.original=i.innerHTML,i.innerHTML=t,s&&i.appendChild(s))}}}resetTranslatedFields(){document.querySelectorAll("[data-original]").forEach((e=>{if(e instanceof HTMLInputElement&&e.dataset.original)e.placeholder=e.dataset.original;else{const t=e.querySelector(".engrid-simple-country");let n=t?t.cloneNode(!0):null;e.innerHTML=e.dataset.original,n&&e.appendChild(n)}e.removeAttribute("data-original")}))}setStateField(e,t){switch(e){case"ES":case"ESP":case"Spain":this.setStateValues(t,"Provincia",null);break;case"BR":case"BRA":case"Brazil":this.setStateValues(t,"Estado",null);break;case"FR":case"FRA":case"France":this.setStateValues(t,"RΓ©gion",null);break;case"GB":case"GBR":case"United Kingdom":this.setStateValues(t,"State/Region",null);break;case"DE":case"DEU":case"Germany":this.setStateValues(t,"Bundesland",null);break;case"NL":case"NLD":case"Netherlands":this.setStateValues(t,"Provincie",null);break;case"AU":case"AUS":this.setStateValues(t,"Province / State",[{label:"Select",value:""},{label:"New South Wales",value:"NSW"},{label:"Victoria",value:"VIC"},{label:"Queensland",value:"QLD"},{label:"South Australia",value:"SA"},{label:"Western Australia",value:"WA"},{label:"Tasmania",value:"TAS"},{label:"Northern Territory",value:"NT"},{label:"Australian Capital Territory",value:"ACT"}]);break;case"Australia":this.setStateValues(t,"Province / State",[{label:"Select",value:""},{label:"New South Wales",value:"New South Wales"},{label:"Victoria",value:"Victoria"},{label:"Queensland",value:"Queensland"},{label:"South Australia",value:"South Australia"},{label:"Western Australia",value:"Western Australia"},{label:"Tasmania",value:"Tasmania"},{label:"Northern Territory",value:"Northern Territory"},{label:"Australian Capital Territory",value:"Australian Capital Territory"}]);break;case"US":case"USA":this.setStateValues(t,"State",[{label:"Select State",value:""},{label:"Alabama",value:"AL"},{label:"Alaska",value:"AK"},{label:"Arizona",value:"AZ"},{label:"Arkansas",value:"AR"},{label:"California",value:"CA"},{label:"Colorado",value:"CO"},{label:"Connecticut",value:"CT"},{label:"Delaware",value:"DE"},{label:"District of Columbia",value:"DC"},{label:"Florida",value:"FL"},{label:"Georgia",value:"GA"},{label:"Hawaii",value:"HI"},{label:"Idaho",value:"ID"},{label:"Illinois",value:"IL"},{label:"Indiana",value:"IN"},{label:"Iowa",value:"IA"},{label:"Kansas",value:"KS"},{label:"Kentucky",value:"KY"},{label:"Louisiana",value:"LA"},{label:"Maine",value:"ME"},{label:"Maryland",value:"MD"},{label:"Massachusetts",value:"MA"},{label:"Michigan",value:"MI"},{label:"Minnesota",value:"MN"},{label:"Mississippi",value:"MS"},{label:"Missouri",value:"MO"},{label:"Montana",value:"MT"},{label:"Nebraska",value:"NE"},{label:"Nevada",value:"NV"},{label:"New Hampshire",value:"NH"},{label:"New Jersey",value:"NJ"},{label:"New Mexico",value:"NM"},{label:"New York",value:"NY"},{label:"North Carolina",value:"NC"},{label:"North Dakota",value:"ND"},{label:"Ohio",value:"OH"},{label:"Oklahoma",value:"OK"},{label:"Oregon",value:"OR"},{label:"Pennsylvania",value:"PA"},{label:"Rhode Island",value:"RI"},{label:"South Carolina",value:"SC"},{label:"South Dakota",value:"SD"},{label:"Tennessee",value:"TN"},{label:"Texas",value:"TX"},{label:"Utah",value:"UT"},{label:"Vermont",value:"VT"},{label:"Virginia",value:"VA"},{label:"Washington",value:"WA"},{label:"West Virginia",value:"WV"},{label:"Wisconsin",value:"WI"},{label:"Wyoming",value:"WY"},{label:"── US Territories ──",value:"",disabled:!0},{label:"American Samoa",value:"AS"},{label:"Guam",value:"GU"},{label:"Northern Mariana Islands",value:"MP"},{label:"Puerto Rico",value:"PR"},{label:"US Minor Outlying Islands",value:"UM"},{label:"Virgin Islands",value:"VI"},{label:"── Armed Forces ──",value:"",disabled:!0},{label:"Armed Forces Americas",value:"AA"},{label:"Armed Forces Africa",value:"AE"},{label:"Armed Forces Canada",value:"AE"},{label:"Armed Forces Europe",value:"AE"},{label:"Armed Forces Middle East",value:"AE"},{label:"Armed Forces Pacific",value:"AP"}]);break;case"United States":this.setStateValues(t,"State",[{label:"Select State",value:""},{label:"Alabama",value:"Alabama"},{label:"Alaska",value:"Alaska"},{label:"Arizona",value:"Arizona"},{label:"Arkansas",value:"Arkansas"},{label:"California",value:"California"},{label:"Colorado",value:"Colorado"},{label:"Connecticut",value:"Connecticut"},{label:"Delaware",value:"Delaware"},{label:"District of Columbia",value:"District of Columbia"},{label:"Florida",value:"Florida"},{label:"Georgia",value:"Georgia"},{label:"Hawaii",value:"Hawaii"},{label:"Idaho",value:"Idaho"},{label:"Illinois",value:"Illinois"},{label:"Indiana",value:"Indiana"},{label:"Iowa",value:"Iowa"},{label:"Kansas",value:"Kansas"},{label:"Kentucky",value:"Kentucky"},{label:"Louisiana",value:"Louisiana"},{label:"Maine",value:"Maine"},{label:"Maryland",value:"Maryland"},{label:"Massachusetts",value:"Massachusetts"},{label:"Michigan",value:"Michigan"},{label:"Minnesota",value:"Minnesota"},{label:"Mississippi",value:"Mississippi"},{label:"Missouri",value:"Missouri"},{label:"Montana",value:"Montana"},{label:"Nebraska",value:"Nebraska"},{label:"Nevada",value:"Nevada"},{label:"New Hampshire",value:"New Hampshire"},{label:"New Jersey",value:"New Jersey"},{label:"New Mexico",value:"New Mexico"},{label:"New York",value:"New York"},{label:"North Carolina",value:"North Carolina"},{label:"North Dakota",value:"North Dakota"},{label:"Ohio",value:"Ohio"},{label:"Oklahoma",value:"Oklahoma"},{label:"Oregon",value:"Oregon"},{label:"Pennsylvania",value:"Pennsylvania"},{label:"Rhode Island",value:"Rhode Island"},{label:"South Carolina",value:"South Carolina"},{label:"South Dakota",value:"South Dakota"},{label:"Tennessee",value:"Tennessee"},{label:"Texas",value:"Texas"},{label:"Utah",value:"Utah"},{label:"Vermont",value:"Vermont"},{label:"Virginia",value:"Virginia"},{label:"Washington",value:"Washington"},{label:"West Virginia",value:"West Virginia"},{label:"Wisconsin",value:"Wisconsin"},{label:"Wyoming",value:"Wyoming"},{label:"── US Territories ──",value:"",disabled:!0},{label:"American Samoa",value:"American Samoa"},{label:"Guam",value:"Guam"},{label:"Northern Mariana Islands",value:"Northern Mariana Islands"},{label:"Puerto Rico",value:"Puerto Rico"},{label:"US Minor Outlying Islands",value:"US Minor Outlying Islands"},{label:"Virgin Islands",value:"Virgin Islands"},{label:"── Armed Forces ──",value:"",disabled:!0},{label:"Armed Forces Americas",value:"Armed Forces Americas"},{label:"Armed Forces Africa",value:"Armed Forces Africa"},{label:"Armed Forces Canada",value:"Armed Forces Canada"},{label:"Armed Forces Europe",value:"Armed Forces Europe"},{label:"Armed Forces Middle East",value:"Armed Forces Middle East"},{label:"Armed Forces Pacific",value:"Armed Forces Pacific"}]);break;case"CA":case"CAN":this.setStateValues(t,"Province / Territory",[{label:"Select",value:""},{label:"Alberta",value:"AB"},{label:"British Columbia",value:"BC"},{label:"Manitoba",value:"MB"},{label:"New Brunswick",value:"NB"},{label:"Newfoundland and Labrador",value:"NL"},{label:"Northwest Territories",value:"NT"},{label:"Nova Scotia",value:"NS"},{label:"Nunavut",value:"NU"},{label:"Ontario",value:"ON"},{label:"Prince Edward Island",value:"PE"},{label:"Quebec",value:"QC"},{label:"Saskatchewan",value:"SK"},{label:"Yukon",value:"YT"}]);break;case"Canada":this.setStateValues(t,"Province / Territory",[{label:"Select",value:""},{label:"Alberta",value:"Alberta"},{label:"British Columbia",value:"British Columbia"},{label:"Manitoba",value:"Manitoba"},{label:"New Brunswick",value:"New Brunswick"},{label:"Newfoundland and Labrador",value:"Newfoundland and Labrador"},{label:"Northwest Territories",value:"Northwest Territories"},{label:"Nova Scotia",value:"Nova Scotia"},{label:"Nunavut",value:"Nunavut"},{label:"Ontario",value:"Ontario"},{label:"Prince Edward Island",value:"Prince Edward Island"},{label:"Quebec",value:"Quebec"},{label:"Saskatchewan",value:"Saskatchewan"},{label:"Yukon",value:"Yukon"}]);break;case"MX":case"MEX":this.setStateValues(t,"Estado",[{label:"Seleccione Estado",value:""},{label:"Aguascalientes",value:"AGU"},{label:"Baja California",value:"BCN"},{label:"Baja California Sur",value:"BCS"},{label:"Campeche",value:"CAM"},{label:"Chiapas",value:"CHP"},{label:"Ciudad de Mexico",value:"CMX"},{label:"Chihuahua",value:"CHH"},{label:"Coahuila",value:"COA"},{label:"Colima",value:"COL"},{label:"Durango",value:"DUR"},{label:"Guanajuato",value:"GUA"},{label:"Guerrero",value:"GRO"},{label:"Hidalgo",value:"HID"},{label:"Jalisco",value:"JAL"},{label:"Michoacan",value:"MIC"},{label:"Morelos",value:"MOR"},{label:"Nayarit",value:"NAY"},{label:"Nuevo Leon",value:"NLE"},{label:"Oaxaca",value:"OAX"},{label:"Puebla",value:"PUE"},{label:"Queretaro",value:"QUE"},{label:"Quintana Roo",value:"ROO"},{label:"San Luis Potosi",value:"SLP"},{label:"Sinaloa",value:"SIN"},{label:"Sonora",value:"SON"},{label:"Tabasco",value:"TAB"},{label:"Tamaulipas",value:"TAM"},{label:"Tlaxcala",value:"TLA"},{label:"Veracruz",value:"VER"},{label:"Yucatan",value:"YUC"},{label:"Zacatecas",value:"ZAC"}]);break;case"Mexico":this.setStateValues(t,"Estado",[{label:"Seleccione Estado",value:""},{label:"Aguascalientes",value:"Aguascalientes"},{label:"Baja California",value:"Baja California"},{label:"Baja California Sur",value:"Baja California Sur"},{label:"Campeche",value:"Campeche"},{label:"Chiapas",value:"Chiapas"},{label:"Ciudad de Mexico",value:"Ciudad de Mexico"},{label:"Chihuahua",value:"Chihuahua"},{label:"Coahuila",value:"Coahuila"},{label:"Colima",value:"Colima"},{label:"Durango",value:"Durango"},{label:"Guanajuato",value:"Guanajuato"},{label:"Guerrero",value:"Guerrero"},{label:"Hidalgo",value:"Hidalgo"},{label:"Jalisco",value:"Jalisco"},{label:"Michoacan",value:"Michoacan"},{label:"Morelos",value:"Morelos"},{label:"Nayarit",value:"Nayarit"},{label:"Nuevo Leon",value:"Nuevo Leon"},{label:"Oaxaca",value:"Oaxaca"},{label:"Puebla",value:"Puebla"},{label:"Queretaro",value:"Queretaro"},{label:"Quintana Roo",value:"Quintana Roo"},{label:"San Luis Potosi",value:"San Luis Potosi"},{label:"Sinaloa",value:"Sinaloa"},{label:"Sonora",value:"Sonora"},{label:"Tabasco",value:"Tabasco"},{label:"Tamaulipas",value:"Tamaulipas"},{label:"Tlaxcala",value:"Tlaxcala"},{label:"Veracruz",value:"Veracruz"},{label:"Yucatan",value:"Yucatan"},{label:"Zacatecas",value:"Zacatecas"}]);break;default:this.setStateValues(t,"Province / State",null)}}setStateValues(e,t,n){const i=g.getField(e),o=i?i.closest(".en__field"):null;if(o){const i=o.querySelector(".en__field__label"),s=o.querySelector(".en__field__element");if(i&&(i.innerHTML=t),s){const i=ne(`engrid-state-${e}`);if(null==n?void 0:n.length){const t=document.createElement("select");t.name=e,t.id="en__field_"+e.toLowerCase().replace(".","_"),t.classList.add("en__field__input"),t.classList.add("en__field__input--select"),t.autocomplete="address-level1";let o=!1;n.forEach((e=>{const n=document.createElement("option");n.value=e.value,n.innerHTML=e.label,i!==e.value||o||(n.selected=!0,o=!0),e.disabled&&(n.disabled=!0),t.appendChild(n)})),s.innerHTML="",s.appendChild(t),t.addEventListener("change",this.rememberState.bind(this,e)),t.dispatchEvent(new Event("change",{bubbles:!0}))}else{s.innerHTML="";const n=document.createElement("input");n.type="text",n.name=e,n.placeholder=t,n.id="en__field_"+e.toLowerCase().replace(".","_"),n.classList.add("en__field__input"),n.classList.add("en__field__input--text"),n.autocomplete="address-level1",i&&(n.value=i),s.appendChild(n),n.addEventListener("change",this.rememberState.bind(this,e))}}}}rememberState(e){const t=g.getField(e);t&&ie(`engrid-state-${t.name}`,t.value,{expires:1,sameSite:"none",secure:!0})}}class re{constructor(){this._countryEvent=y.getInstance(),this.countryWrapper=document.querySelector(".simple_country_select"),this.countrySelect=this._countryEvent.countryField,this.country=null;const e=ne("engrid-autofill"),t=!(!g.checkNested(window.EngagingNetworks,"require","_defined","enjs","checkSubmissionFailed")||!window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed()),n=!!g.checkNested(window.Intl,"DisplayNames"),i=g.getUrlParameter("supporter.country")||g.getUrlParameter("supporter.region")||g.getUrlParameter("ea.url.id")&&!g.getUrlParameter("forwarded"),o=g.getBodyData("hide-fast-address-details")||g.getBodyData("hide-fast-personal-details");e||t||!n||i||o?this.init():fetch(`https://${window.location.hostname}/cdn-cgi/trace`).then((e=>e.text())).then((e=>{let t=e.replace(/[\r\n]+/g,'","').replace(/\=+/g,'":"');t='{"'+t.slice(0,t.lastIndexOf('","'))+'"}';const n=JSON.parse(t);this.country=n.loc,this.init()}))}init(){if(this.countrySelect&&this.country){const e=new Intl.DisplayNames(["en"],{type:"region"});this.setCountryByName(e.of(this.country),this.country)}}setCountryByName(e,t){if(this.countrySelect){let n=this.countrySelect.options;for(let i=0;i or and a 'Skip to main content' link was not added")}insertSkipLinkSpan(){document.body.insertAdjacentHTML("afterbegin",'Skip to main content ')}}class le{constructor(){this.imgSrcDefer=document.querySelectorAll("img[data-src]"),this.videoBackground=document.querySelectorAll("video"),this.videoBackgroundSource=document.querySelectorAll("video source");for(let e=0;e{e.addEventListener("click",(t=>{const n=e.className.split(" ").filter((e=>e.startsWith(this.linkClass)));g.debug&&console.log(n),n.length&&(t.preventDefault(),g.setFieldValue("transaction.recurrfreq",n[0].substring(this.linkClass.length).toUpperCase()),this._frequency.load())}))}));const e=g.getFieldValue("transaction.recurrfreq").toUpperCase();document.getElementsByName(this.checkboxName).forEach((t=>{const n=t.value.toUpperCase();t.checked=n===e,t.addEventListener("change",(()=>{const e=t.value.toUpperCase();t.checked?(g.setFieldValue("transaction.recurrfreq",e),g.setFieldValue("transaction.recurrpay","Y"),this._frequency.load(),this._amount.setAmount(this._amount.amount,!1)):"ONETIME"!==e&&(g.setFieldValue("transaction.recurrfreq","ONETIME"),g.setFieldValue("transaction.recurrpay","N"),this._frequency.load(),this._amount.setAmount(this._amount.amount,!1))}))})),this._frequency.onFrequencyChange.subscribe((()=>{const e=this._frequency.frequency.toUpperCase();document.getElementsByName(this.checkboxName).forEach((t=>{const n=t.value.toUpperCase();t.checked&&n!==e?t.checked=!1:t.checked||n!==e||(t.checked=!0)}))}))}}class de{constructor(){this.pageBackground=document.querySelector(".page-backgroundImage"),this.mutationObserver=null,this.logger=new ye("PageBackground","lightblue","darkblue","πΌοΈ"),this.pageBackground?(this.initializeBackgroundImage(),this.setDataAttributes(),this.processAttributionPositioning(),this.setupMutationObserver()):this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used")}initializeBackgroundImage(){if(!this.pageBackground)return;const e=this.pageBackground.querySelector("img");if(!e)return void this.logger.log("A background image set in the page was not found, any default image set in the theme on --engrid__page-backgroundImage_url will be used");const t=e.getAttribute("data-src"),n=e.src;t?this.setBackgroundImageUrl(t,"data-src"):n?this.setBackgroundImageUrl(n,"src"):this.logger.log("A background image set in the page was found but without a data-src or src value, no action taken",e)}setBackgroundImageUrl(e,t){if(this.pageBackground&&e)try{const n=`url('${e}')`;this.pageBackground.style.setProperty("--engrid__page-backgroundImage_url",n),this.logger.log(`A background image set in the page was found with a ${t} value, setting it as --engrid__page-backgroundImage_url`,e)}catch(e){this.logger.error("Error setting background image URL:",e)}}processAttributionPositioning(){if(!this.pageBackground)return void this.logger.log("No background section found for attribution positioning processing");this.logger.log("Processing attribution positioning for background section:",this.pageBackground);const e=["attribution-center","attribution-bottom","attribution-bottomcenter","attribution-bottomright","attribution-bottomleft","attribution-top","attribution-topcenter","attribution-topright","attribution-topleft","attribution-left","attribution-leftcenter","attribution-right","attribution-rightcenter"];try{const t=this.pageBackground.querySelectorAll("img");this.logger.log("Found images in background section:",t.length),t.forEach((t=>{this.processImageAttribution(t,e)}))}catch(e){this.logger.error("Error processing attribution positioning:",e)}}processImageAttribution(e,t){const n=t.find((t=>e.classList.contains(t))),i=e.getAttribute("data-background-position");n?this.handleClassBasedAttribution(e,n):i&&this.handleDataAttributeAttribution(e,i)}handleClassBasedAttribution(e,t){this.logger.log("Found attribution class on image:",t,e);const n=e.closest(".en__component--column");n?(e.classList.remove(t),n.classList.add(t),this.logger.log("Moved attribution class from image to parent column:",t,n)):this.logger.log("No parent .en__component--column found for image:",e)}handleDataAttributeAttribution(e,t){const n=`attribution-${t}`;this.logger.log("Found data-background-position on image:",t,"->",n,e);const i=e.closest(".en__component--column");i?(e.removeAttribute("data-background-position"),i.classList.add(n),this.logger.log("Moved data-background-position from image to parent column as class:",n,i)):this.logger.log("No parent .en__component--column found for image:",e)}setupMutationObserver(){if(this.pageBackground&&window.MutationObserver)try{this.mutationObserver=new MutationObserver((e=>{let t=!1;e.forEach((e=>{"childList"!==e.type&&"attributes"!==e.type||(t=!0)})),t&&(this.logger.log("DOM changes detected in background section, reprocessing attribution classes"),setTimeout((()=>{this.processAttributionPositioning()}),100))})),this.mutationObserver.observe(this.pageBackground,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class"]}),this.logger.log("MutationObserver set up for background section")}catch(e){this.logger.error("Error setting up MutationObserver:",e)}else window.MutationObserver||this.logger.log("MutationObserver not supported in this browser")}reprocessAttributionPositioning(){this.logger.log("Manually reprocessing attribution positioning"),this.processAttributionPositioning()}destroy(){this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null,this.logger.log("MutationObserver disconnected"))}setDataAttributes(){return this.hasVideoBackground()?g.setBodyData("page-background","video"):this.hasImageBackground()?g.setBodyData("page-background","image"):g.setBodyData("page-background","empty")}hasVideoBackground(){return!!this.pageBackground&&!!this.pageBackground.querySelector("video")}hasImageBackground(){return!!this.pageBackground&&(!this.hasVideoBackground()&&!!this.pageBackground.querySelector("img"))}}class ue{constructor(e,t=null,n=null,i){this.apiKey=e,this.dateField=t,this.statusField=n,this.dateFormat=i,this.form=h.getInstance(),this.emailField=null,this.emailWrapper=document.querySelector(".en__field--emailAddress"),this.nbDate=null,this.nbStatus=null,this.logger=new ye("NeverBounce","#039bc4","#dfdfdf","π§"),this.shouldRun=!0,this.nbLoaded=!1,this.bypassEmails=["noaddress.ea"],this.neverBounceTimeout=g.getOption("NeverBounceTimeout")||1e4,this.neverBounceTimeoutFunc=null;new URLSearchParams(window.location.search).has("bypassemailvalidation")?this.logger.log("Bypass Email Validation Enabled - not running NeverBounce"):(this.emailField=document.getElementById("en__field_supporter_emailAddress"),window._NBSettings={apiKey:this.apiKey,autoFieldHookup:!1,inputLatency:1500,displayPoweredBy:!1,loadingMessage:"Validating...",softRejectMessage:"Invalid email",acceptedMessage:"Email validated!",feedback:!1,timeout:Math.floor((this.neverBounceTimeout-1e3)/1e3)},g.loadJS("https://cdn.neverbounce.com/widget/dist/NeverBounce.js"),this.emailField&&(this.emailField.value&&(this.logger.log("E-mail Field Found"),this.shouldRun=!1),this.emailField.addEventListener("change",(e=>{var t;this.nbLoaded||(this.shouldRun=!0,this.init(),(null===(t=this.emailField)||void 0===t?void 0:t.value)&&setTimeout((function(){window._nb.fields.get(document.querySelector("[data-nb-id]"))[0].forceUpdate()}),100))})),window.setTimeout((()=>{this.emailField&&this.emailField.value&&(this.logger.log("E-mail Filled Programatically"),this.shouldRun=!1),this.init()}),1e3)),this.form.onValidate.subscribe(this.validate.bind(this)))}init(){if(!this.shouldRun)return void this.logger.log("Should Not Run");if(this.nbLoaded)return void this.logger.log("Already Loaded");if(this.logger.log("Init Function"),this.dateField&&document.getElementsByName(this.dateField).length&&(this.nbDate=document.querySelector("[name='"+this.dateField+"']")),this.statusField&&document.getElementsByName(this.statusField).length&&(this.nbStatus=document.querySelector("[name='"+this.statusField+"']")),!this.emailField)return void this.logger.log("E-mail Field Not Found");this.wrap(this.emailField,document.createElement("div"));this.emailField.parentNode.id="nb-wrapper";const e=document.createElement("div");e.innerHTML='Enter a valid email.
',this.insertAfter(e,this.emailField);const t=this;document.body.addEventListener("nb:registered",(function(e){const n=document.querySelector('[data-nb-id="'+e.detail.id+'"]');n.addEventListener("nb:loading",(function(e){g.disableSubmit("Validating Your Email"),t.setEmailStatus("loading"),t.clearTimeout(),t.neverBounceTimeoutFunc=setTimeout((()=>{t.setEmailStatus("unknown"),t.nbDate&&(t.nbDate.value=g.formatDate(new Date,t.dateFormat)),t.nbStatus&&(t.nbStatus.value="unknown"),g.enableSubmit(),window._nb.fields.unregisterListener(t.emailField),t.nbLoaded=!1,t.logger.log("NeverBounce Timeout Reached. Bypassing validation, setting unknown status and removing NB.")}),t.neverBounceTimeout)})),n.addEventListener("nb:clear",(function(e){t.nbLoaded&&(t.clearTimeout(),t.setEmailStatus("clear"),g.enableSubmit(),t.nbDate&&(t.nbDate.value=""),t.nbStatus&&(t.nbStatus.value=""))})),n.addEventListener("nb:soft-result",(function(e){t.nbLoaded&&(t.clearTimeout(),t.setEmailStatus("soft-result"),t.nbDate&&(t.nbDate.value=""),t.nbStatus&&(t.nbStatus.value=""),g.enableSubmit())})),n.addEventListener("nb:result",(function(e){t.nbLoaded&&(t.clearTimeout(),e.detail.result.is(window._nb.settings.getAcceptedStatusCodes())?(t.setEmailStatus("valid"),t.nbDate&&(t.nbDate.value=g.formatDate(new Date,t.dateFormat)),t.nbStatus&&(t.nbStatus.value=e.detail.result.response.result)):(t.setEmailStatus("invalid"),t.nbDate&&(t.nbDate.value=""),t.nbStatus&&(t.nbStatus.value="")),g.enableSubmit())}))})),window._nb.fields.registerListener(t.emailField,!0),this.nbLoaded=!0}clearStatus(){if(!this.emailField)return void this.logger.log("E-mail Field Not Found");this.emailField.classList.remove("rm-error");const e=document.getElementById("nb-wrapper"),t=document.getElementById("nb-feedback");e.className="",t.className="en__field__error nb-hidden",t.innerHTML="",this.emailWrapper.classList.remove("en__field--validationFailed")}deleteENFieldError(){const e=document.querySelector(".en__field--emailAddress>div.en__field__error");e&&e.remove()}setEmailStatus(e){if(this.logger.log("Status:",e),!this.emailField)return void this.logger.log("E-mail Field Not Found");if(this.isBypassEmail())return void this.logger.log("Bypass email detected. Skipping status update.");const t=document.getElementById("nb-wrapper");let n=document.getElementById("nb-feedback");const i="nb-hidden",o="nb-loading",s="rm-error";if(!n){const e=t.querySelector("div");e&&(e.innerHTML='Enter a valid email.
'),n=document.getElementById("nb-feedback")}if("valid"==e)this.clearStatus();else switch(t.classList.remove("nb-success"),t.classList.add("nb-error"),e){case"required":this.deleteENFieldError(),n.innerHTML="A valid email is required",n.classList.remove(o),n.classList.remove(i),this.emailField.classList.add(s);break;case"soft-result":this.emailField.value?(this.deleteENFieldError(),n.innerHTML="Invalid email",n.classList.remove(i),this.emailField.classList.add(s)):this.clearStatus();break;case"invalid":this.deleteENFieldError(),n.innerHTML="Invalid email",n.classList.remove(o),n.classList.remove(i),this.emailField.classList.add(s);break;default:this.clearStatus()}}insertAfter(e,t){var n;null===(n=null==t?void 0:t.parentNode)||void 0===n||n.insertBefore(e,t.nextSibling)}wrap(e,t){var n;null===(n=e.parentNode)||void 0===n||n.insertBefore(t,e),t.appendChild(e)}isBypassEmail(){if(!this.emailField||!this.emailField.value)return!1;const e=this.emailField.value.toLowerCase();return this.bypassEmails.some((t=>e.includes(t.toLowerCase())))}validate(){var e;if(!this.form.validate)return;const t=g.getFieldValue("nb-result");this.emailField&&this.shouldRun&&this.nbLoaded&&t?this.isBypassEmail()?this.logger.log("Bypass email detected. Skipping validation."):(this.nbStatus&&(this.nbStatus.value=t),["catchall","unknown","valid"].includes(t)||(this.setEmailStatus("required"),null===(e=this.emailField)||void 0===e||e.focus(),this.logger.log("NB-Result:",g.getFieldValue("nb-result")),this.form.validate=!1)):this.logger.log("validate(): Should Not Run. Returning true.")}clearTimeout(){this.neverBounceTimeoutFunc&&(clearTimeout(this.neverBounceTimeoutFunc),this.neverBounceTimeoutFunc=null)}}class he{constructor(){var e;this.form=h.getInstance(),this.emailField=null,this.emailWrapper=document.querySelector(".en__field--emailAddress"),this.faDate=null,this.faStatus=null,this.faMessage=null,this.logger=new ye("FreshAddress","#039bc4","#dfdfdf","π§"),this.shouldRun=!0,this.options=g.getOption("FreshAddress"),!1!==this.options&&(window.FreshAddress||(null===(e=this.options)||void 0===e?void 0:e.proxyUrl))&&(this.emailField=document.getElementById("en__field_supporter_emailAddress"),this.emailField?(this.createFields(),this.addEventListeners(),window.FreshAddressStatus="idle",this.emailField.value&&(this.logger.log("E-mail Field Found"),this.shouldRun=!1),window.setTimeout((()=>{this.emailField&&this.emailField.value&&(this.logger.log("E-mail Filled Programatically"),this.shouldRun=!1)}),1e3)):this.logger.log("E-mail Field Not Found"))}createFields(){this.options&&(this.options.dateField=this.options.dateField||"fa_date",this.faDate=g.getField(this.options.dateField),this.faDate||(this.logger.log("Date Field Not Found. Creating..."),g.createHiddenInput(this.options.dateField,""),this.faDate=g.getField(this.options.dateField)),this.options.statusField=this.options.statusField||"fa_status",this.faStatus=g.getField(this.options.statusField),this.faStatus||(this.logger.log("Status Field Not Found. Creating..."),g.createHiddenInput(this.options.statusField,""),this.faStatus=g.getField(this.options.statusField)),this.options.messageField=this.options.messageField||"fa_message",this.faMessage=g.getField(this.options.messageField),this.faMessage||(this.logger.log("Message Field Not Found. Creating..."),g.createHiddenInput(this.options.messageField,""),this.faMessage=g.getField(this.options.messageField)))}writeToFields(e,t){this.options&&(this.faDate.value=g.formatDate(new Date,this.options.dateFieldFormat||"yyyy-MM-dd"),this.faStatus.value=e,this.faMessage.value=t,this.emailWrapper.dataset.freshaddressSafetosendstatus=e.toLowerCase())}addEventListeners(){var e;this.options&&(null===(e=this.emailField)||void 0===e||e.addEventListener("change",(()=>{var e,t;if(!this.shouldRun||(null===(e=this.emailField)||void 0===e?void 0:e.value.includes("@4sitestudios.com")))return g.removeError(this.emailWrapper),this.writeToFields("Valid","Skipped"),void this.logger.log("Skipping E-mail Validation");this.logger.log("Validating "+(null===(t=this.emailField)||void 0===t?void 0:t.value)),this.options&&this.options.proxyUrl?this.callProxy():this.callAPI()})),this.form.onValidate.subscribe(this.validate.bind(this)))}callAPI(){var e;if(!this.options||!window.FreshAddress)return;if(!this.shouldRun)return;window.FreshAddressStatus="validating";const t=null===(e=this.emailField)||void 0===e?void 0:e.value;window.FreshAddress.validateEmail(t,{emps:!1,rtc_timeout:1200}).then((e=>(this.logger.log("Validate API Response",JSON.parse(JSON.stringify(e))),this.validateResponse(e))))}validateResponse(e){var t;if(e.isServiceError())return this.logger.log("Service Error"),this.writeToFields("Service Error",e.getErrorResponse()),!0;e.isValid()?(this.writeToFields("Valid",e.getComment()),g.removeError(this.emailWrapper),e.hasSuggest()&&(g.setError(this.emailWrapper,`Did you mean ${e.getSuggEmail()}?`),this.emailField.value=e.getSuggEmail())):e.isError()?(this.writeToFields("Invalid",e.getErrorResponse()),g.setError(this.emailWrapper,e.getErrorResponse()),null===(t=this.emailField)||void 0===t||t.focus(),e.hasSuggest()&&(g.setError(this.emailWrapper,`Did you mean ${e.getSuggEmail()}?`),this.emailField.value=e.getSuggEmail(),this.writeToFields("Error",e.getErrorResponse()))):e.isWarning()?(this.writeToFields("Invalid",e.getErrorResponse()),g.setError(this.emailWrapper,e.getErrorResponse()),e.hasSuggest()&&(g.setError(this.emailWrapper,`Did you mean ${e.getSuggEmail()}?`),this.emailField.value=e.getSuggEmail(),this.writeToFields("Warning",e.getErrorResponse()))):this.writeToFields("API Error","Unknown Error"),window.FreshAddressStatus="idle",g.enableSubmit()}validate(){var e;if(g.removeError(this.emailWrapper),this.form.validate)if(this.options)if(this.shouldRun){if("validating"!==window.FreshAddressStatus)return"Invalid"===this.faStatus.value?(this.form.validate=!1,window.setTimeout((()=>{g.setError(this.emailWrapper,"This email address is not valid.")}),100),null===(e=this.emailField)||void 0===e||e.focus(),g.enableSubmit(),!1):(this.form.validate=!0,!0);{this.logger.log("Waiting for API Response");const e=new Promise(((e,t)=>{setTimeout((()=>{var n;const i=this.faStatus.value;if(""===i||"Invalid"===i)return this.logger.log("Promise Rejected"),null===(n=this.emailField)||void 0===n||n.focus(),void t(!1);this.logger.log("Promise Resolved"),e(!0)}),700)}));this.form.validatePromise=e}}else this.form.validate=!0;else this.form.validate=!0}callProxy(){var e,t;if(!this.options||!this.shouldRun)return;window.FreshAddressStatus="validating",g.disableSubmit("Validating Email Address...");if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.emailField.value))return this.logger.log("Invalid Email Format from Basic Check"),this.writeToFields("Invalid","Invalid Email Format"),g.setError(this.emailWrapper,"This email address is not valid."),null===(e=this.emailField)||void 0===e||e.focus(),void g.enableSubmit();fetch(this.options.proxyUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:null===(t=this.emailField)||void 0===t?void 0:t.value}),signal:AbortSignal.timeout(5e3)}).then((e=>{if(!e.ok)throw new Error(`HTTP error ${e.status}`);return e.json()})).then((e=>{this.logger.log("Proxy API Response",e),this.validateProxyResponse(e)})).catch((e=>e.message.includes("422")?(this.logger.log("Invalid Email Format"),this.writeToFields("Invalid","Invalid Email Format"),void g.setError(this.emailWrapper,"This email address is not valid.")):"AbortError"===e.name?(this.logger.log("Proxy API request timed out"),void this.writeToFields("Request Timeout","The request took too long.")):(this.logger.log("Proxy API Error",e),void this.writeToFields("Service Error",e.toString())))).finally((()=>{window.FreshAddressStatus="idle",g.enableSubmit()}))}validateProxyResponse(e){var t;if(!e.safe_to_send)return this.logger.log("Invalid Proxy Response"),this.writeToFields("Service Error","Invalid Proxy Response"),!0;const n=e.safe_to_send;g.removeError(this.emailWrapper),this.writeToFields(n.status,n.status_code),["invalid","trap"].includes(n.status)&&(this.writeToFields("Invalid",n.status_code),g.setError(this.emailWrapper,"This email address is not valid."),null===(t=this.emailField)||void 0===t||t.focus(),n.email_corrections&&n.email_corrections.length>0&&(this.emailField.value=n.email_corrections[0],g.setError(this.emailWrapper,`This email address is not valid. Did you mean ${n.email_corrections[0]}?`)))}}class pe{constructor(){var e,t;const n=document.querySelector("span[data-engrid-progress-indicator]"),i=g.getPageCount(),o=g.getPageNumber();if(!n||!i||!o)return;let s=null!==(e=n.getAttribute("max"))&&void 0!==e?e:100;"string"==typeof s&&(s=parseInt(s));let r=null!==(t=n.getAttribute("amount"))&&void 0!==t?t:0;"string"==typeof r&&(r=parseInt(r));const a=1===o?0:Math.ceil((o-1)/i*s);let l=1===o?0:Math.ceil(o/i*s);const c=a/100;let d=l/100;if(r&&(l=Math.ceil(r)>Math.ceil(s)?s:r,d=l/100),n.innerHTML=`\n\t\t\t\n\t\t\t\t \n\t\t\t\t${l}% \n\t\t\t
`,l!==a){const e=document.querySelector(".indicator__progress");requestAnimationFrame((function(){e.style.transform=`scaleX(${d})`}))}}}const ge=n(9244).Ay;class me{constructor(e){if(this._form=h.getInstance(),this._events=b.getInstance(),this.iframe=null,this.remoteUrl=e.remoteUrl?e.remoteUrl:null,this.cookieName=e.cookieName?e.cookieName:"engrid-autofill",this.cookieExpirationDays=e.cookieExpirationDays?e.cookieExpirationDays:365,this.rememberMeOptIn=!!e.checked&&e.checked,this.fieldNames=e.fieldNames?e.fieldNames:[],this.fieldDonationAmountRadioName=e.fieldDonationAmountRadioName?e.fieldDonationAmountRadioName:"transaction.donationAmt",this.fieldDonationAmountOtherName=e.fieldDonationAmountOtherName?e.fieldDonationAmountOtherName:"transaction.donationAmt.other",this.fieldDonationRecurrPayRadioName=e.fieldDonationRecurrPayRadioName?e.fieldDonationRecurrPayRadioName:"transaction.recurrpay",this.fieldDonationAmountOtherCheckboxID=e.fieldDonationAmountOtherCheckboxID?e.fieldDonationAmountOtherCheckboxID:"#en__field_transaction_donationAmt4",this.fieldOptInSelectorTarget=e.fieldOptInSelectorTarget?e.fieldOptInSelectorTarget:".en__field--emailAddress.en__field",this.fieldOptInSelectorTargetLocation=e.fieldOptInSelectorTargetLocation?e.fieldOptInSelectorTargetLocation:"after",this.fieldClearSelectorTarget=e.fieldClearSelectorTarget?e.fieldClearSelectorTarget:'label[for="en__field_supporter_firstName"]',this.fieldClearSelectorTargetLocation=e.fieldClearSelectorTargetLocation?e.fieldClearSelectorTargetLocation:"before",this.fieldData={},this.useRemote())this.createIframe((()=>{this.iframe&&this.iframe.contentWindow&&(this.iframe.contentWindow.postMessage(JSON.stringify({key:this.cookieName,operation:"read"}),"*"),this._form.onSubmit.subscribe((()=>{this.rememberMeOptIn&&(this.readFields(),this.saveCookieToRemote())})))}),(e=>{let t;if(e.data&&"string"==typeof e.data&&this.isJson(e.data)&&(t=JSON.parse(e.data)),t&&t.key&&void 0!==t.value&&t.key===this.cookieName){this.updateFieldData(t.value),this.writeFields(),Object.keys(this.fieldData).length>0?this.insertClearRememberMeLink():this.insertRememberMeOptin()}}));else{this.readCookie(),Object.keys(this.fieldData).length>0?(this.insertClearRememberMeLink(),this.rememberMeOptIn=!0):(this.insertRememberMeOptin(),this.rememberMeOptIn=!1),this.writeFields(),this._form.onSubmit.subscribe((()=>{this.rememberMeOptIn&&(this.readFields(),this.saveCookie())}))}}updateFieldData(e){if(e){let t=JSON.parse(e);for(let e=0;e{e.preventDefault(),this.clearFields(["supporter.country"]),this.useRemote()?this.clearCookieOnRemote():this.clearCookie();let t=document.getElementById("clear-autofill-data");t&&(t.style.display="none"),this.rememberMeOptIn=!1,this._events.dispatchClear(),window.dispatchEvent(new CustomEvent("RememberMe_Cleared"))})),this._events.dispatchLoad(!0),window.dispatchEvent(new CustomEvent("RememberMe_Loaded",{detail:{withData:!0}}))}getElementByFirstSelector(e){let t=null;const n=e.split(",");for(let e=0;e\n \n \n\t\t\t`;const o=this.getElementByFirstSelector(this.fieldOptInSelectorTarget);if(o&&o.parentNode){o.parentNode.insertBefore(i,"before"==this.fieldOptInSelectorTargetLocation?o:o.nextSibling);const e=document.getElementById("remember-me-checkbox");e&&e.addEventListener("change",(()=>{e.checked?this.rememberMeOptIn=!0:this.rememberMeOptIn=!1})),ge("#rememberme-learn-more-toggle",{content:t})}}this._events.dispatchLoad(!1),window.dispatchEvent(new CustomEvent("RememberMe_Loaded",{detail:{withData:!1}}))}useRemote(){return!!this.remoteUrl&&"function"==typeof window.postMessage&&window.JSON&&window.localStorage}createIframe(e,t){if(this.remoteUrl){let n=document.createElement("iframe");n.style.cssText="position:absolute;width:1px;height:1px;left:-9999px;",n.src=this.remoteUrl,n.setAttribute("sandbox","allow-same-origin allow-scripts"),n.setAttribute("title","Remember Me iframe"),this.iframe=n,document.body.appendChild(this.iframe),this.iframe.addEventListener("load",(()=>e()),!1),window.addEventListener("message",(e=>{var n;(null===(n=this.iframe)||void 0===n?void 0:n.contentWindow)===e.source&&t(e)}),!1)}}clearCookie(){this.fieldData={},this.saveCookie()}clearCookieOnRemote(){this.fieldData={},this.saveCookieToRemote()}saveCookieToRemote(){this.iframe&&this.iframe.contentWindow&&this.iframe.contentWindow.postMessage(JSON.stringify({key:this.cookieName,value:this.fieldData,operation:"write",expires:this.cookieExpirationDays}),"*")}readCookie(){this.updateFieldData(ne(this.cookieName)||"")}saveCookie(){ie(this.cookieName,JSON.stringify(this.fieldData),{expires:this.cookieExpirationDays})}readFields(){for(let e=0;e0)return this._amount.onAmountChange.subscribe((()=>this.init())),void this.init();this.logger.log("Show If Amount: NO ELEMENTS FOUND")}init(){const e=g.getGiftProcess()?window.pageJson.amount:this._amount.amount;this._elements.forEach((t=>{this.lessthan(e,t),this.lessthanorequalto(e,t),this.equalto(e,t),this.greaterthanorequalto(e,t),this.greaterthan(e,t),this.between(e,t)}))}getClassNameByOperand(e,t){let n=null;return e.forEach((e=>{e.includes(`showifamount-${t}-`)&&(n=e)})),n}lessthan(e,t){const n=this.getClassNameByOperand(t.classList,"lessthan");if(n){let i=n.split("-").slice(-1)[0];e=Number(i)?(this.logger.log("(greaterthanorequalto):",t),t.classList.add("engrid-open")):t.classList.remove("engrid-open")}}greaterthan(e,t){const n=this.getClassNameByOperand(t.classList,"greaterthan");if(n){let i=n.split("-").slice(-1)[0];e>Number(i)?(this.logger.log("(greaterthan):",t),t.classList.add("engrid-open")):t.classList.remove("engrid-open")}}between(e,t){const n=this.getClassNameByOperand(t.classList,"between");if(n){let i=n.split("-").slice(-2,-1)[0],o=n.split("-").slice(-1)[0];e>Number(i)&&e{var t;null===(t=document.querySelector("body"))||void 0===t||t.addEventListener(e,(e=>{e.target.classList.contains("en__field__input--other")&&(this.logger.log("Other Amount Field Focused"),this.setRadioInput())}))}));const e=document.querySelector("[name='transaction.donationAmt.other'");e&&(e.setAttribute("inputmode","decimal"),e.setAttribute("aria-label","Enter your custom donation amount"),e.setAttribute("autocomplete","off"),e.setAttribute("data-lpignore","true"),e.addEventListener("change",(e=>{const t=e.target,n=t.value,i=g.cleanAmount(n);n!==i.toString()&&(this.logger.log(`Other Amount Field Changed: ${n} => ${i}`),"dataLayer"in window&&window.dataLayer.push({event:"otherAmountTransformed",otherAmountTransformation:`${n} => ${i}`}),t.value=i%1!=0?i.toFixed(2):i.toString())})),e.addEventListener("blur",(e=>{const t=e.target.value;if(0===g.cleanAmount(t)){this.logger.log("Other Amount Field Blurred with 0 amount");const e=this._amount.amount;e>0&&this._amount.setAmount(e,!1)}})))}setRadioInput(){const e=document.querySelector(".en__field--donationAmt .en__field__input--other");if(e&&e.parentNode&&e.parentNode.parentNode){const t=e.parentNode;if(t.classList.remove("en__field__item--hidden"),t.parentNode){t.parentNode.querySelector(".en__field__item:nth-last-child(2) input").checked=!0}}}}class ye{constructor(e,t,n,i){if(this.prefix="",this.color="black",this.background="white",this.emoji="",i)this.emoji=i;else switch(t){case"red":this.emoji="π΄";break;case"green":this.emoji="π’";break;case"blue":this.emoji="π΅";break;case"yellow":this.emoji="π‘",this.background="black";break;case"purple":this.emoji="π£";break;default:this.emoji="β«"}e&&(this.prefix=`[ENgrid ${e}]`),t&&(this.color=t),n&&(this.background=n)}get log(){return g.debug||"log"===g.getUrlParameter("debug")?console.log.bind(window.console,"%c"+this.emoji+" "+this.prefix+" %s",`color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`):()=>{}}get success(){return g.debug?console.log.bind(window.console,"%c β
"+this.prefix+" %s","color: green; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;"):()=>{}}get danger(){return g.debug?console.log.bind(window.console,"%c βοΈ "+this.prefix+" %s","color: red; background-color: white; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;"):()=>{}}get warn(){return g.debug?console.warn.bind(window.console,"%c"+this.emoji+" "+this.prefix+" %s",`color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`):()=>{}}get dir(){return g.debug?console.dir.bind(window.console,"%c"+this.emoji+" "+this.prefix+" %s",`color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`):()=>{}}get error(){return g.debug?console.error.bind(window.console,"%c"+this.emoji+" "+this.prefix+" %s",`color: ${this.color}; background-color: ${this.background}; font-size: 1.2em; padding: 4px; border-radius: 2px; font-family: monospace;`):()=>{}}}class ve{constructor(){var e,t;this._form=h.getInstance(),this._amount=p.getInstance(),this._frequency=m.getInstance(),this.minAmount=null!==(e=g.getOption("MinAmount"))&&void 0!==e?e:1,this.maxAmount=null!==(t=g.getOption("MaxAmount"))&&void 0!==t?t:1e5,this.minAmountMessage=g.getOption("MinAmountMessage"),this.maxAmountMessage=g.getOption("MaxAmountMessage"),this.enAmountValidator=null,this.logger=new ye("MinMaxAmount","white","purple","π’"),this.shouldRun()&&(this.setValidationConfigFromEN(),this._amount.onAmountChange.subscribe((e=>window.setTimeout(this.liveValidate.bind(this),1e3))),this._form.onValidate.subscribe(this.enOnValidate.bind(this)))}shouldRun(){return"DONATION"===g.getPageType()}enOnValidate(){if(!this._form.validate)return;const e=document.querySelector("[name='transaction.donationAmt.other']");this._amount.amountthis.maxAmount&&(this.logger.log("Amount is greater than max amount: "+this.maxAmount),e&&e.focus(),this._form.validate=!1),window.setTimeout(this.liveValidate.bind(this),300)}liveValidate(){const e=g.cleanAmount(this._amount.amount.toString()),t=document.activeElement;t&&"INPUT"===t.tagName&&"name"in t&&"transaction.donationAmt.other"===t.name&&0===e||(this.logger.log(`Amount: ${e}`),ethis.maxAmount?(this.logger.log("Amount is greater than max amount: "+this.maxAmount),g.setError(".en__field--withOther",this.maxAmountMessage||"Invalid Amount")):g.removeError(".en__field--withOther"))}setValidationConfigFromEN(){g.getOption("UseAmountValidatorFromEN")&&window.EngagingNetworks.validators?(this.enAmountValidator=window.EngagingNetworks.validators.find((e=>{var t;return("FAMNT"===e.type||"AMNT"===e.type)&&(null===(t=document.querySelector(".en__field--"+e.componentId))||void 0===t?void 0:t.classList.contains("en__field--donationAmt"))})),this.enAmountValidator&&this.enAmountValidator.format&&(this.logger.log("Detected an amount validator for donation amount on the page:",this.enAmountValidator),"AMNT"===this.enAmountValidator.type&&(this.minAmount=Number(this.enAmountValidator.format.split("~")[0]),this.maxAmount=Number(this.enAmountValidator.format.split("~")[1]),this.minAmountMessage=this.enAmountValidator.errorMessage,this.maxAmountMessage=this.enAmountValidator.errorMessage,this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`)),"FAMNT"===this.enAmountValidator.type&&this._frequency.onFrequencyChange.subscribe((e=>{if(!this.enAmountValidator||!this.enAmountValidator.format)return;const t="onetime"===e?"SINGLE":e.toUpperCase(),n=this.enAmountValidator.format.split("|").find((e=>e.startsWith(t)));if(!n)return void this.logger.log(`No validation range found for frequency: ${t}`);const i=n.split(":")[1].split("~");this.minAmount=Number(i[0]),this.maxAmount=Number(i[1]),this.minAmountMessage=this.enAmountValidator.errorMessage,this.maxAmountMessage=this.enAmountValidator.errorMessage,this.logger.log(`Frequency changed to ${t}, updating min and max amounts`,n),this.logger.log(`Setting new values - Min Amount: ${this.minAmount}, Max Amount: ${this.maxAmount}, Error Message: ${this.minAmountMessage}`)})))):this.logger.log("Not setting validation config from EN.")}}class _e{constructor(){if(this.shuffleSeed=n(3184),this.items=[],this.tickerElement=document.querySelector(".engrid-ticker"),this.logger=new ye("Ticker","black","beige","π"),!this.shouldRun())return void this.logger.log("Not running");const e=document.querySelectorAll(".engrid-ticker li");if(e.length>0)for(let t=0;t=n.length&&(r=0);return n.slice(r,r+e).reverse()}render(){var e,t,n;this.logger.log("Rendering");const i=this.getItems();let o=document.createElement("div");o.classList.add("en__component"),o.classList.add("en__component--ticker");let s='';for(let e=0;e'+i[e]+"
";s=''+s+"
",o.innerHTML=s,null===(t=null===(e=this.tickerElement)||void 0===e?void 0:e.parentElement)||void 0===t||t.insertBefore(o,this.tickerElement),null===(n=this.tickerElement)||void 0===n||n.remove();const r=document.querySelector(".ticker").offsetWidth.toString();o.style.setProperty("--ticker-size",r),this.logger.log("Ticker Size: "+o.style.getPropertyValue("--ticker-size")),this.logger.log("Ticker Width: "+r)}}var Se=function(e,t,n,i){return new(n||(n=Promise))((function(o,s){function r(e){try{l(i.next(e))}catch(e){s(e)}}function a(e){try{l(i.throw(e))}catch(e){s(e)}}function l(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}l((i=i.apply(e,t||[])).next())}))};class we{constructor(){this.logger=new ye("DataLayer","#f1e5bc","#009cdc","π"),this.dataLayer=window.dataLayer||[],this._form=h.getInstance(),this.encoder=new TextEncoder,this.endOfGiftProcessStorageKey="ENGRID_END_OF_GIFT_PROCESS_EVENTS",this.giftFields=["amount","currency","donationLogId","feeCover","giftProcess","paymentType","receiptNumber","recurring","transactionId","transactionType"],this.excludedFields=["transaction.ccnumber","transaction.ccexpire.delimiter","transaction.ccexpire","transaction.ccvv","supporter.creditCardHolderName","supporter.bankAccountNumber","supporter.bankAccountType","transaction.bankname","supporter.bankRoutingNumber"],this.hashedFields=["supporter.emailAddress","supporter.phoneNumber","supporter.phoneNumber2","supporter.address1","supporter.address2","supporter.address3","transaction.infemail","transaction.infadd1","transaction.infadd2","transaction.infadd3","supporter.billingAddress1","supporter.billingAddress2","supporter.billingAddress3"],this.retainedEmailField="supporter.emailAddress",this.retainedAddressFields=["supporter.address1","supporter.address2","supporter.address3"],this.retainedPhoneFields=["supporter.phoneNumber2","supporter.phoneNumber"],g.getOption("RememberMe")?b.getInstance().onLoad.subscribe((e=>{this.logger.log("Remember me - onLoad",e),this.onLoad()})):this.onLoad(),this._form.onSubmit.subscribe((()=>this.onSubmit()))}static getInstance(){return we.instance||(we.instance=new we,window._dataLayer=we.instance),we.instance}transformJSON(e){return"string"==typeof e?e.toUpperCase().trim().replace(/\s+/g,"-").replace(/:-/g,"-"):"boolean"==typeof e?e?"TRUE":"FALSE":"number"==typeof e?e:""}onLoad(){const e={},t="ECARD"===g.getPageType()&&g.getOption("SuppressPurchaseEcard");if(g.getGiftProcess()&&(t?(this.logger.log("β Gift process was detected BUT suppressing EN_SUCCESSFUL_DONATION event due to SuppressPurchaseEcard option enabled"),window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey)):(this.logger.log("EN_SUCCESSFUL_DONATION"),this.addEndOfGiftProcessEventsToDataLayer())),window.pageJson){const n=window.pageJson;for(const i in n){if(t&&this.giftFields.includes(i))continue;const o=`EN_PAGEJSON_${i.toUpperCase()}`,s=n[i];e[o]=this.transformJSON(s)}g.getPageCount()===g.getPageNumber()&&(e[`EN_SUBMISSION_SUCCESS_${n.pageType.toUpperCase()}`]="TRUE")}if(new URLSearchParams(window.location.search).forEach(((t,n)=>{e[`EN_URLPARAM_${n.toUpperCase()}`]=this.transformJSON(t)})),this.addRetainedHashesToDataLayer(e),"DONATION"===g.getPageType()){const t=[...document.querySelectorAll('[name="transaction.recurrfreq"]')].map((e=>e.value));e.EN_RECURRING_FREQUENCIES=t}Object.keys(e).length>0&&(e.event="pageJsonVariablesReady",this.dataLayer.push(e)),this.attachEventListeners()}addRetainedHashesToDataLayer(e){"undefined"!=typeof window&&window.localStorage&&["EMAIL","ADDRESS","PHONE"].forEach((t=>{const n=`EN_HASH_${t}`,i=window.localStorage.getItem(n);i&&(e[n]=i)}))}onSubmit(){document.querySelector(".en__field__item:not(.en__field--question) input[name^='supporter.questions'][type='checkbox']:checked")?(this.logger.log("EN_SUBMISSION_WITH_EMAIL_OPTIN"),this.dataLayer.push({event:"EN_SUBMISSION_WITH_EMAIL_OPTIN"})):(this.logger.log("EN_SUBMISSION_WITHOUT_EMAIL_OPTIN"),this.dataLayer.push({event:"EN_SUBMISSION_WITHOUT_EMAIL_OPTIN"}))}attachEventListeners(){document.querySelectorAll(".en__component--advrow input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=hidden]):not([unhidden]), .en__component--advrow textarea").forEach((e=>{e.addEventListener("blur",(e=>{this.handleFieldValueChange(e.target)}))}));document.querySelectorAll(".en__component--advrow input[type=checkbox], .en__component--advrow input[type=radio]").forEach((e=>{e.addEventListener("change",(e=>{this.handleFieldValueChange(e.target)}))}));document.querySelectorAll(".en__component--advrow select").forEach((e=>{e.addEventListener("change",(e=>{this.handleFieldValueChange(e.target)}))}))}handleFieldValueChange(e){var t,n,i;return Se(this,void 0,void 0,(function*(){if(""===e.value||this.excludedFields.includes(e.name))return;const o=this.hashedFields.includes(e.name)?yield this.hash(e.value):e.value;if(["checkbox","radio"].includes(e.type))e.checked&&("en__pg"===e.name?this.dataLayer.push({event:"EN_FORM_VALUE_UPDATED",enFieldName:e.name,enFieldLabel:"Premium Gift",enFieldValue:null===(n=null===(t=e.closest(".en__pg__body"))||void 0===t?void 0:t.querySelector(".en__pg__name"))||void 0===n?void 0:n.textContent,enProductId:null===(i=document.querySelector('[name="transaction.selprodvariantid"]'))||void 0===i?void 0:i.value}):this.dataLayer.push({event:"EN_FORM_VALUE_UPDATED",enFieldName:e.name,enFieldLabel:this.getFieldLabel(e),enFieldValue:o}));else{if(e.name===this.retainedEmailField){const t=this.geRetainedFieldsValue("email"),n=yield this.hash(t);return localStorage.setItem("EN_HASH_EMAIL",n),void this.dataLayer.push({event:"EN_HASH_VALUE_UPDATED",enFieldName:"email",enFieldLabel:this.getFieldLabel(e),enFieldValue:n})}if(this.retainedAddressFields.includes(e.name)){const e=this.geRetainedFieldsValue("address"),t=yield this.hash(e);localStorage.setItem("EN_HASH_ADDRESS",t),this.dataLayer.push({event:"EN_HASH_VALUE_UPDATED",enFieldName:"address",enFieldLabel:"Supporter Address",enFieldValue:t})}else if(this.retainedPhoneFields.includes(e.name)){const e=this.geRetainedFieldsValue("phone"),t=yield this.hash(e);localStorage.setItem("EN_HASH_PHONE",t),this.dataLayer.push({event:"EN_HASH_VALUE_UPDATED",enFieldName:"phone",enFieldLabel:"Supporter Phone",enFieldValue:t})}this.dataLayer.push({event:"EN_FORM_VALUE_UPDATED",enFieldName:e.name,enFieldLabel:this.getFieldLabel(e),enFieldValue:o})}}))}geRetainedFieldsValue(e){switch(e){case"email":return g.getFieldValue(this.retainedEmailField);case"address":return this.retainedAddressFields.map((e=>g.getFieldValue(e))).filter((e=>""!==e)).join("").toLocaleLowerCase().replace(/\s+/g,"");case"phone":for(const e of this.retainedPhoneFields){const t=g.getFieldValue(e);if(""!==t)return t.replace(/\D/g,"")}return"";default:return""}}hash(e){return Se(this,void 0,void 0,(function*(){const t=this.encoder.encode(e),n=yield crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map((e=>{const t=e.toString(16);return 1===t.length?"0"+t:t})).join("")}))}getFieldLabel(e){var t,n;return(null===(n=null===(t=e.closest(".en__field"))||void 0===t?void 0:t.querySelector("label"))||void 0===n?void 0:n.textContent)||""}addEndOfGiftProcessEvent(e,t={}){this.storeEndOfGiftProcessData(Object.assign({event:e},t))}addEndOfGiftProcessVariable(e,t=""){this.storeEndOfGiftProcessData({[e.toUpperCase()]:t})}storeEndOfGiftProcessData(e){const t=this.getEndOfGiftProcessData();t.push(e),window.sessionStorage.setItem(this.endOfGiftProcessStorageKey,JSON.stringify(t))}addEndOfGiftProcessEventsToDataLayer(){this.getEndOfGiftProcessData().forEach((e=>{this.dataLayer.push(e)})),window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey)}getEndOfGiftProcessData(){let e=window.sessionStorage.getItem(this.endOfGiftProcessStorageKey);return e?JSON.parse(e):[]}}class Ee{constructor(){this.logger=new ye("DataReplace","#333333","#00f3ff","‡οΈ"),this.enElements=new Array,this.searchElements(),this.shouldRun()&&(this.logger.log("Elements Found:",this.enElements),this.replaceAll())}searchElements(){const e=document.querySelectorAll("\n .en__component--copyblock,\n .en__component--codeblock,\n .en__field\n ");e.length>0&&e.forEach((e=>{e instanceof HTMLElement&&e.innerHTML.includes("{engrid_data~")&&this.enElements.push(e)}))}shouldRun(){return this.enElements.length>0}replaceAll(){const e=/{engrid_data~\[([\w-]+)\]~?\[?(.+?)?\]?}/g;this.enElements.forEach((t=>{const n=t.innerHTML.matchAll(e);for(const e of n)this.replaceItem(t,e)})),g.setBodyData("merge-tags-processed","")}replaceItem(e,[t,n,i]){var o;let s=null!==(o=g.getUrlParameter(`engrid_data[${n}]`))&&void 0!==o?o:i;s="string"==typeof s?s.replace(/\r?\\n|\n|\r/g," "):"",this.logger.log("Replacing",n,s),e.innerHTML=e.innerHTML.replace(t,s)}}class Ae{constructor(){this.logger=new ye("DataHide","#333333","#f0f0f0","π"),this.enElements=new Array,this.logger.log("Constructor"),this.enElements=g.getUrlParameter("engrid_hide[]"),this.enElements&&0!==this.enElements.length?(this.logger.log("Elements Found:",this.enElements),this.hideAll()):this.logger.log("No Elements Found")}hideAll(){this.enElements.forEach((e=>{const t=Object.keys(e)[0],n=Object.values(e)[0];this.hideItem(t,n)}))}hideItem(e,t){const n=[...e.matchAll(/engrid_hide\[([\w-]+)\]/g)].map((e=>e[1]))[0];if("id"===t){const e=document.getElementById(n);e?(this.logger.log("Hiding By ID",n,e),e.setAttribute("hidden-via-url-argument","")):this.logger.error("Element Not Found By ID",n)}else{const e=document.getElementsByClassName(n);if(e.length>0)for(let t=0;t{const t=e.target;o&&!s&&(s=!0,o.value=o.value.concat("\n"+t.value))})),!o.value.includes("{user_data~Last Name")&&i&&i.addEventListener("blur",(e=>{const t=e.target;o&&!r&&(r=!0,o.value=o.value.concat(" "+t.value))}))}}}class ke{constructor(){if(this._form=h.getInstance(),this.logger=new ye("ExpandRegionName","#333333","#00eb65","π"),this.shouldRun()){const e=g.getOption("RegionLongFormat");console.log("expandedRegionField",e);document.querySelector(`[name="${e}"]`)||(this.logger.log(`CREATED field ${e}`),g.createHiddenInput(e)),this._form.onValidate.subscribe((()=>this.expandRegion()))}}shouldRun(){return!!g.getOption("RegionLongFormat")}expandRegion(){if(!this._form.validate)return;const e=document.querySelector('[name="supporter.region"]'),t=g.getOption("RegionLongFormat"),n=document.querySelector(`[name="${t}"]`);if(e){if("SELECT"===e.tagName&&"options"in e){const t=e.options[e.selectedIndex].innerText;n.value=t,this.logger.log("Populated field",n.value)}else if("INPUT"===e.tagName){const t=e.value;n.value=t,this.logger.log("Populated field",n.value)}return!0}this.logger.log("No region field to populate the hidden region field with")}}class Le{constructor(){this.logger=new ye("UrlToForm","white","magenta","π"),this.urlParams=new URLSearchParams(document.location.search),this.shouldRun()&&this.urlParams.forEach(((e,t)=>{const n=document.getElementsByName(t)[0];n&&("checkbox"===n.type?(n.checked="true"===e||"Y"===e||"1"===e,g.setFieldValue(t,n.checked),this.logger.log(`Set: ${t} to ${n.checked}`)):["text","textarea","email"].includes(n.type)&&n.value||(g.setFieldValue(t,e),this.logger.log(`Set: ${t} to ${e}`)))}))}shouldRun(){return!!document.location.search&&this.hasFields()}hasFields(){return[...this.urlParams.keys()].map((e=>document.getElementsByName(e).length>0)).includes(!0)}}class Fe{constructor(){this.logger=new ye("RequiredIfVisible","#FFFFFF","#811212","π₯"),this._form=h.getInstance(),this.requiredIfVisibleElements=document.querySelectorAll("\n .i-required .en__field,\n .i1-required .en__field:nth-of-type(1),\n .i2-required .en__field:nth-of-type(2),\n .i3-required .en__field:nth-of-type(3),\n .i4-required .en__field:nth-of-type(4),\n .i5-required .en__field:nth-of-type(5),\n .i6-required .en__field:nth-of-type(6),\n .i7-required .en__field:nth-of-type(7),\n .i8-required .en__field:nth-of-type(8),\n .i9-required .en__field:nth-of-type(9),\n .i10-required .en__field:nth-of-type(10),\n .i11-required .en__field:nth-of-type(11)\n "),this.shouldRun()&&this._form.onValidate.subscribe(this.validate.bind(this))}shouldRun(){return this.requiredIfVisibleElements.length>0}validate(){Array.from(this.requiredIfVisibleElements).reverse().forEach((e=>{if(g.removeError(e),g.isVisible(e)){this.logger.log(`${e.getAttribute("class")} is visible`);const t=e.querySelector("input:not([type=hidden]) , select, textarea");if(t&&null===t.closest("[data-unhidden]")&&!g.getFieldValue(t.getAttribute("name"))){const n=e.querySelector(".en__field__label");n?(this.logger.log(`${n.innerText} is required`),window.setTimeout((()=>{g.setError(e,`${n.innerText} is required`)}),100)):(this.logger.log(`${t.getAttribute("name")} is required`),window.setTimeout((()=>{g.setError(e,"This field is required")}),100)),t.focus(),this._form.validate=!1}}}))}}var qe=function(e,t,n,i){return new(n||(n=Promise))((function(o,s){function r(e){try{l(i.next(e))}catch(e){s(e)}}function a(e){try{l(i.throw(e))}catch(e){s(e)}}function l(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}l((i=i.apply(e,t||[])).next())}))};class Ne{constructor(){var e,t,n,i,o;if(this.logger=new ye("TidyContact","#FFFFFF","#4d9068","π§"),this.endpoint="https://api.tidycontact.io",this.wasCalled=!1,this.httpStatus=0,this.timeout=5,this.isDirty=!1,this._form=h.getInstance(),this.countries_list=[["Afghanistan","af","93","070 123 4567"],["Albania","al","355","067 212 3456"],["Algeria","dz","213","0551 23 45 67"],["American Samoa","as","1","(684) 733-1234"],["Andorra","ad","376","312 345"],["Angola","ao","244","923 123 456"],["Anguilla","ai","1","(264) 235-1234"],["Antigua and Barbuda","ag","1","(268) 464-1234"],["Argentina","ar","54","011 15-2345-6789"],["Armenia","am","374","077 123456"],["Aruba","aw","297","560 1234"],["Australia","au","61","0412 345 678"],["Austria","at","43","0664 123456"],["Azerbaijan","az","994","040 123 45 67"],["Bahamas","bs","1","(242) 359-1234"],["Bahrain","bh","973","3600 1234"],["Bangladesh","bd","880","01812-345678"],["Barbados","bb","1","(246) 250-1234"],["Belarus","by","375","8 029 491-19-11"],["Belgium","be","32","0470 12 34 56"],["Belize","bz","501","622-1234"],["Benin","bj","229","90 01 12 34"],["Bermuda","bm","1","(441) 370-1234"],["Bhutan","bt","975","17 12 34 56"],["Bolivia","bo","591","71234567"],["Bosnia and Herzegovina","ba","387","061 123 456"],["Botswana","bw","267","71 123 456"],["Brazil","br","55","(11) 96123-4567"],["British Indian Ocean Territory","io","246","380 1234"],["British Virgin Islands","vg","1","(284) 300-1234"],["Brunei","bn","673","712 3456"],["Bulgaria","bg","359","048 123 456"],["Burkina Faso","bf","226","70 12 34 56"],["Burundi","bi","257","79 56 12 34"],["Cambodia","kh","855","091 234 567"],["Cameroon","cm","237","6 71 23 45 67"],["Canada","ca","1","(506) 234-5678"],["Cape Verde","cv","238","991 12 34"],["Caribbean Netherlands","bq","599","318 1234"],["Cayman Islands","ky","1","(345) 323-1234"],["Central African Republic","cf","236","70 01 23 45"],["Chad","td","235","63 01 23 45"],["Chile","cl","56","(2) 2123 4567"],["China","cn","86","131 2345 6789"],["Christmas Island","cx","61","0412 345 678"],["Cocos Islands","cc","61","0412 345 678"],["Colombia","co","57","321 1234567"],["Comoros","km","269","321 23 45"],["Congo","cd","243","0991 234 567"],["Congo","cg","242","06 123 4567"],["Cook Islands","ck","682","71 234"],["Costa Rica","cr","506","8312 3456"],["CΓ΄te dβIvoire","ci","225","01 23 45 6789"],["Croatia","hr","385","092 123 4567"],["Cuba","cu","53","05 1234567"],["CuraΓ§ao","cw","599","9 518 1234"],["Cyprus","cy","357","96 123456"],["Czech Republic","cz","420","601 123 456"],["Denmark","dk","45","32 12 34 56"],["Djibouti","dj","253","77 83 10 01"],["Dominica","dm","1","(767) 225-1234"],["Dominican Republic","do","1","(809) 234-5678"],["Ecuador","ec","593","099 123 4567"],["Egypt","eg","20","0100 123 4567"],["El Salvador","sv","503","7012 3456"],["Equatorial Guinea","gq","240","222 123 456"],["Eritrea","er","291","07 123 456"],["Estonia","ee","372","5123 4567"],["Eswatini","sz","268","7612 3456"],["Ethiopia","et","251","091 123 4567"],["Falkland Islands","fk","500","51234"],["Faroe Islands","fo","298","211234"],["Fiji","fj","679","701 2345"],["Finland","fi","358","041 2345678"],["France","fr","33","06 12 34 56 78"],["French Guiana","gf","594","0694 20 12 34"],["French Polynesia","pf","689","87 12 34 56"],["Gabon","ga","241","06 03 12 34"],["Gambia","gm","220","301 2345"],["Georgia","ge","995","555 12 34 56"],["Germany","de","49","01512 3456789"],["Ghana","gh","233","023 123 4567"],["Gibraltar","gi","350","57123456"],["Greece","gr","30","691 234 5678"],["Greenland","gl","299","22 12 34"],["Grenada","gd","1","(473) 403-1234"],["Guadeloupe","gp","590","0690 00 12 34"],["Guam","gu","1","(671) 300-1234"],["Guatemala","gt","502","5123 4567"],["Guernsey","gg","44","07781 123456"],["Guinea","gn","224","601 12 34 56"],["Guinea-Bissau","gw","245","955 012 345"],["Guyana","gy","592","609 1234"],["Haiti","ht","509","34 10 1234"],["Honduras","hn","504","9123-4567"],["Hong Kong","hk","852","5123 4567"],["Hungary","hu","36","06 20 123 4567"],["Iceland","is","354","611 1234"],["India","in","91","081234 56789"],["Indonesia","id","62","0812-345-678"],["Iran","ir","98","0912 345 6789"],["Iraq","iq","964","0791 234 5678"],["Ireland","ie","353","085 012 3456"],["Isle of Man","im","44","07924 123456"],["Israel","il","972","050-234-5678"],["Italy","it","39","312 345 6789"],["Jamaica","jm","1","(876) 210-1234"],["Japan","jp","81","090-1234-5678"],["Jersey","je","44","07797 712345"],["Jordan","jo","962","07 9012 3456"],["Kazakhstan","kz","7","8 (771) 000 9998"],["Kenya","ke","254","0712 123456"],["Kiribati","ki","686","72001234"],["Kosovo","xk","383","043 201 234"],["Kuwait","kw","965","500 12345"],["Kyrgyzstan","kg","996","0700 123 456"],["Laos","la","856","020 23 123 456"],["Latvia","lv","371","21 234 567"],["Lebanon","lb","961","71 123 456"],["Lesotho","ls","266","5012 3456"],["Liberia","lr","231","077 012 3456"],["Libya","ly","218","091-2345678"],["Liechtenstein","li","423","660 234 567"],["Lithuania","lt","370","(8-612) 34567"],["Luxembourg","lu","352","628 123 456"],["Macau","mo","853","6612 3456"],["North Macedonia","mk","389","072 345 678"],["Madagascar","mg","261","032 12 345 67"],["Malawi","mw","265","0991 23 45 67"],["Malaysia","my","60","012-345 6789"],["Maldives","mv","960","771-2345"],["Mali","ml","223","65 01 23 45"],["Malta","mt","356","9696 1234"],["Marshall Islands","mh","692","235-1234"],["Martinique","mq","596","0696 20 12 34"],["Mauritania","mr","222","22 12 34 56"],["Mauritius","mu","230","5251 2345"],["Mayotte","yt","262","0639 01 23 45"],["Mexico","mx","52","222 123 4567"],["Micronesia","fm","691","350 1234"],["Moldova","md","373","0621 12 345"],["Monaco","mc","377","06 12 34 56 78"],["Mongolia","mn","976","8812 3456"],["Montenegro","me","382","067 622 901"],["Montserrat","ms","1","(664) 492-3456"],["Morocco","ma","212","0650-123456"],["Mozambique","mz","258","82 123 4567"],["Myanmar","mm","95","09 212 3456"],["Namibia","na","264","081 123 4567"],["Nauru","nr","674","555 1234"],["Nepal","np","977","984-1234567"],["Netherlands","nl","31","06 12345678"],["New Caledonia","nc","687","75.12.34"],["New Zealand","nz","64","021 123 4567"],["Nicaragua","ni","505","8123 4567"],["Niger","ne","227","93 12 34 56"],["Nigeria","ng","234","0802 123 4567"],["Niue","nu","683","888 4012"],["Norfolk Island","nf","672","3 81234"],["North Korea","kp","850","0192 123 4567"],["Northern Mariana Islands","mp","1","(670) 234-5678"],["Norway","no","47","406 12 345"],["Oman","om","968","9212 3456"],["Pakistan","pk","92","0301 2345678"],["Palau","pw","680","620 1234"],["Palestine","ps","970","0599 123 456"],["Panama","pa","507","6123-4567"],["Papua New Guinea","pg","675","7012 3456"],["Paraguay","py","595","0961 456789"],["Peru","pe","51","912 345 678"],["Philippines","ph","63","0905 123 4567"],["Poland","pl","48","512 345 678"],["Portugal","pt","351","912 345 678"],["Puerto Rico","pr","1","(787) 234-5678"],["Qatar","qa","974","3312 3456"],["RΓ©union","re","262","0692 12 34 56"],["Romania","ro","40","0712 034 567"],["Russia","ru","7","8 (912) 345-67-89"],["Rwanda","rw","250","0720 123 456"],["Saint BarthΓ©lemy","bl","590","0690 00 12 34"],["Saint Helena","sh","290","51234"],["Saint Kitts and Nevis","kn","1","(869) 765-2917"],["Saint Lucia","lc","1","(758) 284-5678"],["Saint Martin","mf","590","0690 00 12 34"],["Saint Pierre and Miquelon","pm","508","055 12 34"],["Saint Vincent and the Grenadines","vc","1","(784) 430-1234"],["Samoa","ws","685","72 12345"],["San Marino","sm","378","66 66 12 12"],["SΓ£o TomΓ© and PrΓncipe","st","239","981 2345"],["Saudi Arabia","sa","966","051 234 5678"],["Senegal","sn","221","70 123 45 67"],["Serbia","rs","381","060 1234567"],["Seychelles","sc","248","2 510 123"],["Sierra Leone","sl","232","(025) 123456"],["Singapore","sg","65","8123 4567"],["Sint Maarten","sx","1","(721) 520-5678"],["Slovakia","sk","421","0912 123 456"],["Slovenia","si","386","031 234 567"],["Solomon Islands","sb","677","74 21234"],["Somalia","so","252","7 1123456"],["South Africa","za","27","071 123 4567"],["South Korea","kr","82","010-2000-0000"],["South Sudan","ss","211","0977 123 456"],["Spain","es","34","612 34 56 78"],["Sri Lanka","lk","94","071 234 5678"],["Sudan","sd","249","091 123 1234"],["Suriname","sr","597","741-2345"],["Svalbard and Jan Mayen","sj","47","412 34 567"],["Sweden","se","46","070-123 45 67"],["Switzerland","ch","41","078 123 45 67"],["Syria","sy","963","0944 567 890"],["Taiwan","tw","886","0912 345 678"],["Tajikistan","tj","992","917 12 3456"],["Tanzania","tz","255","0621 234 567"],["Thailand","th","66","081 234 5678"],["Timor-Leste","tl","670","7721 2345"],["Togo","tg","228","90 11 23 45"],["Tokelau","tk","690","7290"],["Tonga","to","676","771 5123"],["Trinidad and Tobago","tt","1","(868) 291-1234"],["Tunisia","tn","216","20 123 456"],["Turkey","tr","90","0501 234 56 78"],["Turkmenistan","tm","993","8 66 123456"],["Turks and Caicos Islands","tc","1","(649) 231-1234"],["Tuvalu","tv","688","90 1234"],["U.S. Virgin Islands","vi","1","(340) 642-1234"],["Uganda","ug","256","0712 345678"],["Ukraine","ua","380","050 123 4567"],["United Arab Emirates","ae","971","050 123 4567"],["United Kingdom","gb","44","07400 123456"],["United States","us","1","(201) 555-0123"],["Uruguay","uy","598","094 231 234"],["Uzbekistan","uz","998","8 91 234 56 78"],["Vanuatu","vu","678","591 2345"],["Vatican City","va","39","312 345 6789"],["Venezuela","ve","58","0412-1234567"],["Vietnam","vn","84","091 234 56 78"],["Wallis and Futuna","wf","681","82 12 34"],["Western Sahara","eh","212","0650-123456"],["Yemen","ye","967","0712 345 678"],["Zambia","zm","260","095 5123456"],["Zimbabwe","zw","263","071 234 5678"],["Γ
land Islands","ax","358","041 2345678"]],this.countries_dropdown=null,this.country_ip=null,this.options=g.getOption("TidyContact"),!1!==this.options&&(null===(e=this.options)||void 0===e?void 0:e.cid))if(this.shouldRun())if(this.loadOptions(),this.hasAddressFields()||this.phoneEnabled()){if(this.createFields(),this.addEventListeners(),g.checkNested(window.EngagingNetworks,"require","_defined","enjs","checkSubmissionFailed")&&!window.EngagingNetworks.require._defined.enjs.checkSubmissionFailed()&&""!=g.getFieldValue(null===(n=null===(t=this.options)||void 0===t?void 0:t.address_fields)||void 0===n?void 0:n.address1)&&(this.logger.log("Address Field is not empty"),this.isDirty=!0),this.phoneEnabled()){this.createPhoneFields(),this.createPhoneMarginVariable(),this.logger.log("Phone Standardization is enabled"),this.countryDropDownEnabled()&&this.renderFlagsDropDown();const e=g.getField(null===(o=null===(i=this.options)||void 0===i?void 0:i.address_fields)||void 0===o?void 0:o.phone);e&&(e.addEventListener("keyup",(e=>{this.handlePhoneInputKeydown(e)})),this.setDefaultPhoneCountry())}}else this.logger.log("No address fields found");else this.logger.log("TidyContact is disabled on this page type")}shouldRun(){return!(this.options&&this.options.page_types&&this.options.page_types.length>0)||this.options.page_types.includes(g.getPageType())}loadOptions(){var e,t,n,i;this.options&&(this.options.address_fields||(this.options.address_fields={address1:"supporter.address1",address2:"supporter.address2",address3:"supporter.address3",city:"supporter.city",region:"supporter.region",postalCode:"supporter.postcode",country:"supporter.country",phone:"supporter.phoneNumber2"}),this.options.address_enable=null===(e=this.options.address_enable)||void 0===e||e,this.options.phone_enable&&(this.options.phone_flags=null===(t=this.options.phone_flags)||void 0===t||t,this.options.phone_country_from_ip=null===(n=this.options.phone_country_from_ip)||void 0===n||n,this.options.phone_preferred_countries=null!==(i=this.options.phone_preferred_countries)&&void 0!==i?i:[]))}createFields(){var e,t,n,i,o,s;if(!this.options||!this.hasAddressFields())return;const r=g.getField("supporter.geo.latitude"),a=g.getField("supporter.geo.longitude");if(r||(g.createHiddenInput("supporter.geo.latitude",""),this.logger.log("Creating Hidden Field: supporter.geo.latitude")),a||(g.createHiddenInput("supporter.geo.longitude",""),this.logger.log("Creating Hidden Field: supporter.geo.longitude")),this.options.record_field){g.getField(this.options.record_field)||(g.createHiddenInput(this.options.record_field,""),this.logger.log("Creating Hidden Field: "+this.options.record_field))}if(this.options.date_field){g.getField(this.options.date_field)||(g.createHiddenInput(this.options.date_field,""),this.logger.log("Creating Hidden Field: "+this.options.date_field))}if(this.options.status_field){g.getField(this.options.status_field)||(g.createHiddenInput(this.options.status_field,""),this.logger.log("Creating Hidden Field: "+this.options.status_field))}g.getField(null===(e=this.options.address_fields)||void 0===e?void 0:e.address2)||(g.createHiddenInput(null===(t=this.options.address_fields)||void 0===t?void 0:t.address2,""),this.logger.log("Creating Hidden Field: "+(null===(n=this.options.address_fields)||void 0===n?void 0:n.address2))),g.getField(null===(i=this.options.address_fields)||void 0===i?void 0:i.address3)||(g.createHiddenInput(null===(o=this.options.address_fields)||void 0===o?void 0:o.address3,""),this.logger.log("Creating Hidden Field: "+(null===(s=this.options.address_fields)||void 0===s?void 0:s.address3)))}createPhoneFields(){if(this.options){if(g.createHiddenInput("tc.phone.country",""),this.logger.log("Creating hidden field: tc.phone.country"),this.options.phone_record_field){g.getField(this.options.phone_record_field)||(g.createHiddenInput(this.options.phone_record_field,""),this.logger.log("Creating hidden field: "+this.options.phone_record_field))}if(this.options.phone_date_field){g.getField(this.options.phone_date_field)||(g.createHiddenInput(this.options.phone_date_field,""),this.logger.log("Creating hidden field: "+this.options.phone_date_field))}if(this.options.phone_status_field){g.getField(this.options.phone_status_field)||(g.createHiddenInput(this.options.phone_status_field,""),this.logger.log("Creating hidden field: "+this.options.phone_status_field))}}}createPhoneMarginVariable(){var e;if(!this.options)return;const t=g.getField(null===(e=this.options.address_fields)||void 0===e?void 0:e.phone);if(t){const e=window.getComputedStyle(t),n=e.marginTop,i=e.marginBottom;document.documentElement.style.setProperty("--tc-phone-margin-top",n),document.documentElement.style.setProperty("--tc-phone-margin-bottom",i)}}addEventListeners(){if(!this.options)return;if(this.options.address_fields)for(const[e,t]of Object.entries(this.options.address_fields)){const e=g.getField(t);e&&e.addEventListener("change",(()=>{this.logger.log("Changed "+e.name,!0),this.isDirty=!0}))}this._form.onSubmit.subscribe(this.callAPI.bind(this));const e=document.getElementsByName("transaction.giveBySelect");e&&e.forEach((e=>{e.addEventListener("change",(()=>{["stripedigitalwallet","paypaltouch"].includes(e.value.toLowerCase())&&(this.logger.log("Clicked Digital Wallet Button"),window.setTimeout((()=>{this.callAPI()}),500))}))}))}checkSum(e){return qe(this,void 0,void 0,(function*(){const t=(new TextEncoder).encode(e),n=yield crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map((e=>("00"+e.toString(16)).slice(-2))).join("")}))}todaysDate(){return(new Date).toLocaleString("en-ZA",{year:"numeric",month:"2-digit",day:"2-digit"}).replace(/\/+/g,"")}countryAllowed(e){var t;return!!this.options&&(!this.options.countries||0===this.options.countries.length||!!(null===(t=this.options.countries)||void 0===t?void 0:t.includes(e.toLowerCase())))}fetchTimeOut(e,t){const n=new AbortController,i=n.signal;t=Object.assign(Object.assign({},t),{signal:i});const o=fetch(e,t);i&&i.addEventListener("abort",(()=>n.abort()));const s=setTimeout((()=>n.abort()),1e3*this.timeout);return o.finally((()=>clearTimeout(s)))}writeError(e){if(!this.options)return;const t=g.getField(this.options.record_field),n=g.getField(this.options.date_field),i=g.getField(this.options.status_field);if(t){let n="";switch(this.httpStatus){case 400:n="Bad Request";break;case 401:n="Unauthorized";break;case 403:n="Forbidden";break;case 404:n="Not Found";break;case 408:n="API Request Timeout";break;case 500:n="Internal Server Error";break;case 503:n="Service Unavailable";break;default:n="Unknown Error"}const i={status:this.httpStatus,error:"string"==typeof e?e:n.toUpperCase()};t.value=JSON.stringify(i)}n&&(n.value=this.todaysDate()),i&&(i.value="ERROR-API")}setFields(e){var t,n,i,o,s;if(!this.options||!this.options.address_enable)return{};let r={};const a=this.getCountry(),l=g.getFieldValue(null===(t=this.options.address_fields)||void 0===t?void 0:t.postalCode),c=null!==(n=this.options.us_zip_divider)&&void 0!==n?n:"+",d=g.getField(null===(i=this.options.address_fields)||void 0===i?void 0:i.address2);if("address2"in e&&!d){g.getFieldValue(null===(o=this.options.address_fields)||void 0===o?void 0:o.address1)==e.address1+" "+e.address2?(delete e.address1,delete e.address2):(e.address1=e.address1+" "+e.address2,delete e.address2)}"postalCode"in e&&l.replace("+",c)===e.postalCode.replace("+",c)&&delete e.postalCode;for(const t in e){const n=this.options.address_fields&&Object.keys(this.options.address_fields).includes(t)?this.options.address_fields[t]:t,i=g.getField(n);if(i){let o=e[t];"postalCode"===t&&["US","USA","United States"].includes(a)&&(o=null!==(s=o.replace("+",c))&&void 0!==s?s:""),r[t]={from:i.value,to:o},this.logger.log(`Set ${i.name} to ${o} (${i.value})`),g.setFieldValue(n,o,!1)}else this.logger.log(`Field ${t} not found`)}return r}hasAddressFields(){var e,t,n,i,o,s;if(!this.options||!this.options.address_enable)return!1;const r=g.getField(null===(e=this.options.address_fields)||void 0===e?void 0:e.address1),a=g.getField(null===(t=this.options.address_fields)||void 0===t?void 0:t.address2),l=g.getField(null===(n=this.options.address_fields)||void 0===n?void 0:n.city),c=g.getField(null===(i=this.options.address_fields)||void 0===i?void 0:i.region),d=g.getField(null===(o=this.options.address_fields)||void 0===o?void 0:o.postalCode),u=g.getField(null===(s=this.options.address_fields)||void 0===s?void 0:s.country);return!!(r||a||l||c||d||u)}canUseAPI(){var e,t,n,i;if(!this.options||!this.hasAddressFields())return!1;const o=!!this.getCountry(),s=!!g.getFieldValue(null===(e=this.options.address_fields)||void 0===e?void 0:e.address1),r=!!g.getFieldValue(null===(t=this.options.address_fields)||void 0===t?void 0:t.city),a=!!g.getFieldValue(null===(n=this.options.address_fields)||void 0===n?void 0:n.region),l=!!g.getFieldValue(null===(i=this.options.address_fields)||void 0===i?void 0:i.postalCode);return o&&s?r&&a||l:(this.logger.log("API cannot be used"),!1)}canUsePhoneAPI(){var e;if(!this.options)return!1;if(this.phoneEnabled()){const t=!!g.getFieldValue(null===(e=this.options.address_fields)||void 0===e?void 0:e.phone),n=!!g.getFieldValue("tc.phone.country");return t&&n}return this.logger.log("Phone API is not enabled"),!1}getCountry(){var e,t;if(!this.options)return"";const n=null!==(e=this.options.country_fallback)&&void 0!==e?e:"";return g.getFieldValue(null===(t=this.options.address_fields)||void 0===t?void 0:t.country)||n.toUpperCase()}getCountryByCode(e){var t;const n=null!==(t=this.countries_list.find((t=>t.includes(e))))&&void 0!==t?t:"";return n?{name:n[0],code:n[1],dialCode:n[2],placeholder:n[3]}:null}phoneEnabled(){return!(!this.options||!this.options.phone_enable)}countryDropDownEnabled(){return!(!this.options||!this.options.phone_flags)}getCountryFromIP(){return qe(this,void 0,void 0,(function*(){return fetch(`https://${window.location.hostname}/cdn-cgi/trace`).then((e=>e.text())).then((e=>{let t=e.replace(/[\r\n]+/g,'","').replace(/\=+/g,'":"');t='{"'+t.slice(0,t.lastIndexOf('","'))+'"}';const n=JSON.parse(t);return this.country_ip=n.loc,this.country_ip}))}))}renderFlagsDropDown(){var e;if(!this.options)return;const t=g.getField(null===(e=this.options.address_fields)||void 0===e?void 0:e.phone);if(!t)return;this.countries_dropdown=document.createElement("div"),this.countries_dropdown.classList.add("tc-flags-container");const n=document.createElement("div");n.classList.add("tc-selected-flag"),n.setAttribute("role","combobox"),n.setAttribute("aria-haspopup","listbox"),n.setAttribute("aria-expanded","false"),n.setAttribute("aria-owns","tc-flags-list"),n.setAttribute("aria-label","Select Country"),n.setAttribute("tabindex","0");const i=document.createElement("div");i.classList.add("tc-flag");const o=document.createElement("div");o.classList.add("tc-flag-arrow"),n.appendChild(i),n.appendChild(o),n.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),n.classList.contains("tc-open")?this.closeCountryDropDown():this.openCountryDropDown()}));const s=document.createElement("ul");if(s.classList.add("tc-country-list"),s.classList.add("tc-hide"),s.setAttribute("id","tc-country-list"),s.setAttribute("role","listbox"),s.setAttribute("aria-label","List of Countries"),s.setAttribute("aria-hidden","true"),this.options.phone_preferred_countries.length>0){const e=[];this.options.phone_preferred_countries.forEach((t=>{const n=this.getCountryByCode(t);n&&e.push(n)})),this.appendCountryItems(s,e,"tc-country-list-item",!0);const t=document.createElement("li");t.classList.add("tc-divider"),t.setAttribute("role","separator"),t.setAttribute("aria-disabled","true"),s.appendChild(t),this.logger.log("Rendering preferred countries",JSON.stringify(e))}const r=[];this.countries_list.forEach((e=>{r.push({name:e[0],code:e[1],dialCode:e[2],placeholder:e[3]})})),this.appendCountryItems(s,r,"tc-country-list-item"),s.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation();const t=e.target.closest("li");if(t.classList.contains("tc-country-list-item")){const e=this.getCountryByCode(t.getAttribute("data-country-code"));e&&this.setPhoneCountry(e)}})),s.addEventListener("mouseover",(e=>{e.preventDefault(),e.stopPropagation();const t=e.target.closest("li.tc-country-list-item");t&&this.highlightCountry(t.getAttribute("data-country-code"))})),this.countries_dropdown.appendChild(n),this.countries_dropdown.appendChild(s),t.parentNode.insertBefore(this.countries_dropdown,t),t.parentNode.classList.add("tc-has-country-flags"),this.countries_dropdown.addEventListener("keydown",(e=>{var t,n;(null===(n=null===(t=this.countries_dropdown)||void 0===t?void 0:t.querySelector(".tc-country-list"))||void 0===n?void 0:n.classList.contains("tc-hide"))&&-1!==["ArrowUp","Up","ArrowDown","Down"," ","Enter"].indexOf(e.key)&&(e.preventDefault(),e.stopPropagation(),this.openCountryDropDown()),"Tab"===e.key&&this.closeCountryDropDown()})),document.addEventListener("keydown",(e=>{var t,n;(null===(n=null===(t=this.countries_dropdown)||void 0===t?void 0:t.querySelector(".tc-country-list"))||void 0===n?void 0:n.classList.contains("tc-hide"))||(e.preventDefault(),"ArrowUp"===e.key||"Up"===e.key||"ArrowDown"===e.key||"Down"===e.key?this.handleUpDownKey(e.key):"Enter"===e.key?this.handleEnterKey():"Escape"===e.key&&this.closeCountryDropDown())})),document.addEventListener("click",(e=>{var t,n;(null===(n=null===(t=this.countries_dropdown)||void 0===t?void 0:t.querySelector(".tc-country-list"))||void 0===n?void 0:n.classList.contains("tc-hide"))||e.target.closest(".tc-country-list")||this.closeCountryDropDown()}))}handleUpDownKey(e){var t;const n=null===(t=this.countries_dropdown)||void 0===t?void 0:t.querySelector(".tc-highlight");if(n){let t="ArrowUp"===e||"Up"===e?n.previousElementSibling:n.nextElementSibling;t&&(t.classList.contains("tc-divider")&&(t="ArrowUp"===e||"Up"===e?t.previousElementSibling:t.nextElementSibling),this.highlightCountry(null==t?void 0:t.getAttribute("data-country-code")))}}handleEnterKey(){var e;const t=null===(e=this.countries_dropdown)||void 0===e?void 0:e.querySelector(".tc-highlight");if(t){const e=this.getCountryByCode(null==t?void 0:t.getAttribute("data-country-code"));this.setPhoneCountry(e)}}handlePhoneInputKeydown(e){const t=e.target.value;if("+"===t.charAt(0)&&t.length>2){const e=this.getCountryByCode(t.substring(1,3));e?this.setPhoneCountry(e):this.setDefaultPhoneCountry()}}openCountryDropDown(){if(!this.countries_dropdown)return;const e=this.countries_dropdown.querySelector(".tc-country-list"),t=this.countries_dropdown.querySelector(".tc-selected-flag");e&&t&&(e.classList.remove("tc-hide"),t.setAttribute("aria-expanded","true"),t.classList.add("tc-open"))}closeCountryDropDown(){var e;if(!this.options)return;if(!this.countries_dropdown)return;const t=this.countries_dropdown.querySelector(".tc-country-list"),n=this.countries_dropdown.querySelector(".tc-selected-flag");t&&n&&(t.classList.add("tc-hide"),n.setAttribute("aria-expanded","false"),n.classList.remove("tc-open"));g.getField(null===(e=this.options.address_fields)||void 0===e?void 0:e.phone).focus()}getFlagImage(e,t){return`\n \n \n \n `}appendCountryItems(e,t,n,i=!1){let o="";for(let e=0;e`,o+=`${this.getFlagImage(s.code,s.name)}
`,o+=`${s.name} `,o+=`+${s.dialCode} `,o+=""}e.insertAdjacentHTML("beforeend",o)}setDefaultPhoneCountry(){var e;if(!this.options)return;if(this.options.phone_country_from_ip)return void this.getCountryFromIP().then((e=>{this.logger.log("Country from IP:",e),this.setPhoneCountry(this.getCountryByCode((null!=e?e:"us").toLowerCase()))})).catch((e=>{this.setPhoneCountry(this.getCountryByCode("us"))}));const t=g.getField(null===(e=this.options.address_fields)||void 0===e?void 0:e.country);if(t){const e=t.options[t.selectedIndex].text,n=this.getCountryByCode(e);if(n)return void this.setPhoneCountry(n);if(this.options.phone_preferred_countries.length>0)return void this.setPhoneCountry(this.getCountryByCode(this.options.phone_preferred_countries[0]))}this.setPhoneCountry(this.getCountryByCode("us"))}setPhoneCountry(e){var t,n,i,o,s,r;if(!this.options||!e)return;const a=g.getField("tc.phone.country");if(a.value===e.code)return;const l=g.getField(null===(t=this.options.address_fields)||void 0===t?void 0:t.phone);if(this.countryDropDownEnabled()){const t=null===(n=this.countries_dropdown)||void 0===n?void 0:n.querySelector(".tc-selected-flag"),a=null===(i=this.countries_dropdown)||void 0===i?void 0:i.querySelector(".tc-flag");t&&a&&(a.innerHTML=this.getFlagImage(e.code,e.name),t.setAttribute("data-country",e.code));const l=null===(o=this.countries_dropdown)||void 0===o?void 0:o.querySelector(".tc-country-list-item[aria-selected='true']");l&&(l.classList.remove("tc-selected"),l.setAttribute("aria-selected","false"));const c=null===(s=this.countries_dropdown)||void 0===s?void 0:s.querySelector(".tc-highlight");c&&c.classList.remove("tc-highlight");const d=null===(r=this.countries_dropdown)||void 0===r?void 0:r.querySelector(`.tc-country-list-item[data-country-code='${e.code}']`);d&&(d.classList.add("tc-selected"),d.setAttribute("aria-selected","true"),d.classList.add("tc-highlight")),(null==t?void 0:t.classList.contains("tc-open"))&&this.closeCountryDropDown()}l.setAttribute("placeholder",e.placeholder),a.value=e.code,this.logger.log(`Setting phone country to ${e.code} - ${e.name}`)}highlightCountry(e){var t,n;if(!e)return;const i=null===(t=this.countries_dropdown)||void 0===t?void 0:t.querySelector(".tc-highlight");i&&i.classList.remove("tc-highlight");const o=null===(n=this.countries_dropdown)||void 0===n?void 0:n.querySelector(".tc-country-list");if(o){const t=o.querySelector(`.tc-country[data-country-code='${e}']`);t&&(t.classList.add("tc-highlight"),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}))}}setPhoneDataFromAPI(e,t){var n;return qe(this,void 0,void 0,(function*(){if(!this.options)return;const i=g.getField(null===(n=this.options.address_fields)||void 0===n?void 0:n.phone),o=g.getField(this.options.phone_record_field),s=g.getField(this.options.phone_date_field),r=g.getField(this.options.phone_status_field);let a={};a.formData={[i.name]:i.value},a.formatted=e.formatted,a.number_type=e.number_type,!0===e.valid?(i.value!==e.formatted.e164&&(a.phone={from:i.value,to:e.formatted.e164},i.value=e.formatted.e164),yield this.checkSum(JSON.stringify(a)).then((e=>{this.logger.log("Phone Checksum",e),a.requestId=t,a.checksum=e})),o&&(a=Object.assign({date:this.todaysDate(),status:"SUCCESS"},a),o.value=JSON.stringify(a)),s&&(s.value=this.todaysDate()),r&&(r.value="SUCCESS")):(yield this.checkSum(JSON.stringify(a)).then((e=>{this.logger.log("Phone Checksum",e),a.requestId=t,a.checksum=e})),o&&(a=Object.assign({date:this.todaysDate(),status:"ERROR"},a),o.value=JSON.stringify(a)),s&&(s.value=this.todaysDate()),r&&(r.value="error"in e?"ERROR: "+e.error:"INVALIDPHONE"))}))}callAPI(){var e,t,n,i,o,s;if(!this.options)return;if(!this.isDirty||this.wasCalled)return;if(!this._form.submit)return void this.logger.log("Form Submission Interrupted by Other Component");const r=g.getField(this.options.record_field),a=g.getField(this.options.date_field),l=g.getField(this.options.status_field),c=g.getField("supporter.geo.latitude"),d=g.getField("supporter.geo.longitude");if(!this.canUseAPI()&&!this.canUsePhoneAPI())return this.logger.log("Not Enough Data to Call API"),a&&(a.value=this.todaysDate()),l&&(l.value="PARTIALADDRESS"),!0;const u=g.getFieldValue(null===(e=this.options.address_fields)||void 0===e?void 0:e.address1),h=g.getFieldValue(null===(t=this.options.address_fields)||void 0===t?void 0:t.address2),p=g.getFieldValue(null===(n=this.options.address_fields)||void 0===n?void 0:n.city),m=g.getFieldValue(null===(i=this.options.address_fields)||void 0===i?void 0:i.region),f=g.getFieldValue(null===(o=this.options.address_fields)||void 0===o?void 0:o.postalCode),b=this.getCountry();if(!this.countryAllowed(b)){if(this.logger.log("Country not allowed: "+b),r){let e={};e=Object.assign({date:this.todaysDate(),status:"DISALLOWED"},e),r.value=JSON.stringify(e)}return a&&(a.value=this.todaysDate()),l&&(l.value="DISALLOWED"),!0}let y={url:window.location.href,cid:this.options.cid};this.canUseAPI()&&(y=Object.assign(y,{address1:u,address2:h,city:p,region:m,postalCode:f,country:b})),this.canUsePhoneAPI()&&(y.phone=g.getFieldValue(null===(s=this.options.address_fields)||void 0===s?void 0:s.phone),y.phoneCountry=g.getFieldValue("tc.phone.country")),this.wasCalled=!0,this.logger.log("FormData",JSON.parse(JSON.stringify(y)));const v=this.fetchTimeOut(this.endpoint,{headers:{"Content-Type":"application/json; charset=utf-8"},method:"POST",body:JSON.stringify(y)}).then((e=>(this.httpStatus=e.status,e.json()))).then((e=>qe(this,void 0,void 0,(function*(){if(this.logger.log("callAPI response",JSON.parse(JSON.stringify(e))),!0===e.valid){let t={};"changed"in e&&(t=this.setFields(e.changed)),t.formData=y,yield this.checkSum(JSON.stringify(t)).then((n=>{this.logger.log("Checksum",n),t.requestId=e.requestId,t.checksum=n})),"latitude"in e&&(c.value=e.latitude,t.latitude=e.latitude),"longitude"in e&&(d.value=e.longitude,t.longitude=e.longitude),r&&(t=Object.assign({date:this.todaysDate(),status:"SUCCESS"},t),r.value=JSON.stringify(t)),a&&(a.value=this.todaysDate()),l&&(l.value="SUCCESS")}else{let t={};t.formData=y,yield this.checkSum(JSON.stringify(t)).then((n=>{this.logger.log("Checksum",n),t.requestId=e.requestId,t.checksum=n})),r&&(t=Object.assign({date:this.todaysDate(),status:"ERROR"},t),r.value=JSON.stringify(t)),a&&(a.value=this.todaysDate()),l&&(l.value="error"in e?"ERROR: "+e.error:"INVALIDADDRESS")}this.phoneEnabled()&&"phone"in e&&(yield this.setPhoneDataFromAPI(e.phone,e.requestId))})))).catch((e=>{e.toString().includes("AbortError")&&(this.logger.log("Fetch aborted"),this.httpStatus=408),this.writeError(e)}));return this._form.submitPromise=v,v}}class xe{constructor(){this.logger=new ye("LiveCurrency","#1901b1","#feb47a","π²"),this.elementsFound=!1,this.isUpdating=!1,this._amount=p.getInstance(),this._frequency=m.getInstance(),this._fees=f.getInstance(),this.searchElements(),this.shouldRun()&&(g.setBodyData("live-currency","active"),this.updateCurrency(),this.addEventListeners(),document.querySelectorAll(".en__field--donationAmt .en__field__element--radio .en__field__item").forEach((e=>{e.setAttribute("data-engrid-currency-symbol-updated","true")})))}searchElements(){const e=document.querySelectorAll("\n .en__component--copyblock,\n .en__component--codeblock,\n .en__field label,\n .en__submit\n ");if(e.length>0){this.elementsFound=!0;const t=g.getCurrencySymbol(),n=g.getCurrencyCode(),i=`${t} `,o=`${n} `;e.forEach((e=>{if(!(e instanceof HTMLElement&&e.innerHTML.startsWith("