@4site/engrid-scripts 0.24.4 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts +1 -0
- package/dist/app.js +12 -1
- package/dist/auto-country-select.js +6 -1
- package/dist/data-layer.d.ts +1 -0
- package/dist/data-layer.js +29 -2
- package/dist/digital-wallets.d.ts +5 -0
- package/dist/digital-wallets.js +42 -1
- package/dist/events/en-form.d.ts +28 -1
- package/dist/events/en-form.js +35 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/interfaces/options.d.ts +6 -0
- package/dist/interfaces/options.js +3 -0
- package/dist/optin-ladder.d.ts +2 -1
- package/dist/optin-ladder.js +43 -20
- package/dist/sticky-nsg.d.ts +10 -0
- package/dist/sticky-nsg.js +109 -0
- package/dist/sticky-prepopulation.d.ts +17 -0
- package/dist/sticky-prepopulation.js +214 -0
- package/dist/swap-amounts.js +6 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/app.d.ts
CHANGED
package/dist/app.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DonationAmount, DonationFrequency, EnForm, ProcessingFees, Country, } from "./events";
|
|
2
|
-
import { AmountLabel, Loader, ProgressBar, UpsellLightbox, ENGrid, OptionsDefaults, setRecurrFreq, PageBackground, MediaAttribution, ApplePay, A11y, CapitalizeFields, Ecard, ClickToExpand, Advocacy, DataAttributes, LiveVariables, iFrame, InputPlaceholders, InputHasValueAndFocus, ShowHideRadioCheckboxes, AutoCountrySelect, SkipToMainContentLink, SrcDefer, NeverBounce, AutoYear, Autocomplete, RememberMe, TranslateFields, ShowIfAmount, EngridLogger, OtherAmount, MinMaxAmount, Ticker, DataReplace, DataHide, AddNameToMessage, ExpandRegionName, AppVersion, UrlToForm, RequiredIfVisible, TidyContact, DataLayer, LiveCurrency, Autosubmit, EventTickets, SwapAmounts, DebugPanel, DebugHiddenFields, FreshAddress, BrandingHtml, CountryDisable, PremiumGift, DigitalWallets, MobileCTA, LiveFrequency, UniversalOptIn, StripeFinancialConnections, GiveBySelect, UrlParamsToBodyAttrs, ExitIntentLightbox, SupporterHub, FastFormFill, SetAttr, ShowIfPresent, ENValidators, CustomCurrency, VGS, PostalCodeValidator, CountryRedirect, WelcomeBack, EcardToTarget, UsOnlyForm, ThankYouPageConditionalContent, EmbeddedEcard, CheckboxLabel, UpsellCheckbox, PostDonationEmbed, FrequencyUpsell, CustomPremium, PreferredPaymentMethod, } from ".";
|
|
2
|
+
import { AmountLabel, Loader, ProgressBar, UpsellLightbox, ENGrid, OptionsDefaults, setRecurrFreq, PageBackground, MediaAttribution, ApplePay, A11y, CapitalizeFields, Ecard, ClickToExpand, Advocacy, DataAttributes, LiveVariables, iFrame, InputPlaceholders, InputHasValueAndFocus, ShowHideRadioCheckboxes, AutoCountrySelect, SkipToMainContentLink, SrcDefer, NeverBounce, AutoYear, Autocomplete, RememberMe, TranslateFields, ShowIfAmount, EngridLogger, OtherAmount, MinMaxAmount, Ticker, DataReplace, DataHide, AddNameToMessage, ExpandRegionName, AppVersion, UrlToForm, RequiredIfVisible, TidyContact, DataLayer, LiveCurrency, Autosubmit, EventTickets, SwapAmounts, DebugPanel, DebugHiddenFields, FreshAddress, BrandingHtml, CountryDisable, PremiumGift, DigitalWallets, MobileCTA, LiveFrequency, UniversalOptIn, StripeFinancialConnections, GiveBySelect, UrlParamsToBodyAttrs, ExitIntentLightbox, SupporterHub, FastFormFill, SetAttr, ShowIfPresent, ENValidators, CustomCurrency, VGS, PostalCodeValidator, CountryRedirect, WelcomeBack, EcardToTarget, UsOnlyForm, ThankYouPageConditionalContent, EmbeddedEcard, CheckboxLabel, UpsellCheckbox, PostDonationEmbed, FrequencyUpsell, CustomPremium, StickyNSG, StickyPrepopulation, PreferredPaymentMethod, } from ".";
|
|
3
3
|
export class App extends ENGrid {
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super();
|
|
@@ -94,6 +94,7 @@ export class App extends ENGrid {
|
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
// Client onSubmit and onError functions
|
|
97
|
+
this._form.onIntentSubmit.subscribe(() => this.onIntentSubmit());
|
|
97
98
|
this._form.onSubmit.subscribe(() => this.onSubmit());
|
|
98
99
|
this._form.onError.subscribe(() => this.onError());
|
|
99
100
|
this._form.onValidate.subscribe(() => this.onValidate());
|
|
@@ -111,6 +112,7 @@ export class App extends ENGrid {
|
|
|
111
112
|
window.enOnSubmit = () => {
|
|
112
113
|
this._form.submit = true;
|
|
113
114
|
this._form.submitPromise = false;
|
|
115
|
+
this._form.dispatchIntentSubmit();
|
|
114
116
|
this._form.dispatchSubmit();
|
|
115
117
|
ENGrid.watchForError(ENGrid.enableSubmit);
|
|
116
118
|
if (!this._form.submit)
|
|
@@ -160,6 +162,8 @@ export class App extends ENGrid {
|
|
|
160
162
|
new Autosubmit();
|
|
161
163
|
// Adjust display of event tickets.
|
|
162
164
|
new EventTickets();
|
|
165
|
+
// StickyNSG - Must load before SwapAmounts
|
|
166
|
+
new StickyNSG();
|
|
163
167
|
// Swap Amounts
|
|
164
168
|
new SwapAmounts();
|
|
165
169
|
// On the end of the script, after all subscribers defined, let's load the current frequency
|
|
@@ -279,6 +283,7 @@ export class App extends ENGrid {
|
|
|
279
283
|
new CheckboxLabel();
|
|
280
284
|
new PostDonationEmbed();
|
|
281
285
|
new FrequencyUpsell();
|
|
286
|
+
new StickyPrepopulation();
|
|
282
287
|
//Debug panel
|
|
283
288
|
let showDebugPanel = this.options.Debug;
|
|
284
289
|
try {
|
|
@@ -328,6 +333,12 @@ export class App extends ENGrid {
|
|
|
328
333
|
this.options.onValidate();
|
|
329
334
|
}
|
|
330
335
|
}
|
|
336
|
+
onIntentSubmit() {
|
|
337
|
+
if (this.options.onIntentSubmit) {
|
|
338
|
+
this.logger.log("Client onIntentSubmit Triggered");
|
|
339
|
+
this.options.onIntentSubmit();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
331
342
|
onSubmit() {
|
|
332
343
|
if (this.options.onSubmit) {
|
|
333
344
|
this.logger.log("Client onSubmit Triggered");
|
|
@@ -16,10 +16,15 @@ export class AutoCountrySelect {
|
|
|
16
16
|
ENGrid.getUrlParameter("supporter.region") ||
|
|
17
17
|
(ENGrid.getUrlParameter("ea.url.id") &&
|
|
18
18
|
!ENGrid.getUrlParameter("forwarded"));
|
|
19
|
+
// If fast form is active, then personal details have already been filled somehow and we should not override the country selection
|
|
20
|
+
// The client is also likely using WelcomeBack.
|
|
21
|
+
const fastFormActive = ENGrid.getBodyData("hide-fast-address-details") ||
|
|
22
|
+
ENGrid.getBodyData("hide-fast-personal-details");
|
|
19
23
|
if (!engridAutofill &&
|
|
20
24
|
!submissionFailed &&
|
|
21
25
|
hasIntlSupport &&
|
|
22
|
-
!locationDataInUrl
|
|
26
|
+
!locationDataInUrl &&
|
|
27
|
+
!fastFormActive) {
|
|
23
28
|
fetch(`https://${window.location.hostname}/cdn-cgi/trace`)
|
|
24
29
|
.then((res) => res.text())
|
|
25
30
|
.then((t) => {
|
package/dist/data-layer.d.ts
CHANGED
package/dist/data-layer.js
CHANGED
|
@@ -24,6 +24,19 @@ export class DataLayer {
|
|
|
24
24
|
this._form = EnForm.getInstance();
|
|
25
25
|
this.encoder = new TextEncoder();
|
|
26
26
|
this.endOfGiftProcessStorageKey = "ENGRID_END_OF_GIFT_PROCESS_EVENTS";
|
|
27
|
+
// pageJson entries related to the gift process
|
|
28
|
+
this.giftFields = [
|
|
29
|
+
"amount",
|
|
30
|
+
"currency",
|
|
31
|
+
"donationLogId",
|
|
32
|
+
"feeCover",
|
|
33
|
+
"giftProcess",
|
|
34
|
+
"paymentType",
|
|
35
|
+
"receiptNumber",
|
|
36
|
+
"recurring",
|
|
37
|
+
"transactionId",
|
|
38
|
+
"transactionType",
|
|
39
|
+
];
|
|
27
40
|
this.excludedFields = [
|
|
28
41
|
// Credit Card
|
|
29
42
|
"transaction.ccnumber",
|
|
@@ -102,13 +115,27 @@ export class DataLayer {
|
|
|
102
115
|
onLoad() {
|
|
103
116
|
// Collect all data layer variables to push at once
|
|
104
117
|
const dataLayerData = {};
|
|
118
|
+
const suppressEcardData = ENGrid.getPageType() === "ECARD" &&
|
|
119
|
+
ENGrid.getOption("SuppressPurchaseEcard");
|
|
105
120
|
if (ENGrid.getGiftProcess()) {
|
|
106
|
-
|
|
107
|
-
this
|
|
121
|
+
// EN will chain together gift process data on the page json when redirecting from a completed donation to an ecard.
|
|
122
|
+
// 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
|
|
123
|
+
// firing for both the donation and the ecard on the same page.
|
|
124
|
+
if (suppressEcardData) {
|
|
125
|
+
this.logger.log("⛔ Gift process was detected BUT suppressing EN_SUCCESSFUL_DONATION event due to SuppressPurchaseEcard option enabled");
|
|
126
|
+
window.sessionStorage.removeItem(this.endOfGiftProcessStorageKey);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.logger.log("EN_SUCCESSFUL_DONATION");
|
|
130
|
+
this.addEndOfGiftProcessEventsToDataLayer();
|
|
131
|
+
}
|
|
108
132
|
}
|
|
109
133
|
if (window.pageJson) {
|
|
110
134
|
const pageJson = window.pageJson;
|
|
111
135
|
for (const property in pageJson) {
|
|
136
|
+
if (suppressEcardData && this.giftFields.includes(property)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
112
139
|
const key = `EN_PAGEJSON_${property.toUpperCase()}`;
|
|
113
140
|
const value = pageJson[property];
|
|
114
141
|
dataLayerData[key] = this.transformJSON(value);
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
export declare class DigitalWallets {
|
|
2
|
+
private logger;
|
|
3
|
+
private _form;
|
|
2
4
|
constructor();
|
|
3
5
|
private addStripeDigitalWallets;
|
|
4
6
|
private addPaypalTouchDigitalWallets;
|
|
5
7
|
private addDAF;
|
|
6
8
|
private addOptionToPaymentTypeField;
|
|
7
9
|
private checkForWalletsBeingAdded;
|
|
10
|
+
private addPaypalOneTouchListener;
|
|
11
|
+
private addStripeDigitalWalletListener;
|
|
12
|
+
private addDAFListener;
|
|
8
13
|
}
|
package/dist/digital-wallets.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ENGrid } from "./engrid";
|
|
2
|
+
import { EnForm } from "./events";
|
|
3
|
+
import { EngridLogger } from "./logger";
|
|
2
4
|
export class DigitalWallets {
|
|
3
5
|
constructor() {
|
|
6
|
+
this.logger = new EngridLogger("DigitalWallets", "#fff", "#333", "👛");
|
|
7
|
+
this._form = EnForm.getInstance();
|
|
4
8
|
//digital wallets not enabled.
|
|
5
9
|
if (!document.getElementById("en__digitalWallet")) {
|
|
6
10
|
ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "false");
|
|
@@ -9,6 +13,7 @@ export class DigitalWallets {
|
|
|
9
13
|
ENGrid.setBodyData("payment-type-option-paypal-one-touch", "false");
|
|
10
14
|
ENGrid.setBodyData("payment-type-option-venmo", "false");
|
|
11
15
|
ENGrid.setBodyData("payment-type-option-daf", "false");
|
|
16
|
+
this.logger.log("No digital wallet container found, skipping digital wallet setup.");
|
|
12
17
|
return;
|
|
13
18
|
}
|
|
14
19
|
// Add giveBySelect classes to the separate wallet containers
|
|
@@ -86,6 +91,7 @@ export class DigitalWallets {
|
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
93
|
addStripeDigitalWallets() {
|
|
94
|
+
this.logger.log("Stripe Digital Wallets detected");
|
|
89
95
|
this.addOptionToPaymentTypeField("stripedigitalwallet", "GooglePay / ApplePay");
|
|
90
96
|
// ENGrid.setBodyData(
|
|
91
97
|
// "payment-type-option-apple-pay",
|
|
@@ -99,15 +105,26 @@ export class DigitalWallets {
|
|
|
99
105
|
ENGrid.setBodyData("payment-type-option-apple-pay", "true");
|
|
100
106
|
ENGrid.setBodyData("payment-type-option-google-pay", "true");
|
|
101
107
|
ENGrid.setBodyData("payment-type-option-stripedigitalwallet", "true");
|
|
108
|
+
this.addStripeDigitalWalletListener()
|
|
109
|
+
? this.logger.log("Stripe Digital Wallet listener added successfully")
|
|
110
|
+
: this.logger.log("Failed to add Stripe Digital Wallet listener");
|
|
102
111
|
}
|
|
103
112
|
addPaypalTouchDigitalWallets() {
|
|
113
|
+
this.logger.log("Paypal Touch Digital Wallets detected");
|
|
104
114
|
this.addOptionToPaymentTypeField("paypaltouch", "Paypal / Venmo");
|
|
105
115
|
ENGrid.setBodyData("payment-type-option-paypal-one-touch", "true");
|
|
106
116
|
ENGrid.setBodyData("payment-type-option-venmo", "true");
|
|
117
|
+
this.addPaypalOneTouchListener()
|
|
118
|
+
? this.logger.log("Paypal Touch listener added successfully")
|
|
119
|
+
: this.logger.log("Failed to add Paypal Touch listener");
|
|
107
120
|
}
|
|
108
121
|
addDAF() {
|
|
122
|
+
this.logger.log("DAF Digital Wallet detected");
|
|
109
123
|
this.addOptionToPaymentTypeField("daf", "Donor Advised Fund");
|
|
110
124
|
ENGrid.setBodyData("payment-type-option-daf", "true");
|
|
125
|
+
this.addDAFListener()
|
|
126
|
+
? this.logger.log("DAF listener added successfully")
|
|
127
|
+
: this.logger.log("Failed to add DAF listener");
|
|
111
128
|
}
|
|
112
129
|
addOptionToPaymentTypeField(value, label) {
|
|
113
130
|
const paymentTypeField = document.querySelector('[name="transaction.paymenttype"]');
|
|
@@ -144,12 +161,36 @@ export class DigitalWallets {
|
|
|
144
161
|
else if (walletType === "daf") {
|
|
145
162
|
this.addDAF();
|
|
146
163
|
}
|
|
147
|
-
//Disconnect observer to prevent multiple additions
|
|
164
|
+
//Disconnect observer and break loop to prevent multiple additions
|
|
148
165
|
observer.disconnect();
|
|
166
|
+
break;
|
|
149
167
|
}
|
|
150
168
|
}
|
|
151
169
|
};
|
|
152
170
|
const observer = new MutationObserver(callback);
|
|
153
171
|
observer.observe(node, { childList: true, subtree: true });
|
|
154
172
|
}
|
|
173
|
+
addPaypalOneTouchListener() {
|
|
174
|
+
var _a, _b, _c, _d, _e;
|
|
175
|
+
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;
|
|
176
|
+
if (!((_e = paypalTouch === null || paypalTouch === void 0 ? void 0 : paypalTouch.library) === null || _e === void 0 ? void 0 : _e.Buttons)) {
|
|
177
|
+
this.logger.log("Paypal Touch library not found, cannot add listener");
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
const buttons = paypalTouch.library.Buttons.bind(paypalTouch.library);
|
|
181
|
+
paypalTouch.library.Buttons = (o) => buttons(Object.assign(Object.assign({}, o), { onClick: (d, a) => (this._form.dispatchIntentSubmit(),
|
|
182
|
+
o.onClick && o.onClick(d, a)) }));
|
|
183
|
+
paypalTouch.unloadButton && paypalTouch.unloadButton();
|
|
184
|
+
paypalTouch.loadButton && paypalTouch.loadButton();
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
addStripeDigitalWalletListener() {
|
|
188
|
+
var _a, _b, _c, _d, _e, _f;
|
|
189
|
+
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)));
|
|
190
|
+
}
|
|
191
|
+
addDAFListener() {
|
|
192
|
+
const chariotButton = document.getElementById("chariot-button");
|
|
193
|
+
chariotButton === null || chariotButton === void 0 ? void 0 : chariotButton.addEventListener("click", this._form.dispatchIntentSubmit.bind(this._form));
|
|
194
|
+
return !!chariotButton;
|
|
195
|
+
}
|
|
155
196
|
}
|
package/dist/events/en-form.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare class EnForm {
|
|
2
2
|
private logger;
|
|
3
|
+
private _onIntentSubmit;
|
|
3
4
|
private _onSubmit;
|
|
4
5
|
private _onValidate;
|
|
5
6
|
private _onError;
|
|
@@ -10,11 +11,37 @@ export declare class EnForm {
|
|
|
10
11
|
private static instance;
|
|
11
12
|
private constructor();
|
|
12
13
|
static getInstance(): EnForm;
|
|
14
|
+
dispatchIntentSubmit(): void;
|
|
13
15
|
dispatchSubmit(): void;
|
|
14
16
|
dispatchValidate(): void;
|
|
15
17
|
dispatchError(): void;
|
|
16
18
|
submitForm(): void;
|
|
19
|
+
/**
|
|
20
|
+
* onIntentSubmit is dispatched when a submit button is clicked,
|
|
21
|
+
* or a digital wallet submission is initiated,
|
|
22
|
+
* but before server-side validation or the actual submit event.
|
|
23
|
+
* This allows you to run code at the moment the user intends to submit,
|
|
24
|
+
* such as triggering data formatting, analytics events, or other pre-submit actions.
|
|
25
|
+
* Actions that rely on fully processed form data or validation results should use the onSubmit event instead.
|
|
26
|
+
* Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
|
|
27
|
+
*/
|
|
28
|
+
get onIntentSubmit(): import("strongly-typed-events").ISignal;
|
|
29
|
+
/**
|
|
30
|
+
* onSubmit is dispatched when the form is submitted, after validation has passed.
|
|
31
|
+
* 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.
|
|
32
|
+
* This event uses window.enOnSubmit, which is called by Engaging Networks' JavaScript when the form is submitted.
|
|
33
|
+
* 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.
|
|
34
|
+
* Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
|
|
35
|
+
*/
|
|
17
36
|
get onSubmit(): import("strongly-typed-events").ISignal;
|
|
18
|
-
|
|
37
|
+
/**
|
|
38
|
+
* onValidate is dispatched using window.enOnValidate, which is called by Engaging Networks' JavaScript
|
|
39
|
+
* when the form is being validated, before submission. This only occurs after ENgrid's client-side validation has passed, but before server-side validation.
|
|
40
|
+
*/
|
|
19
41
|
get onValidate(): import("strongly-typed-events").ISignal;
|
|
42
|
+
/**
|
|
43
|
+
* onError is dispatched using window.enOnError, which is called by Engaging Networks' JavaScript when a server-side validation error occurs on form submission.
|
|
44
|
+
* This allows you to listen for validation errors and respond accordingly, such as displaying custom error messages or triggering analytics events.
|
|
45
|
+
*/
|
|
46
|
+
get onError(): import("strongly-typed-events").ISignal;
|
|
20
47
|
}
|
package/dist/events/en-form.js
CHANGED
|
@@ -3,6 +3,7 @@ import { EngridLogger } from "..";
|
|
|
3
3
|
export class EnForm {
|
|
4
4
|
constructor() {
|
|
5
5
|
this.logger = new EngridLogger("EnForm");
|
|
6
|
+
this._onIntentSubmit = new SignalDispatcher();
|
|
6
7
|
this._onSubmit = new SignalDispatcher();
|
|
7
8
|
this._onValidate = new SignalDispatcher();
|
|
8
9
|
this._onError = new SignalDispatcher();
|
|
@@ -17,6 +18,10 @@ export class EnForm {
|
|
|
17
18
|
}
|
|
18
19
|
return EnForm.instance;
|
|
19
20
|
}
|
|
21
|
+
dispatchIntentSubmit() {
|
|
22
|
+
this._onIntentSubmit.dispatch();
|
|
23
|
+
this.logger.log("dispatchIntentSubmit");
|
|
24
|
+
}
|
|
20
25
|
dispatchSubmit() {
|
|
21
26
|
this._onSubmit.dispatch();
|
|
22
27
|
this.logger.log("dispatchSubmit");
|
|
@@ -40,13 +45,40 @@ export class EnForm {
|
|
|
40
45
|
this.logger.log("submitForm");
|
|
41
46
|
}
|
|
42
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* onIntentSubmit is dispatched when a submit button is clicked,
|
|
50
|
+
* or a digital wallet submission is initiated,
|
|
51
|
+
* but before server-side validation or the actual submit event.
|
|
52
|
+
* This allows you to run code at the moment the user intends to submit,
|
|
53
|
+
* such as triggering data formatting, analytics events, or other pre-submit actions.
|
|
54
|
+
* Actions that rely on fully processed form data or validation results should use the onSubmit event instead.
|
|
55
|
+
* Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
|
|
56
|
+
*/
|
|
57
|
+
get onIntentSubmit() {
|
|
58
|
+
return this._onIntentSubmit.asEvent();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* onSubmit is dispatched when the form is submitted, after validation has passed.
|
|
62
|
+
* 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.
|
|
63
|
+
* This event uses window.enOnSubmit, which is called by Engaging Networks' JavaScript when the form is submitted.
|
|
64
|
+
* 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.
|
|
65
|
+
* Note: onSubmit will also dispatch onIntentSubmit, so do not repeat actions in both events.
|
|
66
|
+
*/
|
|
43
67
|
get onSubmit() {
|
|
44
68
|
return this._onSubmit.asEvent();
|
|
45
69
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
70
|
+
/**
|
|
71
|
+
* onValidate is dispatched using window.enOnValidate, which is called by Engaging Networks' JavaScript
|
|
72
|
+
* when the form is being validated, before submission. This only occurs after ENgrid's client-side validation has passed, but before server-side validation.
|
|
73
|
+
*/
|
|
49
74
|
get onValidate() {
|
|
50
75
|
return this._onValidate.asEvent();
|
|
51
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* onError is dispatched using window.enOnError, which is called by Engaging Networks' JavaScript when a server-side validation error occurs on form submission.
|
|
79
|
+
* This allows you to listen for validation errors and respond accordingly, such as displaying custom error messages or triggering analytics events.
|
|
80
|
+
*/
|
|
81
|
+
get onError() {
|
|
82
|
+
return this._onError.asEvent();
|
|
83
|
+
}
|
|
52
84
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,8 @@ export * from "./optin-ladder";
|
|
|
86
86
|
export * from "./post-donation-embed";
|
|
87
87
|
export * from "./frequency-upsell-modal";
|
|
88
88
|
export * from "./frequency-upsell";
|
|
89
|
+
export * from "./sticky-nsg";
|
|
90
|
+
export * from "./sticky-prepopulation";
|
|
89
91
|
export * from "./preferred-payment-method";
|
|
90
92
|
export * from "./events";
|
|
91
93
|
export * from "./version";
|
package/dist/index.js
CHANGED
|
@@ -86,6 +86,8 @@ export * from "./optin-ladder";
|
|
|
86
86
|
export * from "./post-donation-embed";
|
|
87
87
|
export * from "./frequency-upsell-modal";
|
|
88
88
|
export * from "./frequency-upsell";
|
|
89
|
+
export * from "./sticky-nsg";
|
|
90
|
+
export * from "./sticky-prepopulation";
|
|
89
91
|
export * from "./preferred-payment-method";
|
|
90
92
|
// Events
|
|
91
93
|
export * from "./events";
|
|
@@ -18,6 +18,7 @@ export interface Options {
|
|
|
18
18
|
UseAmountValidatorFromEN?: boolean;
|
|
19
19
|
SkipToMainContentLink?: boolean;
|
|
20
20
|
SrcDefer?: boolean;
|
|
21
|
+
SuppressPurchaseEcard?: boolean;
|
|
21
22
|
NeverBounceAPI?: string | null;
|
|
22
23
|
NeverBounceDateField?: string | null;
|
|
23
24
|
NeverBounceDateFormat?: string;
|
|
@@ -50,6 +51,10 @@ export interface Options {
|
|
|
50
51
|
fieldClearSelectorTargetLocation?: string;
|
|
51
52
|
checked?: boolean;
|
|
52
53
|
};
|
|
54
|
+
StickyNSG?: boolean;
|
|
55
|
+
StickyPrepopulation?: false | {
|
|
56
|
+
fields: string[];
|
|
57
|
+
};
|
|
53
58
|
TidyContact?: false | {
|
|
54
59
|
cid?: string;
|
|
55
60
|
page_types?: ("DONATION" | "ECARD" | "SURVEY" | "EMAILTOTARGET" | "ADVOCACY" | "SUBSCRIBEFORM" | "EVENT" | "SUPPORTERHUB" | "UNSUBSCRIBE" | "TWEETPAGE" | "UNKNOWN")[];
|
|
@@ -173,6 +178,7 @@ export interface Options {
|
|
|
173
178
|
};
|
|
174
179
|
onLoad?: () => void;
|
|
175
180
|
onResize?: () => void;
|
|
181
|
+
onIntentSubmit?: () => void;
|
|
176
182
|
onSubmit?: () => void;
|
|
177
183
|
onError?: () => void;
|
|
178
184
|
onValidate?: () => void;
|
|
@@ -17,6 +17,7 @@ export const OptionsDefaults = {
|
|
|
17
17
|
UseAmountValidatorFromEN: false,
|
|
18
18
|
SkipToMainContentLink: true,
|
|
19
19
|
SrcDefer: true,
|
|
20
|
+
SuppressPurchaseEcard: false,
|
|
20
21
|
NeverBounceAPI: null,
|
|
21
22
|
NeverBounceDateField: null,
|
|
22
23
|
NeverBounceStatusField: null,
|
|
@@ -41,6 +42,8 @@ export const OptionsDefaults = {
|
|
|
41
42
|
CountryRedirect: false,
|
|
42
43
|
WelcomeBack: false,
|
|
43
44
|
OptInLadder: false,
|
|
45
|
+
StickyNSG: false,
|
|
46
|
+
StickyPrepopulation: false,
|
|
44
47
|
PreferredPaymentMethod: false,
|
|
45
48
|
PageLayouts: [
|
|
46
49
|
"leftleft1col",
|
package/dist/optin-ladder.d.ts
CHANGED
|
@@ -7,9 +7,10 @@ export declare class OptInLadder {
|
|
|
7
7
|
private runAsChildThankYou;
|
|
8
8
|
private inIframe;
|
|
9
9
|
private saveStepToSessionStorage;
|
|
10
|
-
private getFirstPageUrl;
|
|
11
10
|
private saveOptInsToSessionStorage;
|
|
12
11
|
private isEmbeddedThankYouPage;
|
|
12
|
+
private getPageUrl;
|
|
13
|
+
private getFirstPageUrl;
|
|
13
14
|
private hidePage;
|
|
14
15
|
private clearSessionStorage;
|
|
15
16
|
}
|
package/dist/optin-ladder.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Docs: https://engrid.4sitestudios.com/component/optin-ladder
|
|
3
|
+
* This component is responsible for showing a ladder of checkboxes, one at a time, to the user.
|
|
4
|
+
* 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.
|
|
5
|
+
* 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.
|
|
6
|
+
* 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.
|
|
7
|
+
* 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.
|
|
8
|
+
*/
|
|
6
9
|
import { EngridLogger, ENGrid, EnForm } from ".";
|
|
7
10
|
export class OptInLadder {
|
|
8
11
|
constructor() {
|
|
@@ -95,7 +98,7 @@ export class OptInLadder {
|
|
|
95
98
|
if (!emailField || !emailField.value) {
|
|
96
99
|
this.logger.log("Email field is empty");
|
|
97
100
|
// Since this is a OptInLadder page with no e-mail address, hide the page
|
|
98
|
-
this.hidePage();
|
|
101
|
+
this.hidePage(true);
|
|
99
102
|
return;
|
|
100
103
|
}
|
|
101
104
|
const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}");
|
|
@@ -179,6 +182,12 @@ export class OptInLadder {
|
|
|
179
182
|
return;
|
|
180
183
|
}
|
|
181
184
|
const hasOptInLadderStop = sessionStorage.getItem("engrid.optin-ladder-stop");
|
|
185
|
+
const hasOptInLadderPersistStop = sessionStorage.getItem("engrid.optin-ladder-persist-stop");
|
|
186
|
+
if (hasOptInLadderPersistStop) {
|
|
187
|
+
this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page");
|
|
188
|
+
sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
182
191
|
if (hasOptInLadderStop) {
|
|
183
192
|
this.logger.log("OptInLadder has been stopped");
|
|
184
193
|
return;
|
|
@@ -186,9 +195,14 @@ export class OptInLadder {
|
|
|
186
195
|
const sessionStorageOptInLadder = JSON.parse(sessionStorage.getItem("engrid.optin-ladder") || "{}");
|
|
187
196
|
const currentStep = sessionStorageOptInLadder.step || 0;
|
|
188
197
|
const totalSteps = sessionStorageOptInLadder.totalSteps || 0;
|
|
189
|
-
if (
|
|
190
|
-
this.logger.log(
|
|
198
|
+
if (totalSteps === 0) {
|
|
199
|
+
this.logger.log("No total steps found in sessionStorage");
|
|
191
200
|
this.hidePage();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
else if (currentStep <= totalSteps) {
|
|
204
|
+
this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`);
|
|
205
|
+
this.hidePage(true);
|
|
192
206
|
// Redirect to the first page
|
|
193
207
|
window.location.href = this.getFirstPageUrl();
|
|
194
208
|
return;
|
|
@@ -211,14 +225,6 @@ export class OptInLadder {
|
|
|
211
225
|
sessionStorage.setItem("engrid.optin-ladder", JSON.stringify({ step, totalSteps }));
|
|
212
226
|
this.logger.log(`Saved step ${step} of ${totalSteps} to sessionStorage`);
|
|
213
227
|
}
|
|
214
|
-
getFirstPageUrl() {
|
|
215
|
-
// Get the current URL and replace the last path with 1?chain
|
|
216
|
-
const url = new URL(window.location.href);
|
|
217
|
-
const path = url.pathname.split("/");
|
|
218
|
-
path.pop();
|
|
219
|
-
path.push("1");
|
|
220
|
-
return url.origin + path.join("/") + "?chain";
|
|
221
|
-
}
|
|
222
228
|
saveOptInsToSessionStorage(type = "parent") {
|
|
223
229
|
// Grab all the checkboxes with the name starting with "supporter.questions"
|
|
224
230
|
const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]');
|
|
@@ -248,15 +254,32 @@ export class OptInLadder {
|
|
|
248
254
|
isEmbeddedThankYouPage() {
|
|
249
255
|
return ENGrid.getBodyData("embedded") === "thank-you-page-donation";
|
|
250
256
|
}
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
257
|
+
getPageUrl(page, chain = false) {
|
|
258
|
+
const url = new URL(window.location.href);
|
|
259
|
+
const path = url.pathname.split("/");
|
|
260
|
+
path[path.length - 1] = String(page);
|
|
261
|
+
return url.origin + path.join("/") + (chain ? "?chain" : "");
|
|
262
|
+
}
|
|
263
|
+
getFirstPageUrl() {
|
|
264
|
+
return this.getPageUrl(1, true);
|
|
265
|
+
}
|
|
266
|
+
hidePage(forceHide = false) {
|
|
267
|
+
if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) {
|
|
268
|
+
this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page");
|
|
269
|
+
sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y");
|
|
270
|
+
window.location.href = this.getPageUrl(2);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
const engridPage = document.querySelector("#engrid");
|
|
274
|
+
if (engridPage) {
|
|
275
|
+
engridPage.classList.add("hide");
|
|
276
|
+
}
|
|
255
277
|
}
|
|
256
278
|
}
|
|
257
279
|
clearSessionStorage() {
|
|
258
280
|
sessionStorage.removeItem("engrid.supporter.questions");
|
|
259
281
|
sessionStorage.removeItem("engrid.optin-ladder");
|
|
260
282
|
sessionStorage.removeItem("engrid.optin-ladder-stop");
|
|
283
|
+
sessionStorage.removeItem("engrid.optin-ladder-persist-stop");
|
|
261
284
|
}
|
|
262
285
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { EngridLogger } from "./logger";
|
|
2
|
+
import { ENGrid } from "./engrid";
|
|
3
|
+
import * as cookie from "./cookie";
|
|
4
|
+
export class StickyNSG {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.logger = new EngridLogger("StickyNSG", "teal", "white", "📌");
|
|
7
|
+
this.cookieName = "engrid-sticky-nsg";
|
|
8
|
+
if (!this.shouldRun())
|
|
9
|
+
return;
|
|
10
|
+
this.logger.log("Sticky NSG is enabled");
|
|
11
|
+
this.deleteCookieIfGiftProcessComplete();
|
|
12
|
+
this.createStickyNSGCookie();
|
|
13
|
+
this.applyStickyNSGCookie();
|
|
14
|
+
}
|
|
15
|
+
shouldRun() {
|
|
16
|
+
return ENGrid.getOption("StickyNSG") === true;
|
|
17
|
+
}
|
|
18
|
+
/*
|
|
19
|
+
* Determine if NSG provided by EN is active on the page
|
|
20
|
+
*/
|
|
21
|
+
nsgActiveOnPage() {
|
|
22
|
+
return (window.EngagingNetworks &&
|
|
23
|
+
window.EngagingNetworks.suggestedGift &&
|
|
24
|
+
typeof window.EngagingNetworks.suggestedGift === "object" &&
|
|
25
|
+
Object.keys(window.EngagingNetworks.suggestedGift).length > 0);
|
|
26
|
+
}
|
|
27
|
+
/*
|
|
28
|
+
* Delete the cookie if the gift process is complete
|
|
29
|
+
*/
|
|
30
|
+
deleteCookieIfGiftProcessComplete() {
|
|
31
|
+
if (ENGrid.getGiftProcess()) {
|
|
32
|
+
this.logger.log("Gift process complete, removing sticky NSG cookie if it exists");
|
|
33
|
+
cookie.remove(this.cookieName);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/*
|
|
37
|
+
* Create the sticky NSG cookie if NSG is active on the page
|
|
38
|
+
*/
|
|
39
|
+
createStickyNSGCookie() {
|
|
40
|
+
var _a, _b, _c, _d, _e, _f;
|
|
41
|
+
if (!this.nsgActiveOnPage()) {
|
|
42
|
+
this.logger.log("No NSG active on page, not creating sticky NSG cookie");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const url = new URL(window.location.href);
|
|
46
|
+
if (url.searchParams.get("skipstickynsg") === "true") {
|
|
47
|
+
this.logger.log("'skipstickynsg' param present, not creating sticky NSG cookie");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// We do some reformating to match the EngridAmounts format
|
|
51
|
+
// We also add "Other" to the amounts list
|
|
52
|
+
const nsg = window.EngagingNetworks.suggestedGift;
|
|
53
|
+
this.logger.log("Creating sticky NSG cookie", nsg);
|
|
54
|
+
const oneTimeNsg = (_a = nsg.single) === null || _a === void 0 ? void 0 : _a.reduce((acc, curr) => {
|
|
55
|
+
acc[curr.value] = curr.value;
|
|
56
|
+
return acc;
|
|
57
|
+
}, {});
|
|
58
|
+
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;
|
|
59
|
+
const recurringNsg = (_d = nsg.recurring) === null || _d === void 0 ? void 0 : _d.reduce((acc, curr) => {
|
|
60
|
+
acc[curr.value] = curr.value;
|
|
61
|
+
return acc;
|
|
62
|
+
}, {});
|
|
63
|
+
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;
|
|
64
|
+
const nsgCookieData = {};
|
|
65
|
+
if (oneTimeNsg && oneTimeDefault) {
|
|
66
|
+
nsgCookieData.onetime = {
|
|
67
|
+
amounts: oneTimeNsg,
|
|
68
|
+
default: oneTimeDefault,
|
|
69
|
+
stickyDefault: false,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (recurringNsg && recurringDefault) {
|
|
73
|
+
nsgCookieData.monthly = {
|
|
74
|
+
amounts: recurringNsg,
|
|
75
|
+
default: recurringDefault,
|
|
76
|
+
stickyDefault: false,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (Object.keys(nsgCookieData).length === 0) {
|
|
80
|
+
this.logger.log("No valid NSG data found to create sticky NSG cookie");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const cookieValue = JSON.stringify(nsgCookieData);
|
|
84
|
+
cookie.set(this.cookieName, cookieValue, { path: "/", expires: 30 });
|
|
85
|
+
this.logger.log("Sticky NSG cookie created", cookieValue);
|
|
86
|
+
}
|
|
87
|
+
/*
|
|
88
|
+
* Apply the sticky NSG cookie values to window.EngridAmounts if NSG is not active on the page
|
|
89
|
+
*/
|
|
90
|
+
applyStickyNSGCookie() {
|
|
91
|
+
if (this.nsgActiveOnPage()) {
|
|
92
|
+
this.logger.log("NSG active on page, not applying sticky NSG cookie, leaving the EN NSG values.");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const cookieValue = cookie.get(this.cookieName);
|
|
96
|
+
if (!cookieValue) {
|
|
97
|
+
this.logger.log("No sticky NSG cookie found, nothing to apply");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const nsg = JSON.parse(cookieValue);
|
|
102
|
+
this.logger.log("Applying sticky NSG cookie values", nsg);
|
|
103
|
+
window.EngridAmounts = nsg;
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
this.logger.error("Error parsing sticky NSG cookie, not applying", e);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class StickyPrepopulation {
|
|
2
|
+
private logger;
|
|
3
|
+
private options;
|
|
4
|
+
private cookieName;
|
|
5
|
+
constructor();
|
|
6
|
+
private shouldRun;
|
|
7
|
+
private deleteCookie;
|
|
8
|
+
private createCookie;
|
|
9
|
+
private applyPrepopulation;
|
|
10
|
+
private getSupporterDetailsFromFields;
|
|
11
|
+
private encryptSupporterDetails;
|
|
12
|
+
private decryptSupporterDetails;
|
|
13
|
+
private createEncryptionKey;
|
|
14
|
+
private arrayBufferToBase64;
|
|
15
|
+
private base64ToArrayBuffer;
|
|
16
|
+
private getSeed;
|
|
17
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { ENGrid } from "./engrid";
|
|
11
|
+
import { EngridLogger } from "./logger";
|
|
12
|
+
import * as cookie from "./cookie";
|
|
13
|
+
export class StickyPrepopulation {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.logger = new EngridLogger("StickyPrepopulation", "teal", "white", "📌");
|
|
16
|
+
this.options = { fields: [] };
|
|
17
|
+
this.cookieName = "engrid-sticky-prepop";
|
|
18
|
+
if (!this.shouldRun()) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.logger.log("StickyPrepopulation initialized");
|
|
22
|
+
if (ENGrid.getGiftProcess()) {
|
|
23
|
+
this.deleteCookie();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (ENGrid.getPageNumber() !== 1 || !ENGrid.getField("supporter.emailAddress")) {
|
|
27
|
+
this.logger.log("Not on page 1 or email field not present, not creating cookie or applying pre-population.");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.createCookie();
|
|
31
|
+
this.applyPrepopulation();
|
|
32
|
+
}
|
|
33
|
+
/*
|
|
34
|
+
* Determine if we should run the script
|
|
35
|
+
* Do not run if RememberMe is active
|
|
36
|
+
* Do not run if on a chain link
|
|
37
|
+
* Only run if StickyPrepopulation option is set with fields
|
|
38
|
+
*/
|
|
39
|
+
shouldRun() {
|
|
40
|
+
if (ENGrid.getOption("RememberMe")) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const url = new URL(window.location.href);
|
|
44
|
+
const options = ENGrid.getOption("StickyPrepopulation");
|
|
45
|
+
if (options && (options === null || options === void 0 ? void 0 : options.fields.length) > 0 && !url.searchParams.has("chain")) {
|
|
46
|
+
this.options = options;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/*
|
|
54
|
+
* Delete the cookie if the gift process is complete
|
|
55
|
+
*/
|
|
56
|
+
deleteCookie() {
|
|
57
|
+
this.logger.log("Gift process complete, removing sticky prepopulation cookie if it exists");
|
|
58
|
+
cookie.remove(this.cookieName);
|
|
59
|
+
}
|
|
60
|
+
/*
|
|
61
|
+
* Create the cookie if we're coming from a campaign link and supporterId is present
|
|
62
|
+
*/
|
|
63
|
+
createCookie() {
|
|
64
|
+
var _a;
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
// If we're not coming from a campaign link, don't create the cookie
|
|
67
|
+
if (!((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId)) {
|
|
68
|
+
this.logger.log("No supporterId present, not creating sticky prepopulation cookie");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const encryptedSupporterDetails = yield this.encryptSupporterDetails(this.getSupporterDetailsFromFields());
|
|
73
|
+
cookie.set(this.cookieName, window.btoa(JSON.stringify({
|
|
74
|
+
encryptedData: encryptedSupporterDetails.encryptedData,
|
|
75
|
+
iv: encryptedSupporterDetails.iv,
|
|
76
|
+
pageId: ENGrid.getPageID()
|
|
77
|
+
})), { path: "/", expires: 7 });
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
this.logger.log("Error creating sticky prepopulation cookie");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.logger.log("Sticky prepopulation cookie created");
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/*
|
|
87
|
+
* If the cookie is present and supporterId is not (it's not a campaign link prefilled by EN),
|
|
88
|
+
* then apply the prepopulation
|
|
89
|
+
*/
|
|
90
|
+
applyPrepopulation() {
|
|
91
|
+
var _a;
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
const cookieData = cookie.get(this.cookieName);
|
|
94
|
+
if (!cookieData) {
|
|
95
|
+
this.logger.log("No sticky prepopulation cookie found, not prepopulating fields");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if ((_a = window.pageJson) === null || _a === void 0 ? void 0 : _a.supporterId) {
|
|
99
|
+
this.logger.log("SupporterId present, not applying sticky prepopulation");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let supporterDetails = {};
|
|
103
|
+
try {
|
|
104
|
+
const encryptedSupporterDetails = JSON.parse(window.atob(cookieData));
|
|
105
|
+
if (!encryptedSupporterDetails || (encryptedSupporterDetails === null || encryptedSupporterDetails === void 0 ? void 0 : encryptedSupporterDetails.pageId) !== ENGrid.getPageID()) {
|
|
106
|
+
this.logger.log("No encrypted supporter details found in cookie, or page ID does not match");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
supporterDetails = JSON.parse(yield this.decryptSupporterDetails(this.base64ToArrayBuffer(encryptedSupporterDetails.encryptedData), new Uint8Array(this.base64ToArrayBuffer(encryptedSupporterDetails.iv))));
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
this.logger.log("Error decrypting supporter details from cookie");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.options.fields.forEach((fieldName) => {
|
|
116
|
+
if (!supporterDetails[fieldName])
|
|
117
|
+
return;
|
|
118
|
+
ENGrid.setFieldValue(fieldName, decodeURIComponent(supporterDetails[fieldName]));
|
|
119
|
+
this.logger.log(`Setting "${fieldName}" to "${decodeURIComponent(supporterDetails[fieldName])}"`);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/*
|
|
124
|
+
* Get the supporter details from the form fields
|
|
125
|
+
*/
|
|
126
|
+
getSupporterDetailsFromFields() {
|
|
127
|
+
const supporterDetails = {};
|
|
128
|
+
this.options.fields.forEach((fieldName) => {
|
|
129
|
+
let field = document.querySelector(`[name="${fieldName}"]`);
|
|
130
|
+
// If it is a radio or checkbox, get the checked value
|
|
131
|
+
if (field) {
|
|
132
|
+
if (field.type === "radio" || field.type === "checkbox") {
|
|
133
|
+
field = document.querySelector(`[name="${fieldName}"]:checked`);
|
|
134
|
+
}
|
|
135
|
+
supporterDetails[fieldName] = encodeURIComponent(field.value);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return supporterDetails;
|
|
139
|
+
}
|
|
140
|
+
/*
|
|
141
|
+
* Encrypt the supporter details
|
|
142
|
+
*/
|
|
143
|
+
encryptSupporterDetails(supporterDetails) {
|
|
144
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
const encryptionKey = yield this.createEncryptionKey(this.getSeed());
|
|
146
|
+
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
|
147
|
+
const supporterDetailsString = JSON.stringify(supporterDetails);
|
|
148
|
+
const encryptedData = yield window.crypto.subtle.encrypt({
|
|
149
|
+
name: "AES-GCM",
|
|
150
|
+
iv: iv,
|
|
151
|
+
}, encryptionKey, new TextEncoder().encode(supporterDetailsString));
|
|
152
|
+
return {
|
|
153
|
+
encryptedData: this.arrayBufferToBase64(encryptedData),
|
|
154
|
+
iv: this.arrayBufferToBase64(iv),
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/*
|
|
159
|
+
* Decrypt the supporter details
|
|
160
|
+
*/
|
|
161
|
+
decryptSupporterDetails(encryptedSupporterDetails, iv) {
|
|
162
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
163
|
+
const encryptionKey = yield this.createEncryptionKey(this.getSeed());
|
|
164
|
+
const decryptedData = yield window.crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, encryptionKey, encryptedSupporterDetails);
|
|
165
|
+
return new TextDecoder().decode(decryptedData);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/*
|
|
169
|
+
* Create the encryption key
|
|
170
|
+
*/
|
|
171
|
+
createEncryptionKey(seed) {
|
|
172
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
const encoder = new TextEncoder();
|
|
174
|
+
const keyMaterial = yield window.crypto.subtle.importKey("raw", encoder.encode(seed), { name: "PBKDF2" }, false, ["deriveKey"]);
|
|
175
|
+
return yield window.crypto.subtle.deriveKey({
|
|
176
|
+
name: "PBKDF2",
|
|
177
|
+
salt: encoder.encode(seed),
|
|
178
|
+
iterations: 100000,
|
|
179
|
+
hash: "SHA-256",
|
|
180
|
+
}, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/*
|
|
184
|
+
* Convert an ArrayBuffer to a base64 string
|
|
185
|
+
*/
|
|
186
|
+
arrayBufferToBase64(buffer) {
|
|
187
|
+
let binary = "";
|
|
188
|
+
const bytes = new Uint8Array(buffer);
|
|
189
|
+
const len = bytes.byteLength;
|
|
190
|
+
for (let i = 0; i < len; i++) {
|
|
191
|
+
binary += String.fromCharCode(bytes[i]);
|
|
192
|
+
}
|
|
193
|
+
return window.btoa(binary);
|
|
194
|
+
}
|
|
195
|
+
/*
|
|
196
|
+
* Create an Array Buffer from a base64 string
|
|
197
|
+
*/
|
|
198
|
+
base64ToArrayBuffer(base64) {
|
|
199
|
+
const binary_string = window.atob(base64);
|
|
200
|
+
const len = binary_string.length;
|
|
201
|
+
const bytes = new Uint8Array(len);
|
|
202
|
+
for (let i = 0; i < len; i++) {
|
|
203
|
+
bytes[i] = binary_string.charCodeAt(i);
|
|
204
|
+
}
|
|
205
|
+
return bytes.buffer;
|
|
206
|
+
}
|
|
207
|
+
/*
|
|
208
|
+
* Derive a seed from the page URL
|
|
209
|
+
*/
|
|
210
|
+
getSeed() {
|
|
211
|
+
const url = new URL(window.location.href);
|
|
212
|
+
return url.origin + url.pathname + (url.searchParams.get("ea.tracking.id") ? `?ea.tracking.id=${url.searchParams.get("ea.tracking.id")}` : '');
|
|
213
|
+
}
|
|
214
|
+
}
|
package/dist/swap-amounts.js
CHANGED
|
@@ -117,7 +117,12 @@ export class SwapAmounts {
|
|
|
117
117
|
}));
|
|
118
118
|
}
|
|
119
119
|
shouldRun() {
|
|
120
|
-
|
|
120
|
+
const hasNSG = window.EngagingNetworks.suggestedGift !== undefined &&
|
|
121
|
+
Object.keys(window.EngagingNetworks.suggestedGift).length > 0;
|
|
122
|
+
if (!!window.EngridAmounts && hasNSG) {
|
|
123
|
+
this.logger.log("Not swapping amounts because NSG is active on page");
|
|
124
|
+
}
|
|
125
|
+
return !!window.EngridAmounts && !hasNSG;
|
|
121
126
|
}
|
|
122
127
|
ignoreCurrentValue() {
|
|
123
128
|
const urlParam = ENGrid.getUrlParameter("transaction.donationAmt");
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AppVersion = "0.
|
|
1
|
+
export declare const AppVersion = "0.25.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AppVersion = "0.
|
|
1
|
+
export const AppVersion = "0.25.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@4site/engrid-scripts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Scripts for the ENGRID Project",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"strongly-typed-events": "^2.0.9"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/4site-interactive-studios/engrid#readme",
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "6f0962a8be8ef7211c383a7d8d7b2c188091408d",
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"nodemon": "^2.0.20"
|
|
31
31
|
}
|