@dintero/checkout-web-sdk 0.10.2 → 0.11.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/declarations/src/checkout.d.ts +2 -1
- package/dist/declarations/src/index.d.ts +4 -4
- package/dist/declarations/src/subscribe.d.ts +2 -2
- package/dist/dintero-checkout-web-sdk.cjs.dev.js +408 -395
- package/dist/dintero-checkout-web-sdk.cjs.prod.js +408 -395
- package/dist/dintero-checkout-web-sdk.esm.js +408 -395
- package/dist/dintero-checkout-web-sdk.umd.min.js +2 -2
- package/dist/dintero-checkout-web-sdk.umd.min.js.map +1 -1
- package/package.json +6 -6
|
@@ -2,7 +2,7 @@ import 'native-promise-only';
|
|
|
2
2
|
|
|
3
3
|
var pkg = {
|
|
4
4
|
name: "@dintero/checkout-web-sdk",
|
|
5
|
-
version: "0.
|
|
5
|
+
version: "0.11.0",
|
|
6
6
|
description: "Dintero Checkout SDK for web frontends",
|
|
7
7
|
main: "dist/dintero-checkout-web-sdk.cjs.js",
|
|
8
8
|
module: "dist/dintero-checkout-web-sdk.esm.js",
|
|
@@ -17,7 +17,7 @@ var pkg = {
|
|
|
17
17
|
},
|
|
18
18
|
scripts: {
|
|
19
19
|
build: "yarn tsc --noEmit && preconstruct build",
|
|
20
|
-
lint: "
|
|
20
|
+
lint: "biome check",
|
|
21
21
|
test: "vitest --config .vitest.config.mts",
|
|
22
22
|
"semantic-release": "semantic-release",
|
|
23
23
|
prepublishOnly: "yarn run build"
|
|
@@ -36,16 +36,16 @@ var pkg = {
|
|
|
36
36
|
devDependencies: {
|
|
37
37
|
"@babel/core": "7.28.5",
|
|
38
38
|
"@babel/preset-typescript": "7.28.5",
|
|
39
|
+
"@biomejs/biome": "2.3.8",
|
|
39
40
|
"@preconstruct/cli": "2.8.12",
|
|
40
41
|
"@semantic-release/exec": "7.1.0",
|
|
41
42
|
"@semantic-release/git": "10.0.1",
|
|
42
|
-
"@vitest/browser": "4.0.
|
|
43
|
+
"@vitest/browser": "4.0.15",
|
|
43
44
|
"@vitest/browser-webdriverio": "^4.0.4",
|
|
44
|
-
prettier: "3.6.2",
|
|
45
45
|
"semantic-release": "25.0.2",
|
|
46
46
|
typescript: "5.9.3",
|
|
47
|
-
vitest: "4.0.
|
|
48
|
-
webdriverio: "9.
|
|
47
|
+
vitest: "4.0.15",
|
|
48
|
+
webdriverio: "9.21.0"
|
|
49
49
|
},
|
|
50
50
|
dependencies: {
|
|
51
51
|
"native-promise-only": "0.8.1"
|
|
@@ -72,9 +72,65 @@ let InternalCheckoutEvents = /*#__PURE__*/function (InternalCheckoutEvents) {
|
|
|
72
72
|
InternalCheckoutEvents["ScrollToTop"] = "ScrollToTop";
|
|
73
73
|
InternalCheckoutEvents["ShowPopOutButton"] = "ShowPopOutButton";
|
|
74
74
|
InternalCheckoutEvents["HidePopOutButton"] = "HidePopOutButton";
|
|
75
|
+
InternalCheckoutEvents["TopLevelNavigation"] = "TopLevelNavigation";
|
|
75
76
|
return InternalCheckoutEvents;
|
|
76
77
|
}({});
|
|
77
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Creates an iframe and adds it to the container.
|
|
81
|
+
*
|
|
82
|
+
* Returns a promise that resolves to the iframe when the iframe has loaded.
|
|
83
|
+
* Rejects the promise if there is a problem loading the iframe.
|
|
84
|
+
*/
|
|
85
|
+
const createIframeAsync = (container, url) => {
|
|
86
|
+
if (!container || !container.appendChild) {
|
|
87
|
+
throw new Error("Invalid container");
|
|
88
|
+
}
|
|
89
|
+
const iframe = document.createElement("iframe");
|
|
90
|
+
|
|
91
|
+
// No border, transparent and stretch to 100% of the container width.
|
|
92
|
+
iframe.setAttribute("frameborder", "0");
|
|
93
|
+
iframe.setAttribute("allowTransparency", "true");
|
|
94
|
+
iframe.setAttribute("style", "width:100%; height:0;");
|
|
95
|
+
|
|
96
|
+
// TODO: Get this to work as expected, might be tricky with current
|
|
97
|
+
// tests since they will require the csp to be "unsafe-inline".
|
|
98
|
+
// The server needs to add the same property in the Content Security
|
|
99
|
+
// Policy headers in the response for this to work. A CSP header set by
|
|
100
|
+
// a meta tag in the iframe target will not be detected as a valid
|
|
101
|
+
// CSP from the iframe host.
|
|
102
|
+
// Content Security Policy, should be limited to "endpoint".
|
|
103
|
+
// iframe.setAttribute("csp", `default-src ${endpoint}`);
|
|
104
|
+
|
|
105
|
+
// Apply extra restrictions to the content in the iframe.
|
|
106
|
+
// allow popups is needed to open terms in new window
|
|
107
|
+
iframe.setAttribute("sandbox", "allow-scripts allow-forms allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-top-navigation");
|
|
108
|
+
|
|
109
|
+
// Needed for to allow apple pay from iframe
|
|
110
|
+
iframe.setAttribute("allow", "payment; clipboard-write *");
|
|
111
|
+
|
|
112
|
+
// The download priority of the resource in the <iframe>'s src attribute.
|
|
113
|
+
iframe.setAttribute("importance", "high");
|
|
114
|
+
|
|
115
|
+
// Set the iframe source to the url.
|
|
116
|
+
iframe.setAttribute("src", url);
|
|
117
|
+
|
|
118
|
+
// Resolve or reject promise when iframe loads.
|
|
119
|
+
|
|
120
|
+
// // Add iframe to the container.
|
|
121
|
+
// container.appendChild(iframe);
|
|
122
|
+
return {
|
|
123
|
+
iframe,
|
|
124
|
+
initiate: async () => {
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
iframe.onload = () => resolve();
|
|
127
|
+
iframe.onerror = () => reject();
|
|
128
|
+
container.appendChild(iframe);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
78
134
|
/**
|
|
79
135
|
* Wraps window.location.assign()
|
|
80
136
|
*/
|
|
@@ -112,7 +168,9 @@ const getSessionUrl = options => {
|
|
|
112
168
|
if (popOut) {
|
|
113
169
|
params.append("role", "pop_out_launcher");
|
|
114
170
|
}
|
|
115
|
-
if (
|
|
171
|
+
if (
|
|
172
|
+
// biome-ignore lint/suspicious/noPrototypeBuiltins: test
|
|
173
|
+
options.hasOwnProperty("hideTestMessage") && options.hideTestMessage !== undefined && options.hideTestMessage === true) {
|
|
116
174
|
params.append("hide_test_message", "true");
|
|
117
175
|
}
|
|
118
176
|
const hostname = getHostname();
|
|
@@ -162,7 +220,7 @@ const getHostname = () => {
|
|
|
162
220
|
hostname
|
|
163
221
|
} = window.location;
|
|
164
222
|
return hostname;
|
|
165
|
-
} catch (
|
|
223
|
+
} catch (_) {
|
|
166
224
|
return undefined;
|
|
167
225
|
}
|
|
168
226
|
};
|
|
@@ -174,7 +232,7 @@ const hostnameIsTop = () => {
|
|
|
174
232
|
const hostname = getHostname();
|
|
175
233
|
const topHostname = window.top.location.hostname;
|
|
176
234
|
return topHostname && hostname && hostname === topHostname;
|
|
177
|
-
} catch (
|
|
235
|
+
} catch (_) {
|
|
178
236
|
return false;
|
|
179
237
|
}
|
|
180
238
|
};
|
|
@@ -184,226 +242,142 @@ const url = {
|
|
|
184
242
|
windowLocationAssign
|
|
185
243
|
};
|
|
186
244
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
// Resolve or reject promise when iframe loads.
|
|
227
|
-
|
|
228
|
-
// // Add iframe to the container.
|
|
229
|
-
// container.appendChild(iframe);
|
|
230
|
-
return {
|
|
231
|
-
iframe,
|
|
232
|
-
initiate: async () => {
|
|
233
|
-
return new Promise((resolve, reject) => {
|
|
234
|
-
iframe.onload = () => resolve();
|
|
235
|
-
iframe.onerror = () => reject();
|
|
236
|
-
container.appendChild(iframe);
|
|
237
|
-
});
|
|
245
|
+
const createPopOutWindow = (sid, url, width, height) => {
|
|
246
|
+
return new Promise(resolve => {
|
|
247
|
+
try {
|
|
248
|
+
// Creates a centered pop up window
|
|
249
|
+
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
250
|
+
const top = window.screenY + (window.outerHeight - height) / 2;
|
|
251
|
+
const features = `width=${width},height=${height},left=${left},top=${top},location=no,menubar=no,toolbar=no,status=no`;
|
|
252
|
+
let popOut;
|
|
253
|
+
let timeout = -1;
|
|
254
|
+
// Set up listener for application loaded message from pop out window
|
|
255
|
+
const handleAppLoaded = event => {
|
|
256
|
+
const correctSource = event.source === popOut;
|
|
257
|
+
const correctOrigin = event.origin === new URL(url).origin;
|
|
258
|
+
const correctMessage = event.data && event.data.type === "AppLoaded";
|
|
259
|
+
const correctContext = event.data.context === "popOut";
|
|
260
|
+
const correctSid = event.data.sid === sid;
|
|
261
|
+
if (correctSource && correctOrigin && correctMessage && correctContext && correctSid) {
|
|
262
|
+
clearTimeout(timeout);
|
|
263
|
+
resolve(popOut);
|
|
264
|
+
window.removeEventListener("message", handleAppLoaded);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
window.addEventListener("message", handleAppLoaded);
|
|
268
|
+
// Open pop out
|
|
269
|
+
popOut = window.open(url, "dintero-checkout", features);
|
|
270
|
+
// Check that pop out was opened
|
|
271
|
+
if (!popOut) {
|
|
272
|
+
console.log("createPopOutWindow no popOut");
|
|
273
|
+
resolve(undefined);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// Trigger timeout if pop out is not loaded
|
|
277
|
+
timeout = window.setTimeout(() => {
|
|
278
|
+
console.log("createPopOutWindow timeout");
|
|
279
|
+
resolve(undefined);
|
|
280
|
+
}, 10000);
|
|
281
|
+
} catch (_err) {
|
|
282
|
+
resolve(undefined);
|
|
238
283
|
}
|
|
239
|
-
};
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Unsubscribe handler from event(s).
|
|
244
|
-
*/
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Post a message acknowledgement to the checkout iframe.
|
|
248
|
-
*/
|
|
249
|
-
const postAck = (source, event) => {
|
|
250
|
-
if (event.data.mid && source) {
|
|
251
|
-
source.postMessage({
|
|
252
|
-
ack: event.data.mid
|
|
253
|
-
}, event.origin || "*");
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Post a SessionLock-event to the checkout iframe.
|
|
259
|
-
*/
|
|
260
|
-
const postSessionLock = (iframe, sid) => {
|
|
261
|
-
if (iframe.contentWindow) {
|
|
262
|
-
iframe.contentWindow.postMessage({
|
|
263
|
-
type: "LockSession",
|
|
264
|
-
sid
|
|
265
|
-
}, "*");
|
|
266
|
-
}
|
|
284
|
+
});
|
|
267
285
|
};
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
type: "ValidationResult",
|
|
276
|
-
sid,
|
|
277
|
-
...result
|
|
278
|
-
}, "*");
|
|
286
|
+
const openPopOut = async options => {
|
|
287
|
+
let unsubscribe;
|
|
288
|
+
let intervalId = -1;
|
|
289
|
+
let popOutWindow;
|
|
290
|
+
if (popOutWindow && !popOutWindow.closed) {
|
|
291
|
+
// Skip if already open.
|
|
292
|
+
return;
|
|
279
293
|
}
|
|
280
|
-
};
|
|
281
294
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
295
|
+
// Open popup window
|
|
296
|
+
const popOutUrl = url.getPopOutUrl(options);
|
|
297
|
+
popOutWindow = await createPopOutWindow(options.sid, popOutUrl, Math.min(480, window.screen.width), Math.min(840, window.screen.height));
|
|
298
|
+
const focusPopOut = () => {
|
|
299
|
+
if (popOutWindow) {
|
|
300
|
+
popOutWindow.focus();
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
const cleanUpClosed = () => {
|
|
304
|
+
window.clearInterval(intervalId);
|
|
305
|
+
intervalId = -1;
|
|
306
|
+
window.removeEventListener("beforeunload", closePopOut);
|
|
307
|
+
popOutWindow = undefined;
|
|
308
|
+
options.onClose();
|
|
309
|
+
if (unsubscribe) {
|
|
310
|
+
unsubscribe();
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const closePopOut = () => {
|
|
314
|
+
if (popOutWindow) {
|
|
315
|
+
popOutWindow.close();
|
|
316
|
+
}
|
|
317
|
+
cleanUpClosed();
|
|
318
|
+
};
|
|
319
|
+
const checkIfPopupClosed = () => {
|
|
320
|
+
if (popOutWindow?.closed) {
|
|
321
|
+
cleanUpClosed();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
293
324
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
*/
|
|
297
|
-
const postActivePaymentProductType = (iframe, sid, paymentProductType) => {
|
|
298
|
-
if (iframe.contentWindow) {
|
|
299
|
-
iframe.contentWindow.postMessage({
|
|
300
|
-
type: "SetActivePaymentProductType",
|
|
301
|
-
sid,
|
|
302
|
-
payment_product_type: paymentProductType
|
|
303
|
-
}, "*");
|
|
304
|
-
}
|
|
305
|
-
};
|
|
325
|
+
// Close pop out if current window is closed
|
|
326
|
+
window.addEventListener("beforeunload", closePopOut);
|
|
306
327
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
*/
|
|
310
|
-
const postValidatePopOutEvent = (iframe, sid) => {
|
|
311
|
-
if (iframe.contentWindow) {
|
|
312
|
-
iframe.contentWindow.postMessage({
|
|
313
|
-
type: "ValidatingPopOut",
|
|
314
|
-
sid
|
|
315
|
-
}, "*");
|
|
316
|
-
}
|
|
317
|
-
};
|
|
328
|
+
// Check if checkout is still open
|
|
329
|
+
intervalId = window.setInterval(checkIfPopupClosed, 200);
|
|
318
330
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
sid
|
|
327
|
-
}, "*");
|
|
328
|
-
}
|
|
331
|
+
// Set up pub/sub of messages from pop out to SDK
|
|
332
|
+
unsubscribe = options.onOpen(popOutWindow);
|
|
333
|
+
return {
|
|
334
|
+
close: closePopOut,
|
|
335
|
+
focus: focusPopOut,
|
|
336
|
+
popOutWindow
|
|
337
|
+
};
|
|
329
338
|
};
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
339
|
+
const postPopOutSessionLock = (popOutWindow, sid) => {
|
|
340
|
+
try {
|
|
341
|
+
if (popOutWindow) {
|
|
342
|
+
popOutWindow.postMessage({
|
|
343
|
+
type: "LockSession",
|
|
344
|
+
sid
|
|
345
|
+
}, "*");
|
|
346
|
+
}
|
|
347
|
+
} catch (e) {
|
|
348
|
+
console.error(e);
|
|
340
349
|
}
|
|
341
350
|
};
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
351
|
+
const postPopOutSessionRefresh = (popOutWindow, sid) => {
|
|
352
|
+
try {
|
|
353
|
+
if (popOutWindow) {
|
|
354
|
+
popOutWindow.postMessage({
|
|
355
|
+
type: "RefreshSession",
|
|
356
|
+
sid
|
|
357
|
+
}, "*");
|
|
358
|
+
}
|
|
359
|
+
} catch (e) {
|
|
360
|
+
console.error(e);
|
|
352
361
|
}
|
|
353
362
|
};
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
363
|
+
const postPopOutActivePaymentProductType = (popOutWindow, sid, paymentProductType) => {
|
|
364
|
+
try {
|
|
365
|
+
if (popOutWindow) {
|
|
366
|
+
popOutWindow.postMessage({
|
|
367
|
+
type: "SetActivePaymentProductType",
|
|
368
|
+
sid,
|
|
369
|
+
payment_product_type: paymentProductType
|
|
370
|
+
}, "*");
|
|
371
|
+
}
|
|
372
|
+
} catch (e) {
|
|
373
|
+
console.error(e);
|
|
365
374
|
}
|
|
366
375
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const subscribe = options => {
|
|
373
|
-
const {
|
|
374
|
-
sid,
|
|
375
|
-
endpoint,
|
|
376
|
-
handler,
|
|
377
|
-
eventTypes,
|
|
378
|
-
checkout
|
|
379
|
-
} = options;
|
|
380
|
-
|
|
381
|
-
// Wrap event handler in a function that checks for correct origin and
|
|
382
|
-
// filters on event type(s) in the event data.
|
|
383
|
-
const endpointUrl = new URL(endpoint);
|
|
384
|
-
const wrappedHandler = event => {
|
|
385
|
-
const correctOrigin = event.origin === endpointUrl.origin;
|
|
386
|
-
const correctWindow = event.source === checkout.iframe.contentWindow;
|
|
387
|
-
const correctSid = event.data && event.data.sid === sid;
|
|
388
|
-
const correctMessageType = eventTypes.indexOf(event.data && event.data.type) !== -1;
|
|
389
|
-
if (correctOrigin && correctWindow && correctSid && correctMessageType) {
|
|
390
|
-
postAck(checkout.iframe.contentWindow, event);
|
|
391
|
-
handler(event.data, checkout);
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
// Add event listener to the iframe.
|
|
396
|
-
window.addEventListener("message", wrappedHandler, false);
|
|
397
|
-
|
|
398
|
-
// Function to remove the event listener from the iframe.
|
|
399
|
-
const unsubscribe = () => {
|
|
400
|
-
window.removeEventListener("message", wrappedHandler, false);
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
// Return object with unsubscribe function.
|
|
404
|
-
return {
|
|
405
|
-
unsubscribe
|
|
406
|
-
};
|
|
376
|
+
const popOutModule = {
|
|
377
|
+
openPopOut,
|
|
378
|
+
postPopOutSessionLock,
|
|
379
|
+
postPopOutSessionRefresh,
|
|
380
|
+
postPopOutActivePaymentProductType
|
|
407
381
|
};
|
|
408
382
|
|
|
409
383
|
const getBackdropZIndex = () => {
|
|
@@ -412,8 +386,8 @@ const getBackdropZIndex = () => {
|
|
|
412
386
|
const highest = Array.from(elements).reduce((acc, element) => {
|
|
413
387
|
try {
|
|
414
388
|
const zIndexStr = document.defaultView.getComputedStyle(element, null).getPropertyValue("z-index");
|
|
415
|
-
const zIndex = parseInt(zIndexStr || "0");
|
|
416
|
-
if (!isNaN(zIndex) && zIndex > acc) {
|
|
389
|
+
const zIndex = Number.parseInt(zIndexStr || "0", 10);
|
|
390
|
+
if (!Number.isNaN(zIndex) && zIndex > acc) {
|
|
417
391
|
return zIndex;
|
|
418
392
|
}
|
|
419
393
|
} catch (e) {
|
|
@@ -753,9 +727,9 @@ const configureButton = (button, {
|
|
|
753
727
|
|
|
754
728
|
// Position
|
|
755
729
|
button.style.position = "absolute";
|
|
756
|
-
button.style.top = top
|
|
757
|
-
button.style.left = left
|
|
758
|
-
button.style.right = right
|
|
730
|
+
button.style.top = `${top}px`;
|
|
731
|
+
button.style.left = `${left}px`;
|
|
732
|
+
button.style.right = `${right}px`;
|
|
759
733
|
|
|
760
734
|
// Appearance from checkout
|
|
761
735
|
const {
|
|
@@ -783,7 +757,7 @@ const addHoverAndFocusVisibleStyles = (stylesHover, stylesFocusVisible) => {
|
|
|
783
757
|
}
|
|
784
758
|
const style = document.createElement("style");
|
|
785
759
|
style.setAttribute("id", styleId);
|
|
786
|
-
|
|
760
|
+
const content = [];
|
|
787
761
|
if (stylesHover) {
|
|
788
762
|
content.push(toCssEntity(`#${OPEN_POP_OUT_BUTTON_ID}:hover:not(:disabled)`, stylesHover));
|
|
789
763
|
}
|
|
@@ -802,182 +776,211 @@ const toCssParameters = keyValues => {
|
|
|
802
776
|
const slugify = str => {
|
|
803
777
|
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
804
778
|
};
|
|
805
|
-
const addPopOutButton = options => {
|
|
806
|
-
// Will add or update existing button
|
|
807
|
-
const {
|
|
808
|
-
container
|
|
809
|
-
} = options;
|
|
810
|
-
const exists = document.getElementById(OPEN_POP_OUT_BUTTON_ID);
|
|
811
|
-
const button = exists || document.createElement("button");
|
|
812
|
-
configureButton(button, options);
|
|
813
|
-
if (!exists) {
|
|
814
|
-
container.appendChild(button);
|
|
779
|
+
const addPopOutButton = options => {
|
|
780
|
+
// Will add or update existing button
|
|
781
|
+
const {
|
|
782
|
+
container
|
|
783
|
+
} = options;
|
|
784
|
+
const exists = document.getElementById(OPEN_POP_OUT_BUTTON_ID);
|
|
785
|
+
const button = exists || document.createElement("button");
|
|
786
|
+
configureButton(button, options);
|
|
787
|
+
if (!exists) {
|
|
788
|
+
container.appendChild(button);
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
const setPopOutButtonDisabled = disabled => {
|
|
792
|
+
try {
|
|
793
|
+
const button = document.getElementById(OPEN_POP_OUT_BUTTON_ID);
|
|
794
|
+
if (button) {
|
|
795
|
+
if (disabled) {
|
|
796
|
+
button.setAttribute("disabled", disabled.toString());
|
|
797
|
+
} else {
|
|
798
|
+
button.removeAttribute("disabled");
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
} catch (e) {
|
|
802
|
+
// Ignore error and continue
|
|
803
|
+
console.error(e);
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
const removePopOutButton = () => {
|
|
807
|
+
try {
|
|
808
|
+
const button = document.getElementById(OPEN_POP_OUT_BUTTON_ID);
|
|
809
|
+
if (button) {
|
|
810
|
+
button.remove();
|
|
811
|
+
}
|
|
812
|
+
} catch (e) {
|
|
813
|
+
// Ignore error and continue
|
|
814
|
+
console.error(e);
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Unsubscribe handler from event(s).
|
|
820
|
+
*/
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Post a message acknowledgement to the checkout iframe.
|
|
824
|
+
*/
|
|
825
|
+
const postAck = (source, event) => {
|
|
826
|
+
if (event.data.mid && source) {
|
|
827
|
+
source.postMessage({
|
|
828
|
+
ack: event.data.mid
|
|
829
|
+
}, event.origin || "*");
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Post a SessionLock-event to the checkout iframe.
|
|
835
|
+
*/
|
|
836
|
+
const postSessionLock = (iframe, sid) => {
|
|
837
|
+
if (iframe.contentWindow) {
|
|
838
|
+
iframe.contentWindow.postMessage({
|
|
839
|
+
type: "LockSession",
|
|
840
|
+
sid
|
|
841
|
+
}, "*");
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Post the validation result to the checkout iframe
|
|
847
|
+
*/
|
|
848
|
+
const postValidationResult = (iframe, sid, result) => {
|
|
849
|
+
if (iframe.contentWindow) {
|
|
850
|
+
iframe.contentWindow.postMessage({
|
|
851
|
+
type: "ValidationResult",
|
|
852
|
+
sid,
|
|
853
|
+
...result
|
|
854
|
+
}, "*");
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Post RefreshSession-event to the checkout iframe.
|
|
860
|
+
*/
|
|
861
|
+
const postSessionRefresh = (iframe, sid) => {
|
|
862
|
+
if (iframe.contentWindow) {
|
|
863
|
+
iframe.contentWindow.postMessage({
|
|
864
|
+
type: "RefreshSession",
|
|
865
|
+
sid
|
|
866
|
+
}, "*");
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Post SetActivePaymentProductType-event to the checkout iframe.
|
|
872
|
+
*/
|
|
873
|
+
const postActivePaymentProductType = (iframe, sid, paymentProductType) => {
|
|
874
|
+
if (iframe.contentWindow) {
|
|
875
|
+
iframe.contentWindow.postMessage({
|
|
876
|
+
type: "SetActivePaymentProductType",
|
|
877
|
+
sid,
|
|
878
|
+
payment_product_type: paymentProductType
|
|
879
|
+
}, "*");
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Post ClosePopOut-event to the checkout iframe.
|
|
885
|
+
*/
|
|
886
|
+
const postValidatePopOutEvent = (iframe, sid) => {
|
|
887
|
+
if (iframe.contentWindow) {
|
|
888
|
+
iframe.contentWindow.postMessage({
|
|
889
|
+
type: "ValidatingPopOut",
|
|
890
|
+
sid
|
|
891
|
+
}, "*");
|
|
815
892
|
}
|
|
816
893
|
};
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
827
|
-
} catch (e) {
|
|
828
|
-
// Ignore error and continue
|
|
829
|
-
console.error(e);
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* Post OpenPopOutFailed-event to the checkout iframe.
|
|
897
|
+
*/
|
|
898
|
+
const postOpenPopOutFailedEvent = (iframe, sid) => {
|
|
899
|
+
if (iframe.contentWindow) {
|
|
900
|
+
iframe.contentWindow.postMessage({
|
|
901
|
+
type: "OpenPopOutFailed",
|
|
902
|
+
sid
|
|
903
|
+
}, "*");
|
|
830
904
|
}
|
|
831
905
|
};
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Post OpenedPopOut-event to the checkout iframe.
|
|
909
|
+
*/
|
|
910
|
+
const postOpenPopOutEvent = (iframe, sid) => {
|
|
911
|
+
if (iframe.contentWindow) {
|
|
912
|
+
iframe.contentWindow.postMessage({
|
|
913
|
+
type: "OpenedPopOut",
|
|
914
|
+
sid
|
|
915
|
+
}, "*");
|
|
841
916
|
}
|
|
842
917
|
};
|
|
843
918
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
const handleAppLoaded = event => {
|
|
855
|
-
const correctSource = event.source === popOut;
|
|
856
|
-
const correctOrigin = event.origin === new URL(url).origin;
|
|
857
|
-
const correctMessage = event.data && event.data.type === "AppLoaded";
|
|
858
|
-
const correctContext = event.data.context === "popOut";
|
|
859
|
-
const correctSid = event.data.sid === sid;
|
|
860
|
-
if (correctSource && correctOrigin && correctMessage && correctContext && correctSid) {
|
|
861
|
-
clearTimeout(timeout);
|
|
862
|
-
resolve(popOut);
|
|
863
|
-
window.removeEventListener("message", handleAppLoaded);
|
|
864
|
-
}
|
|
865
|
-
};
|
|
866
|
-
window.addEventListener("message", handleAppLoaded);
|
|
867
|
-
// Open pop out
|
|
868
|
-
popOut = window.open(url, "dintero-checkout", features);
|
|
869
|
-
// Check that pop out was opened
|
|
870
|
-
if (!popOut) {
|
|
871
|
-
console.log("createPopOutWindow no popOut");
|
|
872
|
-
resolve(undefined);
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
|
-
// Trigger timeout if pop out is not loaded
|
|
876
|
-
timeout = window.setTimeout(() => {
|
|
877
|
-
console.log("createPopOutWindow timeout");
|
|
878
|
-
resolve(undefined);
|
|
879
|
-
}, 10000);
|
|
880
|
-
} catch (err) {
|
|
881
|
-
resolve(undefined);
|
|
882
|
-
}
|
|
883
|
-
});
|
|
919
|
+
/**
|
|
920
|
+
* Post ClosePopOut-event to the checkout iframe.
|
|
921
|
+
*/
|
|
922
|
+
const postClosePopOutEvent = (iframe, sid) => {
|
|
923
|
+
if (iframe.contentWindow) {
|
|
924
|
+
iframe.contentWindow.postMessage({
|
|
925
|
+
type: "ClosedPopOut",
|
|
926
|
+
sid
|
|
927
|
+
}, "*");
|
|
928
|
+
}
|
|
884
929
|
};
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Post SetLanguage-event to the checkout iframe.
|
|
933
|
+
*/
|
|
934
|
+
const postSetLanguage = (iframe, sid, language) => {
|
|
935
|
+
if (iframe.contentWindow) {
|
|
936
|
+
iframe.contentWindow.postMessage({
|
|
937
|
+
type: "SetLanguage",
|
|
938
|
+
sid,
|
|
939
|
+
language
|
|
940
|
+
}, "*");
|
|
892
941
|
}
|
|
942
|
+
};
|
|
893
943
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
const checkIfPopupClosed = () => {
|
|
919
|
-
if (popOutWindow && popOutWindow.closed) {
|
|
920
|
-
cleanUpClosed();
|
|
944
|
+
/**
|
|
945
|
+
* Subscribe to events from an iframe given a handler and a set
|
|
946
|
+
* of event types.
|
|
947
|
+
*/
|
|
948
|
+
const subscribe = options => {
|
|
949
|
+
const {
|
|
950
|
+
sid,
|
|
951
|
+
endpoint,
|
|
952
|
+
handler,
|
|
953
|
+
eventTypes,
|
|
954
|
+
checkout
|
|
955
|
+
} = options;
|
|
956
|
+
|
|
957
|
+
// Wrap event handler in a function that checks for correct origin and
|
|
958
|
+
// filters on event type(s) in the event data.
|
|
959
|
+
const endpointUrl = new URL(endpoint);
|
|
960
|
+
const wrappedHandler = event => {
|
|
961
|
+
const correctOrigin = event.origin === endpointUrl.origin;
|
|
962
|
+
const correctWindow = event.source === checkout.iframe.contentWindow;
|
|
963
|
+
const correctSid = event.data && event.data.sid === sid;
|
|
964
|
+
const correctMessageType = eventTypes.indexOf(event.data?.type) !== -1;
|
|
965
|
+
if (correctOrigin && correctWindow && correctSid && correctMessageType) {
|
|
966
|
+
postAck(checkout.iframe.contentWindow, event);
|
|
967
|
+
handler(event.data, checkout);
|
|
921
968
|
}
|
|
922
969
|
};
|
|
923
970
|
|
|
924
|
-
//
|
|
925
|
-
window.addEventListener("
|
|
971
|
+
// Add event listener to the iframe.
|
|
972
|
+
window.addEventListener("message", wrappedHandler, false);
|
|
926
973
|
|
|
927
|
-
//
|
|
928
|
-
|
|
974
|
+
// Function to remove the event listener from the iframe.
|
|
975
|
+
const unsubscribe = () => {
|
|
976
|
+
window.removeEventListener("message", wrappedHandler, false);
|
|
977
|
+
};
|
|
929
978
|
|
|
930
|
-
//
|
|
931
|
-
unsubscribe = options.onOpen(popOutWindow);
|
|
979
|
+
// Return object with unsubscribe function.
|
|
932
980
|
return {
|
|
933
|
-
|
|
934
|
-
focus: focusPopOut,
|
|
935
|
-
popOutWindow
|
|
981
|
+
unsubscribe
|
|
936
982
|
};
|
|
937
983
|
};
|
|
938
|
-
const postPopOutSessionLock = (popOutWindow, sid) => {
|
|
939
|
-
try {
|
|
940
|
-
if (popOutWindow) {
|
|
941
|
-
popOutWindow.postMessage({
|
|
942
|
-
type: "LockSession",
|
|
943
|
-
sid
|
|
944
|
-
}, "*");
|
|
945
|
-
}
|
|
946
|
-
} catch (e) {
|
|
947
|
-
console.error(e);
|
|
948
|
-
}
|
|
949
|
-
};
|
|
950
|
-
const postPopOutSessionRefresh = (popOutWindow, sid) => {
|
|
951
|
-
try {
|
|
952
|
-
if (popOutWindow) {
|
|
953
|
-
popOutWindow.postMessage({
|
|
954
|
-
type: "RefreshSession",
|
|
955
|
-
sid
|
|
956
|
-
}, "*");
|
|
957
|
-
}
|
|
958
|
-
} catch (e) {
|
|
959
|
-
console.error(e);
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
const postPopOutActivePaymentProductType = (popOutWindow, sid, paymentProductType) => {
|
|
963
|
-
try {
|
|
964
|
-
if (popOutWindow) {
|
|
965
|
-
popOutWindow.postMessage({
|
|
966
|
-
type: "SetActivePaymentProductType",
|
|
967
|
-
sid,
|
|
968
|
-
payment_product_type: paymentProductType
|
|
969
|
-
}, "*");
|
|
970
|
-
}
|
|
971
|
-
} catch (e) {
|
|
972
|
-
console.error(e);
|
|
973
|
-
}
|
|
974
|
-
};
|
|
975
|
-
const popOutModule = {
|
|
976
|
-
openPopOut,
|
|
977
|
-
postPopOutSessionLock,
|
|
978
|
-
postPopOutSessionRefresh,
|
|
979
|
-
postPopOutActivePaymentProductType
|
|
980
|
-
};
|
|
981
984
|
|
|
982
985
|
/**
|
|
983
986
|
* An event handler that navigates to the href in the event.
|
|
@@ -1002,7 +1005,7 @@ const setIframeHeight = (event, checkout) => {
|
|
|
1002
1005
|
* An event handler that scrolls to the top of the iframe. This is useful when the user
|
|
1003
1006
|
* is navigated to another page.
|
|
1004
1007
|
*/
|
|
1005
|
-
const scrollToIframeTop = (
|
|
1008
|
+
const scrollToIframeTop = (_event, checkout) => {
|
|
1006
1009
|
try {
|
|
1007
1010
|
checkout.iframe.scrollIntoView({
|
|
1008
1011
|
block: "start",
|
|
@@ -1053,7 +1056,7 @@ const createPopOutMessageHandler = (source, checkout) => {
|
|
|
1053
1056
|
const popOutCompletedHandler = {
|
|
1054
1057
|
internalPopOutHandler: true,
|
|
1055
1058
|
eventTypes: paymentCompletedEvents,
|
|
1056
|
-
handler: (eventData,
|
|
1059
|
+
handler: (eventData, _checkout) => {
|
|
1057
1060
|
if (eventData.href) {
|
|
1058
1061
|
// Remove open pop out button rendered by SDK
|
|
1059
1062
|
removePopOutButton();
|
|
@@ -1075,18 +1078,18 @@ const createPopOutMessageHandler = (source, checkout) => {
|
|
|
1075
1078
|
// Check that we should handle the message
|
|
1076
1079
|
if (event.source === source && event.data.context === "popOut" && event.data.sid === checkout.options.sid) {
|
|
1077
1080
|
// Check if handler matches incoming event and trigger the handler if so.
|
|
1078
|
-
[
|
|
1081
|
+
for (const handlerObject of [
|
|
1079
1082
|
// SDK events for managing the pop out flow.
|
|
1080
1083
|
popOutChangedLanguageHandler, popOutCompletedHandler,
|
|
1081
1084
|
// Events configured when the checkout was embedded.
|
|
1082
|
-
...checkout.handlers]
|
|
1085
|
+
...checkout.handlers]) {
|
|
1083
1086
|
if (handlerObject.eventTypes.includes(event.data.type) && handlerObject.handler) {
|
|
1084
1087
|
// Invoking the handler function if the event type matches the handler.
|
|
1085
1088
|
safelyInvoke(() => {
|
|
1086
1089
|
handlerObject.handler(event.data, checkout);
|
|
1087
1090
|
});
|
|
1088
1091
|
}
|
|
1089
|
-
}
|
|
1092
|
+
}
|
|
1090
1093
|
}
|
|
1091
1094
|
};
|
|
1092
1095
|
// Add messageRouter event listener to the Pop Out
|
|
@@ -1227,7 +1230,7 @@ const handleShowButton = (event, checkout) => {
|
|
|
1227
1230
|
/**
|
|
1228
1231
|
* Remove the pop out button above the embedded iframe
|
|
1229
1232
|
*/
|
|
1230
|
-
const handleRemoveButton = (event,
|
|
1233
|
+
const handleRemoveButton = (event, _checkout) => {
|
|
1231
1234
|
if (event.type === InternalCheckoutEvents.HidePopOutButton) {
|
|
1232
1235
|
removePopOutButton();
|
|
1233
1236
|
}
|
|
@@ -1290,15 +1293,16 @@ const embed = async options => {
|
|
|
1290
1293
|
const {
|
|
1291
1294
|
iframe,
|
|
1292
1295
|
initiate
|
|
1293
|
-
} = createIframeAsync(innerContainer,
|
|
1296
|
+
} = createIframeAsync(innerContainer, url.getSessionUrl({
|
|
1294
1297
|
sid,
|
|
1295
1298
|
endpoint,
|
|
1296
1299
|
language,
|
|
1297
1300
|
ui: options.ui || "inline",
|
|
1298
1301
|
shouldCallValidateSession: onValidateSession !== undefined,
|
|
1299
1302
|
popOut,
|
|
1303
|
+
// biome-ignore lint/suspicious/noPrototypeBuiltins: test
|
|
1300
1304
|
...(options.hasOwnProperty("hideTestMessage") && {
|
|
1301
|
-
hideTestMessage: options
|
|
1305
|
+
hideTestMessage: options.hideTestMessage
|
|
1302
1306
|
})
|
|
1303
1307
|
}));
|
|
1304
1308
|
|
|
@@ -1312,7 +1316,9 @@ const embed = async options => {
|
|
|
1312
1316
|
// Try to remove backdrop if it exists
|
|
1313
1317
|
removeBackdrop();
|
|
1314
1318
|
}
|
|
1315
|
-
|
|
1319
|
+
for (const sub of subscriptions) {
|
|
1320
|
+
sub.unsubscribe();
|
|
1321
|
+
}
|
|
1316
1322
|
if (iframe.parentElement) {
|
|
1317
1323
|
innerContainer.removeChild(iframe);
|
|
1318
1324
|
}
|
|
@@ -1336,7 +1342,9 @@ const embed = async options => {
|
|
|
1336
1342
|
sid,
|
|
1337
1343
|
endpoint,
|
|
1338
1344
|
handler: sessionEvent => {
|
|
1339
|
-
|
|
1345
|
+
for (const sub of eventSubscriptions) {
|
|
1346
|
+
sub.unsubscribe();
|
|
1347
|
+
}
|
|
1340
1348
|
resolve(sessionEvent);
|
|
1341
1349
|
},
|
|
1342
1350
|
eventTypes: [resolveEvent],
|
|
@@ -1347,7 +1355,9 @@ const embed = async options => {
|
|
|
1347
1355
|
sid,
|
|
1348
1356
|
endpoint,
|
|
1349
1357
|
handler: () => {
|
|
1350
|
-
|
|
1358
|
+
for (const sub of eventSubscriptions) {
|
|
1359
|
+
sub.unsubscribe();
|
|
1360
|
+
}
|
|
1351
1361
|
reject(`Received unexpected event: ${rejectEvent}`);
|
|
1352
1362
|
},
|
|
1353
1363
|
eventTypes: [rejectEvent],
|
|
@@ -1387,7 +1397,7 @@ const embed = async options => {
|
|
|
1387
1397
|
* error message. Only used when the embed function in the SDK has a dedicated handler for onPayment, onError etc.
|
|
1388
1398
|
* If no custom handler is set the followHref handler is used instead.
|
|
1389
1399
|
*/
|
|
1390
|
-
const handleWithResult = (
|
|
1400
|
+
const handleWithResult = (_sid, endpoint, handler) => {
|
|
1391
1401
|
return (event, checkout) => {
|
|
1392
1402
|
if (!has_delivered_final_event) {
|
|
1393
1403
|
has_delivered_final_event = true;
|
|
@@ -1399,7 +1409,7 @@ const embed = async options => {
|
|
|
1399
1409
|
}
|
|
1400
1410
|
pairs.push(["language", checkout.language]);
|
|
1401
1411
|
pairs.push(["sdk", pkg.version]);
|
|
1402
|
-
const urlQuery = pairs.filter(([
|
|
1412
|
+
const urlQuery = pairs.filter(([_key, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
1403
1413
|
checkout.iframe.setAttribute("src", composeUrl(endpoint, "embedResult/", urlQuery));
|
|
1404
1414
|
handler(event, checkout);
|
|
1405
1415
|
}
|
|
@@ -1444,6 +1454,9 @@ const embed = async options => {
|
|
|
1444
1454
|
}, {
|
|
1445
1455
|
handler: scrollToIframeTop,
|
|
1446
1456
|
eventTypes: [InternalCheckoutEvents.ScrollToTop]
|
|
1457
|
+
}, {
|
|
1458
|
+
handler: followHref,
|
|
1459
|
+
eventTypes: [InternalCheckoutEvents.TopLevelNavigation]
|
|
1447
1460
|
}, {
|
|
1448
1461
|
handler: wrappedOnLoadedOrUpdated,
|
|
1449
1462
|
eventTypes: [CheckoutEvents.SessionLoaded, CheckoutEvents.SessionUpdated]
|
|
@@ -1495,10 +1508,10 @@ const embed = async options => {
|
|
|
1495
1508
|
session: undefined,
|
|
1496
1509
|
popOutWindow: undefined
|
|
1497
1510
|
};
|
|
1498
|
-
|
|
1511
|
+
for (const {
|
|
1499
1512
|
handler,
|
|
1500
1513
|
eventTypes
|
|
1501
|
-
})
|
|
1514
|
+
} of handlers) {
|
|
1502
1515
|
if (handler) {
|
|
1503
1516
|
subscriptions.push(subscribe({
|
|
1504
1517
|
sid,
|
|
@@ -1509,7 +1522,7 @@ const embed = async options => {
|
|
|
1509
1522
|
source: checkout.iframe.contentWindow
|
|
1510
1523
|
}));
|
|
1511
1524
|
}
|
|
1512
|
-
}
|
|
1525
|
+
}
|
|
1513
1526
|
|
|
1514
1527
|
// Add iframe to DOM
|
|
1515
1528
|
await initiate();
|