@authsignal/browser 0.1.0 → 0.1.2

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/index.mjs DELETED
@@ -1,4520 +0,0 @@
1
- // Unique ID creation requires a high quality random # generator. In the browser we therefore
2
- // require the crypto API and do not support built-in fallback to lower quality random number
3
- // generators (like Math.random()).
4
- let getRandomValues;
5
- const rnds8 = new Uint8Array(16);
6
- function rng() {
7
- // lazy load so that environments that need to polyfill have a chance to do so
8
- if (!getRandomValues) {
9
- // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
10
- getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
11
-
12
- if (!getRandomValues) {
13
- throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
14
- }
15
- }
16
-
17
- return getRandomValues(rnds8);
18
- }
19
-
20
- /**
21
- * Convert array of 16 byte values to UUID string format of the form:
22
- * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
23
- */
24
-
25
- const byteToHex = [];
26
-
27
- for (let i = 0; i < 256; ++i) {
28
- byteToHex.push((i + 0x100).toString(16).slice(1));
29
- }
30
-
31
- function unsafeStringify(arr, offset = 0) {
32
- // Note: Be careful editing this code! It's been tuned for performance
33
- // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
34
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
35
- }
36
-
37
- const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
38
- var native = {
39
- randomUUID
40
- };
41
-
42
- function v4(options, buf, offset) {
43
- if (native.randomUUID && !buf && !options) {
44
- return native.randomUUID();
45
- }
46
-
47
- options = options || {};
48
- const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
49
-
50
- rnds[6] = rnds[6] & 0x0f | 0x40;
51
- rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
52
-
53
- if (buf) {
54
- offset = offset || 0;
55
-
56
- for (let i = 0; i < 16; ++i) {
57
- buf[offset + i] = rnds[i];
58
- }
59
-
60
- return buf;
61
- }
62
-
63
- return unsafeStringify(rnds);
64
- }
65
-
66
- var setCookie = function (_a) {
67
- var name = _a.name, value = _a.value, expire = _a.expire, domain = _a.domain, secure = _a.secure;
68
- var expireString = expire === Infinity ? " expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + expire;
69
- document.cookie =
70
- encodeURIComponent(name) +
71
- "=" +
72
- value +
73
- "; path=/;" +
74
- expireString +
75
- (domain ? "; domain=" + domain : "") +
76
- (secure ? "; secure" : "");
77
- };
78
- var getCookieDomain = function () {
79
- return document.location.hostname.replace("www.", "");
80
- };
81
- var getCookie = function (name) {
82
- if (!name) {
83
- return null;
84
- }
85
- return (decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(name).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null);
86
- };
87
-
88
- var AuthsignalWindowMessage;
89
- (function (AuthsignalWindowMessage) {
90
- AuthsignalWindowMessage["AUTHSIGNAL_CLOSE_POPUP"] = "AUTHSIGNAL_CLOSE_POPUP";
91
- })(AuthsignalWindowMessage || (AuthsignalWindowMessage = {}));
92
-
93
- var focusableSelectors = [
94
- 'a[href]:not([tabindex^="-"])',
95
- 'area[href]:not([tabindex^="-"])',
96
- 'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])',
97
- 'input[type="radio"]:not([disabled]):not([tabindex^="-"])',
98
- 'select:not([disabled]):not([tabindex^="-"])',
99
- 'textarea:not([disabled]):not([tabindex^="-"])',
100
- 'button:not([disabled]):not([tabindex^="-"])',
101
- 'iframe:not([tabindex^="-"])',
102
- 'audio[controls]:not([tabindex^="-"])',
103
- 'video[controls]:not([tabindex^="-"])',
104
- '[contenteditable]:not([tabindex^="-"])',
105
- '[tabindex]:not([tabindex^="-"])',
106
- ];
107
-
108
- var TAB_KEY = 'Tab';
109
- var ESCAPE_KEY = 'Escape';
110
-
111
- /**
112
- * Define the constructor to instantiate a dialog
113
- *
114
- * @constructor
115
- * @param {Element} element
116
- */
117
- function A11yDialog(element) {
118
- // Prebind the functions that will be bound in addEventListener and
119
- // removeEventListener to avoid losing references
120
- this._show = this.show.bind(this);
121
- this._hide = this.hide.bind(this);
122
- this._maintainFocus = this._maintainFocus.bind(this);
123
- this._bindKeypress = this._bindKeypress.bind(this);
124
-
125
- this.$el = element;
126
- this.shown = false;
127
- this._id = this.$el.getAttribute('data-a11y-dialog') || this.$el.id;
128
- this._previouslyFocused = null;
129
- this._listeners = {};
130
-
131
- // Initialise everything needed for the dialog to work properly
132
- this.create();
133
- }
134
-
135
- /**
136
- * Set up everything necessary for the dialog to be functioning
137
- *
138
- * @param {(NodeList | Element | string)} targets
139
- * @return {this}
140
- */
141
- A11yDialog.prototype.create = function () {
142
- this.$el.setAttribute('aria-hidden', true);
143
- this.$el.setAttribute('aria-modal', true);
144
- this.$el.setAttribute('tabindex', -1);
145
-
146
- if (!this.$el.hasAttribute('role')) {
147
- this.$el.setAttribute('role', 'dialog');
148
- }
149
-
150
- // Keep a collection of dialog openers, each of which will be bound a click
151
- // event listener to open the dialog
152
- this._openers = $$('[data-a11y-dialog-show="' + this._id + '"]');
153
- this._openers.forEach(
154
- function (opener) {
155
- opener.addEventListener('click', this._show);
156
- }.bind(this)
157
- );
158
-
159
- // Keep a collection of dialog closers, each of which will be bound a click
160
- // event listener to close the dialog
161
- const $el = this.$el;
162
-
163
- this._closers = $$('[data-a11y-dialog-hide]', this.$el)
164
- // This filter is necessary in case there are nested dialogs, so that
165
- // only closers from the current dialog are retrieved and effective
166
- .filter(function (closer) {
167
- // Testing for `[aria-modal="true"]` is not enough since this attribute
168
- // and the collect of closers is done at instantation time, when nested
169
- // dialogs might not have yet been instantiated. Note that if the dialogs
170
- // are manually instantiated, this could still fail because none of these
171
- // selectors would match; this would cause closers to close all parent
172
- // dialogs instead of just the current one
173
- return closer.closest('[aria-modal="true"], [data-a11y-dialog]') === $el
174
- })
175
- .concat($$('[data-a11y-dialog-hide="' + this._id + '"]'));
176
-
177
- this._closers.forEach(
178
- function (closer) {
179
- closer.addEventListener('click', this._hide);
180
- }.bind(this)
181
- );
182
-
183
- // Execute all callbacks registered for the `create` event
184
- this._fire('create');
185
-
186
- return this
187
- };
188
-
189
- /**
190
- * Show the dialog element, disable all the targets (siblings), trap the
191
- * current focus within it, listen for some specific key presses and fire all
192
- * registered callbacks for `show` event
193
- *
194
- * @param {CustomEvent} event
195
- * @return {this}
196
- */
197
- A11yDialog.prototype.show = function (event) {
198
- // If the dialog is already open, abort
199
- if (this.shown) {
200
- return this
201
- }
202
-
203
- // Keep a reference to the currently focused element to be able to restore
204
- // it later
205
- this._previouslyFocused = document.activeElement;
206
- this.$el.removeAttribute('aria-hidden');
207
- this.shown = true;
208
-
209
- // Set the focus to the dialog element
210
- moveFocusToDialog(this.$el);
211
-
212
- // Bind a focus event listener to the body element to make sure the focus
213
- // stays trapped inside the dialog while open, and start listening for some
214
- // specific key presses (TAB and ESC)
215
- document.body.addEventListener('focus', this._maintainFocus, true);
216
- document.addEventListener('keydown', this._bindKeypress);
217
-
218
- // Execute all callbacks registered for the `show` event
219
- this._fire('show', event);
220
-
221
- return this
222
- };
223
-
224
- /**
225
- * Hide the dialog element, enable all the targets (siblings), restore the
226
- * focus to the previously active element, stop listening for some specific
227
- * key presses and fire all registered callbacks for `hide` event
228
- *
229
- * @param {CustomEvent} event
230
- * @return {this}
231
- */
232
- A11yDialog.prototype.hide = function (event) {
233
- // If the dialog is already closed, abort
234
- if (!this.shown) {
235
- return this
236
- }
237
-
238
- this.shown = false;
239
- this.$el.setAttribute('aria-hidden', 'true');
240
-
241
- // If there was a focused element before the dialog was opened (and it has a
242
- // `focus` method), restore the focus back to it
243
- // See: https://github.com/KittyGiraudel/a11y-dialog/issues/108
244
- if (this._previouslyFocused && this._previouslyFocused.focus) {
245
- this._previouslyFocused.focus();
246
- }
247
-
248
- // Remove the focus event listener to the body element and stop listening
249
- // for specific key presses
250
- document.body.removeEventListener('focus', this._maintainFocus, true);
251
- document.removeEventListener('keydown', this._bindKeypress);
252
-
253
- // Execute all callbacks registered for the `hide` event
254
- this._fire('hide', event);
255
-
256
- return this
257
- };
258
-
259
- /**
260
- * Destroy the current instance (after making sure the dialog has been hidden)
261
- * and remove all associated listeners from dialog openers and closers
262
- *
263
- * @return {this}
264
- */
265
- A11yDialog.prototype.destroy = function () {
266
- // Hide the dialog to avoid destroying an open instance
267
- this.hide();
268
-
269
- // Remove the click event listener from all dialog openers
270
- this._openers.forEach(
271
- function (opener) {
272
- opener.removeEventListener('click', this._show);
273
- }.bind(this)
274
- );
275
-
276
- // Remove the click event listener from all dialog closers
277
- this._closers.forEach(
278
- function (closer) {
279
- closer.removeEventListener('click', this._hide);
280
- }.bind(this)
281
- );
282
-
283
- // Execute all callbacks registered for the `destroy` event
284
- this._fire('destroy');
285
-
286
- // Keep an object of listener types mapped to callback functions
287
- this._listeners = {};
288
-
289
- return this
290
- };
291
-
292
- /**
293
- * Register a new callback for the given event type
294
- *
295
- * @param {string} type
296
- * @param {Function} handler
297
- */
298
- A11yDialog.prototype.on = function (type, handler) {
299
- if (typeof this._listeners[type] === 'undefined') {
300
- this._listeners[type] = [];
301
- }
302
-
303
- this._listeners[type].push(handler);
304
-
305
- return this
306
- };
307
-
308
- /**
309
- * Unregister an existing callback for the given event type
310
- *
311
- * @param {string} type
312
- * @param {Function} handler
313
- */
314
- A11yDialog.prototype.off = function (type, handler) {
315
- var index = (this._listeners[type] || []).indexOf(handler);
316
-
317
- if (index > -1) {
318
- this._listeners[type].splice(index, 1);
319
- }
320
-
321
- return this
322
- };
323
-
324
- /**
325
- * Iterate over all registered handlers for given type and call them all with
326
- * the dialog element as first argument, event as second argument (if any). Also
327
- * dispatch a custom event on the DOM element itself to make it possible to
328
- * react to the lifecycle of auto-instantiated dialogs.
329
- *
330
- * @access private
331
- * @param {string} type
332
- * @param {CustomEvent} event
333
- */
334
- A11yDialog.prototype._fire = function (type, event) {
335
- var listeners = this._listeners[type] || [];
336
- var domEvent = new CustomEvent(type, { detail: event });
337
-
338
- this.$el.dispatchEvent(domEvent);
339
-
340
- listeners.forEach(
341
- function (listener) {
342
- listener(this.$el, event);
343
- }.bind(this)
344
- );
345
- };
346
-
347
- /**
348
- * Private event handler used when listening to some specific key presses
349
- * (namely ESCAPE and TAB)
350
- *
351
- * @access private
352
- * @param {Event} event
353
- */
354
- A11yDialog.prototype._bindKeypress = function (event) {
355
- // This is an escape hatch in case there are nested dialogs, so the keypresses
356
- // are only reacted to for the most recent one
357
- const focused = document.activeElement;
358
- if (focused && focused.closest('[aria-modal="true"]') !== this.$el) return
359
-
360
- // If the dialog is shown and the ESCAPE key is being pressed, prevent any
361
- // further effects from the ESCAPE key and hide the dialog, unless its role
362
- // is 'alertdialog', which should be modal
363
- if (
364
- this.shown &&
365
- event.key === ESCAPE_KEY &&
366
- this.$el.getAttribute('role') !== 'alertdialog'
367
- ) {
368
- event.preventDefault();
369
- this.hide(event);
370
- }
371
-
372
- // If the dialog is shown and the TAB key is being pressed, make sure the
373
- // focus stays trapped within the dialog element
374
- if (this.shown && event.key === TAB_KEY) {
375
- trapTabKey(this.$el, event);
376
- }
377
- };
378
-
379
- /**
380
- * Private event handler used when making sure the focus stays within the
381
- * currently open dialog
382
- *
383
- * @access private
384
- * @param {Event} event
385
- */
386
- A11yDialog.prototype._maintainFocus = function (event) {
387
- // If the dialog is shown and the focus is not within a dialog element (either
388
- // this one or another one in case of nested dialogs) or within an element
389
- // with the `data-a11y-dialog-focus-trap-ignore` attribute, move it back to
390
- // its first focusable child.
391
- // See: https://github.com/KittyGiraudel/a11y-dialog/issues/177
392
- if (
393
- this.shown &&
394
- !event.target.closest('[aria-modal="true"]') &&
395
- !event.target.closest('[data-a11y-dialog-ignore-focus-trap]')
396
- ) {
397
- moveFocusToDialog(this.$el);
398
- }
399
- };
400
-
401
- /**
402
- * Convert a NodeList into an array
403
- *
404
- * @param {NodeList} collection
405
- * @return {Array<Element>}
406
- */
407
- function toArray(collection) {
408
- return Array.prototype.slice.call(collection)
409
- }
410
-
411
- /**
412
- * Query the DOM for nodes matching the given selector, scoped to context (or
413
- * the whole document)
414
- *
415
- * @param {String} selector
416
- * @param {Element} [context = document]
417
- * @return {Array<Element>}
418
- */
419
- function $$(selector, context) {
420
- return toArray((context || document).querySelectorAll(selector))
421
- }
422
-
423
- /**
424
- * Set the focus to the first element with `autofocus` with the element or the
425
- * element itself
426
- *
427
- * @param {Element} node
428
- */
429
- function moveFocusToDialog(node) {
430
- var focused = node.querySelector('[autofocus]') || node;
431
-
432
- focused.focus();
433
- }
434
-
435
- /**
436
- * Get the focusable children of the given element
437
- *
438
- * @param {Element} node
439
- * @return {Array<Element>}
440
- */
441
- function getFocusableChildren(node) {
442
- return $$(focusableSelectors.join(','), node).filter(function (child) {
443
- return !!(
444
- child.offsetWidth ||
445
- child.offsetHeight ||
446
- child.getClientRects().length
447
- )
448
- })
449
- }
450
-
451
- /**
452
- * Trap the focus inside the given element
453
- *
454
- * @param {Element} node
455
- * @param {Event} event
456
- */
457
- function trapTabKey(node, event) {
458
- var focusableChildren = getFocusableChildren(node);
459
- var focusedItemIndex = focusableChildren.indexOf(document.activeElement);
460
-
461
- // If the SHIFT key is being pressed while tabbing (moving backwards) and
462
- // the currently focused item is the first one, move the focus to the last
463
- // focusable item from the dialog element
464
- if (event.shiftKey && focusedItemIndex === 0) {
465
- focusableChildren[focusableChildren.length - 1].focus();
466
- event.preventDefault();
467
- // If the SHIFT key is not being pressed (moving forwards) and the currently
468
- // focused item is the last one, move the focus to the first focusable item
469
- // from the dialog element
470
- } else if (
471
- !event.shiftKey &&
472
- focusedItemIndex === focusableChildren.length - 1
473
- ) {
474
- focusableChildren[0].focus();
475
- event.preventDefault();
476
- }
477
- }
478
-
479
- function instantiateDialogs() {
480
- $$('[data-a11y-dialog]').forEach(function (node) {
481
- new A11yDialog(node);
482
- });
483
- }
484
-
485
- if (typeof document !== 'undefined') {
486
- if (document.readyState === 'loading') {
487
- document.addEventListener('DOMContentLoaded', instantiateDialogs);
488
- } else {
489
- if (window.requestAnimationFrame) {
490
- window.requestAnimationFrame(instantiateDialogs);
491
- } else {
492
- window.setTimeout(instantiateDialogs, 16);
493
- }
494
- }
495
- }
496
-
497
- /*
498
- * File: iframeResizer.js
499
- * Desc: Force iframes to size to content.
500
- * Requires: iframeResizer.contentWindow.js to be loaded into the target frame.
501
- * Doc: https://github.com/davidjbradshaw/iframe-resizer
502
- * Author: David J. Bradshaw - dave@bradshaw.net
503
- * Contributor: Jure Mav - jure.mav@gmail.com
504
- * Contributor: Reed Dadoune - reed@dadoune.com
505
- */
506
- (function (undefined$1) {
507
- if (typeof window === 'undefined') return // don't run for server side render
508
-
509
- var count = 0,
510
- logEnabled = false,
511
- hiddenCheckEnabled = false,
512
- msgHeader = 'message',
513
- msgHeaderLen = msgHeader.length,
514
- msgId = '[iFrameSizer]', // Must match iframe msg ID
515
- msgIdLen = msgId.length,
516
- pagePosition = null,
517
- requestAnimationFrame = window.requestAnimationFrame,
518
- resetRequiredMethods = Object.freeze({
519
- max: 1,
520
- scroll: 1,
521
- bodyScroll: 1,
522
- documentElementScroll: 1
523
- }),
524
- settings = {},
525
- timer = null,
526
- defaults = Object.freeze({
527
- autoResize: true,
528
- bodyBackground: null,
529
- bodyMargin: null,
530
- bodyMarginV1: 8,
531
- bodyPadding: null,
532
- checkOrigin: true,
533
- inPageLinks: false,
534
- enablePublicMethods: true,
535
- heightCalculationMethod: 'bodyOffset',
536
- id: 'iFrameResizer',
537
- interval: 32,
538
- log: false,
539
- maxHeight: Infinity,
540
- maxWidth: Infinity,
541
- minHeight: 0,
542
- minWidth: 0,
543
- mouseEvents: true,
544
- resizeFrom: 'parent',
545
- scrolling: false,
546
- sizeHeight: true,
547
- sizeWidth: false,
548
- warningTimeout: 5000,
549
- tolerance: 0,
550
- widthCalculationMethod: 'scroll',
551
- onClose: function () {
552
- return true
553
- },
554
- onClosed: function () {},
555
- onInit: function () {},
556
- onMessage: function () {
557
- warn('onMessage function not defined');
558
- },
559
- onMouseEnter: function () {},
560
- onMouseLeave: function () {},
561
- onResized: function () {},
562
- onScroll: function () {
563
- return true
564
- }
565
- });
566
-
567
- function getMutationObserver() {
568
- return (
569
- window.MutationObserver ||
570
- window.WebKitMutationObserver ||
571
- window.MozMutationObserver
572
- )
573
- }
574
-
575
- function addEventListener(el, evt, func) {
576
- el.addEventListener(evt, func, false);
577
- }
578
-
579
- function removeEventListener(el, evt, func) {
580
- el.removeEventListener(evt, func, false);
581
- }
582
-
583
- function setupRequestAnimationFrame() {
584
- var vendors = ['moz', 'webkit', 'o', 'ms'];
585
- var x;
586
-
587
- // Remove vendor prefixing if prefixed and break early if not
588
- for (x = 0; x < vendors.length && !requestAnimationFrame; x += 1) {
589
- requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
590
- }
591
-
592
- if (requestAnimationFrame) {
593
- // Firefox extension content-scripts have a globalThis object that is not the same as window.
594
- // Binding `requestAnimationFrame` to window allows the function to work and prevents errors
595
- // being thrown when run in that context, and should be a no-op in every other context.
596
- requestAnimationFrame = requestAnimationFrame.bind(window);
597
- } else {
598
- log('setup', 'RequestAnimationFrame not supported');
599
- }
600
- }
601
-
602
- function getMyID(iframeId) {
603
- var retStr = 'Host page: ' + iframeId;
604
-
605
- if (window.top !== window.self) {
606
- retStr =
607
- window.parentIFrame && window.parentIFrame.getId
608
- ? window.parentIFrame.getId() + ': ' + iframeId
609
- : 'Nested host page: ' + iframeId;
610
- }
611
-
612
- return retStr
613
- }
614
-
615
- function formatLogHeader(iframeId) {
616
- return msgId + '[' + getMyID(iframeId) + ']'
617
- }
618
-
619
- function isLogEnabled(iframeId) {
620
- return settings[iframeId] ? settings[iframeId].log : logEnabled
621
- }
622
-
623
- function log(iframeId, msg) {
624
- output('log', iframeId, msg, isLogEnabled(iframeId));
625
- }
626
-
627
- function info(iframeId, msg) {
628
- output('info', iframeId, msg, isLogEnabled(iframeId));
629
- }
630
-
631
- function warn(iframeId, msg) {
632
- output('warn', iframeId, msg, true);
633
- }
634
-
635
- function output(type, iframeId, msg, enabled) {
636
- if (true === enabled && 'object' === typeof window.console) {
637
- // eslint-disable-next-line no-console
638
- console[type](formatLogHeader(iframeId), msg);
639
- }
640
- }
641
-
642
- function iFrameListener(event) {
643
- function resizeIFrame() {
644
- function resize() {
645
- setSize(messageData);
646
- setPagePosition(iframeId);
647
- on('onResized', messageData);
648
- }
649
-
650
- ensureInRange('Height');
651
- ensureInRange('Width');
652
-
653
- syncResize(resize, messageData, 'init');
654
- }
655
-
656
- function processMsg() {
657
- var data = msg.slice(msgIdLen).split(':');
658
- var height = data[1] ? parseInt(data[1], 10) : 0;
659
- var iframe = settings[data[0]] && settings[data[0]].iframe;
660
- var compStyle = getComputedStyle(iframe);
661
-
662
- return {
663
- iframe: iframe,
664
- id: data[0],
665
- height: height + getPaddingEnds(compStyle) + getBorderEnds(compStyle),
666
- width: data[2],
667
- type: data[3]
668
- }
669
- }
670
-
671
- function getPaddingEnds(compStyle) {
672
- if (compStyle.boxSizing !== 'border-box') {
673
- return 0
674
- }
675
- var top = compStyle.paddingTop ? parseInt(compStyle.paddingTop, 10) : 0;
676
- var bot = compStyle.paddingBottom
677
- ? parseInt(compStyle.paddingBottom, 10)
678
- : 0;
679
- return top + bot
680
- }
681
-
682
- function getBorderEnds(compStyle) {
683
- if (compStyle.boxSizing !== 'border-box') {
684
- return 0
685
- }
686
- var top = compStyle.borderTopWidth
687
- ? parseInt(compStyle.borderTopWidth, 10)
688
- : 0;
689
- var bot = compStyle.borderBottomWidth
690
- ? parseInt(compStyle.borderBottomWidth, 10)
691
- : 0;
692
- return top + bot
693
- }
694
-
695
- function ensureInRange(Dimension) {
696
- var max = Number(settings[iframeId]['max' + Dimension]),
697
- min = Number(settings[iframeId]['min' + Dimension]),
698
- dimension = Dimension.toLowerCase(),
699
- size = Number(messageData[dimension]);
700
-
701
- log(iframeId, 'Checking ' + dimension + ' is in range ' + min + '-' + max);
702
-
703
- if (size < min) {
704
- size = min;
705
- log(iframeId, 'Set ' + dimension + ' to min value');
706
- }
707
-
708
- if (size > max) {
709
- size = max;
710
- log(iframeId, 'Set ' + dimension + ' to max value');
711
- }
712
-
713
- messageData[dimension] = '' + size;
714
- }
715
-
716
- function isMessageFromIFrame() {
717
- function checkAllowedOrigin() {
718
- function checkList() {
719
- var i = 0,
720
- retCode = false;
721
-
722
- log(
723
- iframeId,
724
- 'Checking connection is from allowed list of origins: ' +
725
- checkOrigin
726
- );
727
-
728
- for (; i < checkOrigin.length; i++) {
729
- if (checkOrigin[i] === origin) {
730
- retCode = true;
731
- break
732
- }
733
- }
734
- return retCode
735
- }
736
-
737
- function checkSingle() {
738
- var remoteHost = settings[iframeId] && settings[iframeId].remoteHost;
739
- log(iframeId, 'Checking connection is from: ' + remoteHost);
740
- return origin === remoteHost
741
- }
742
-
743
- return checkOrigin.constructor === Array ? checkList() : checkSingle()
744
- }
745
-
746
- var origin = event.origin,
747
- checkOrigin = settings[iframeId] && settings[iframeId].checkOrigin;
748
-
749
- if (checkOrigin && '' + origin !== 'null' && !checkAllowedOrigin()) {
750
- throw new Error(
751
- 'Unexpected message received from: ' +
752
- origin +
753
- ' for ' +
754
- messageData.iframe.id +
755
- '. Message was: ' +
756
- event.data +
757
- '. This error can be disabled by setting the checkOrigin: false option or by providing of array of trusted domains.'
758
- )
759
- }
760
-
761
- return true
762
- }
763
-
764
- function isMessageForUs() {
765
- return (
766
- msgId === ('' + msg).slice(0, msgIdLen) &&
767
- msg.slice(msgIdLen).split(':')[0] in settings
768
- ) // ''+Protects against non-string msg
769
- }
770
-
771
- function isMessageFromMetaParent() {
772
- // Test if this message is from a parent above us. This is an ugly test, however, updating
773
- // the message format would break backwards compatibility.
774
- var retCode = messageData.type in { true: 1, false: 1, undefined: 1 };
775
-
776
- if (retCode) {
777
- log(iframeId, 'Ignoring init message from meta parent page');
778
- }
779
-
780
- return retCode
781
- }
782
-
783
- function getMsgBody(offset) {
784
- return msg.slice(msg.indexOf(':') + msgHeaderLen + offset)
785
- }
786
-
787
- function forwardMsgFromIFrame(msgBody) {
788
- log(
789
- iframeId,
790
- 'onMessage passed: {iframe: ' +
791
- messageData.iframe.id +
792
- ', message: ' +
793
- msgBody +
794
- '}'
795
- );
796
-
797
- on('onMessage', {
798
- iframe: messageData.iframe,
799
- message: JSON.parse(msgBody)
800
- });
801
-
802
- log(iframeId, '--');
803
- }
804
-
805
- function getPageInfo() {
806
- var bodyPosition = document.body.getBoundingClientRect(),
807
- iFramePosition = messageData.iframe.getBoundingClientRect();
808
-
809
- return JSON.stringify({
810
- iframeHeight: iFramePosition.height,
811
- iframeWidth: iFramePosition.width,
812
- clientHeight: Math.max(
813
- document.documentElement.clientHeight,
814
- window.innerHeight || 0
815
- ),
816
- clientWidth: Math.max(
817
- document.documentElement.clientWidth,
818
- window.innerWidth || 0
819
- ),
820
- offsetTop: parseInt(iFramePosition.top - bodyPosition.top, 10),
821
- offsetLeft: parseInt(iFramePosition.left - bodyPosition.left, 10),
822
- scrollTop: window.pageYOffset,
823
- scrollLeft: window.pageXOffset,
824
- documentHeight: document.documentElement.clientHeight,
825
- documentWidth: document.documentElement.clientWidth,
826
- windowHeight: window.innerHeight,
827
- windowWidth: window.innerWidth
828
- })
829
- }
830
-
831
- function sendPageInfoToIframe(iframe, iframeId) {
832
- function debouncedTrigger() {
833
- trigger('Send Page Info', 'pageInfo:' + getPageInfo(), iframe, iframeId);
834
- }
835
- debounceFrameEvents(debouncedTrigger, 32, iframeId);
836
- }
837
-
838
- function startPageInfoMonitor() {
839
- function setListener(type, func) {
840
- function sendPageInfo() {
841
- if (settings[id]) {
842
- sendPageInfoToIframe(settings[id].iframe, id);
843
- } else {
844
- stop();
845
- }
846
- }
847
- ['scroll', 'resize'].forEach(function (evt) {
848
- log(id, type + evt + ' listener for sendPageInfo');
849
- func(window, evt, sendPageInfo);
850
- });
851
- }
852
-
853
- function stop() {
854
- setListener('Remove ', removeEventListener);
855
- }
856
-
857
- function start() {
858
- setListener('Add ', addEventListener);
859
- }
860
-
861
- var id = iframeId; // Create locally scoped copy of iFrame ID
862
-
863
- start();
864
-
865
- if (settings[id]) {
866
- settings[id].stopPageInfo = stop;
867
- }
868
- }
869
-
870
- function stopPageInfoMonitor() {
871
- if (settings[iframeId] && settings[iframeId].stopPageInfo) {
872
- settings[iframeId].stopPageInfo();
873
- delete settings[iframeId].stopPageInfo;
874
- }
875
- }
876
-
877
- function checkIFrameExists() {
878
- var retBool = true;
879
-
880
- if (null === messageData.iframe) {
881
- warn(iframeId, 'IFrame (' + messageData.id + ') not found');
882
- retBool = false;
883
- }
884
- return retBool
885
- }
886
-
887
- function getElementPosition(target) {
888
- var iFramePosition = target.getBoundingClientRect();
889
-
890
- getPagePosition(iframeId);
891
-
892
- return {
893
- x: Math.floor(Number(iFramePosition.left) + Number(pagePosition.x)),
894
- y: Math.floor(Number(iFramePosition.top) + Number(pagePosition.y))
895
- }
896
- }
897
-
898
- function scrollRequestFromChild(addOffset) {
899
- /* istanbul ignore next */ // Not testable in Karma
900
- function reposition() {
901
- pagePosition = newPosition;
902
- scrollTo();
903
- log(iframeId, '--');
904
- }
905
-
906
- function calcOffset() {
907
- return {
908
- x: Number(messageData.width) + offset.x,
909
- y: Number(messageData.height) + offset.y
910
- }
911
- }
912
-
913
- function scrollParent() {
914
- if (window.parentIFrame) {
915
- window.parentIFrame['scrollTo' + (addOffset ? 'Offset' : '')](
916
- newPosition.x,
917
- newPosition.y
918
- );
919
- } else {
920
- warn(
921
- iframeId,
922
- 'Unable to scroll to requested position, window.parentIFrame not found'
923
- );
924
- }
925
- }
926
-
927
- var offset = addOffset
928
- ? getElementPosition(messageData.iframe)
929
- : { x: 0, y: 0 },
930
- newPosition = calcOffset();
931
-
932
- log(
933
- iframeId,
934
- 'Reposition requested from iFrame (offset x:' +
935
- offset.x +
936
- ' y:' +
937
- offset.y +
938
- ')'
939
- );
940
-
941
- if (window.top === window.self) {
942
- reposition();
943
- } else {
944
- scrollParent();
945
- }
946
- }
947
-
948
- function scrollTo() {
949
- if (false === on('onScroll', pagePosition)) {
950
- unsetPagePosition();
951
- } else {
952
- setPagePosition(iframeId);
953
- }
954
- }
955
-
956
- function findTarget(location) {
957
- function jumpToTarget() {
958
- var jumpPosition = getElementPosition(target);
959
-
960
- log(
961
- iframeId,
962
- 'Moving to in page link (#' +
963
- hash +
964
- ') at x: ' +
965
- jumpPosition.x +
966
- ' y: ' +
967
- jumpPosition.y
968
- );
969
- pagePosition = {
970
- x: jumpPosition.x,
971
- y: jumpPosition.y
972
- };
973
-
974
- scrollTo();
975
- log(iframeId, '--');
976
- }
977
-
978
- function jumpToParent() {
979
- if (window.parentIFrame) {
980
- window.parentIFrame.moveToAnchor(hash);
981
- } else {
982
- log(
983
- iframeId,
984
- 'In page link #' +
985
- hash +
986
- ' not found and window.parentIFrame not found'
987
- );
988
- }
989
- }
990
-
991
- var hash = location.split('#')[1] || '',
992
- hashData = decodeURIComponent(hash),
993
- target =
994
- document.getElementById(hashData) ||
995
- document.getElementsByName(hashData)[0];
996
-
997
- if (target) {
998
- jumpToTarget();
999
- } else if (window.top === window.self) {
1000
- log(iframeId, 'In page link #' + hash + ' not found');
1001
- } else {
1002
- jumpToParent();
1003
- }
1004
- }
1005
-
1006
- function onMouse(event) {
1007
- var mousePos = {};
1008
-
1009
- if (Number(messageData.width) === 0 && Number(messageData.height) === 0) {
1010
- var data = getMsgBody(9).split(':');
1011
- mousePos = {
1012
- x: data[1],
1013
- y: data[0]
1014
- };
1015
- } else {
1016
- mousePos = {
1017
- x: messageData.width,
1018
- y: messageData.height
1019
- };
1020
- }
1021
-
1022
- on(event, {
1023
- iframe: messageData.iframe,
1024
- screenX: Number(mousePos.x),
1025
- screenY: Number(mousePos.y),
1026
- type: messageData.type
1027
- });
1028
- }
1029
-
1030
- function on(funcName, val) {
1031
- return chkEvent(iframeId, funcName, val)
1032
- }
1033
-
1034
- function actionMsg() {
1035
- if (settings[iframeId] && settings[iframeId].firstRun) firstRun();
1036
-
1037
- switch (messageData.type) {
1038
- case 'close': {
1039
- closeIFrame(messageData.iframe);
1040
- break
1041
- }
1042
-
1043
- case 'message': {
1044
- forwardMsgFromIFrame(getMsgBody(6));
1045
- break
1046
- }
1047
-
1048
- case 'mouseenter': {
1049
- onMouse('onMouseEnter');
1050
- break
1051
- }
1052
-
1053
- case 'mouseleave': {
1054
- onMouse('onMouseLeave');
1055
- break
1056
- }
1057
-
1058
- case 'autoResize': {
1059
- settings[iframeId].autoResize = JSON.parse(getMsgBody(9));
1060
- break
1061
- }
1062
-
1063
- case 'scrollTo': {
1064
- scrollRequestFromChild(false);
1065
- break
1066
- }
1067
-
1068
- case 'scrollToOffset': {
1069
- scrollRequestFromChild(true);
1070
- break
1071
- }
1072
-
1073
- case 'pageInfo': {
1074
- sendPageInfoToIframe(
1075
- settings[iframeId] && settings[iframeId].iframe,
1076
- iframeId
1077
- );
1078
- startPageInfoMonitor();
1079
- break
1080
- }
1081
-
1082
- case 'pageInfoStop': {
1083
- stopPageInfoMonitor();
1084
- break
1085
- }
1086
-
1087
- case 'inPageLink': {
1088
- findTarget(getMsgBody(9));
1089
- break
1090
- }
1091
-
1092
- case 'reset': {
1093
- resetIFrame(messageData);
1094
- break
1095
- }
1096
-
1097
- case 'init': {
1098
- resizeIFrame();
1099
- on('onInit', messageData.iframe);
1100
- break
1101
- }
1102
-
1103
- default: {
1104
- if (
1105
- Number(messageData.width) === 0 &&
1106
- Number(messageData.height) === 0
1107
- ) {
1108
- warn(
1109
- 'Unsupported message received (' +
1110
- messageData.type +
1111
- '), this is likely due to the iframe containing a later ' +
1112
- 'version of iframe-resizer than the parent page'
1113
- );
1114
- } else {
1115
- resizeIFrame();
1116
- }
1117
- }
1118
- }
1119
- }
1120
-
1121
- function hasSettings(iframeId) {
1122
- var retBool = true;
1123
-
1124
- if (!settings[iframeId]) {
1125
- retBool = false;
1126
- warn(
1127
- messageData.type +
1128
- ' No settings for ' +
1129
- iframeId +
1130
- '. Message was: ' +
1131
- msg
1132
- );
1133
- }
1134
-
1135
- return retBool
1136
- }
1137
-
1138
- function iFrameReadyMsgReceived() {
1139
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
1140
- for (var iframeId in settings) {
1141
- trigger(
1142
- 'iFrame requested init',
1143
- createOutgoingMsg(iframeId),
1144
- settings[iframeId].iframe,
1145
- iframeId
1146
- );
1147
- }
1148
- }
1149
-
1150
- function firstRun() {
1151
- if (settings[iframeId]) {
1152
- settings[iframeId].firstRun = false;
1153
- }
1154
- }
1155
-
1156
- var msg = event.data,
1157
- messageData = {},
1158
- iframeId = null;
1159
-
1160
- if ('[iFrameResizerChild]Ready' === msg) {
1161
- iFrameReadyMsgReceived();
1162
- } else if (isMessageForUs()) {
1163
- messageData = processMsg();
1164
- iframeId = messageData.id;
1165
- if (settings[iframeId]) {
1166
- settings[iframeId].loaded = true;
1167
- }
1168
-
1169
- if (!isMessageFromMetaParent() && hasSettings(iframeId)) {
1170
- log(iframeId, 'Received: ' + msg);
1171
-
1172
- if (checkIFrameExists() && isMessageFromIFrame()) {
1173
- actionMsg();
1174
- }
1175
- }
1176
- } else {
1177
- info(iframeId, 'Ignored: ' + msg);
1178
- }
1179
- }
1180
-
1181
- function chkEvent(iframeId, funcName, val) {
1182
- var func = null,
1183
- retVal = null;
1184
-
1185
- if (settings[iframeId]) {
1186
- func = settings[iframeId][funcName];
1187
-
1188
- if ('function' === typeof func) {
1189
- retVal = func(val);
1190
- } else {
1191
- throw new TypeError(
1192
- funcName + ' on iFrame[' + iframeId + '] is not a function'
1193
- )
1194
- }
1195
- }
1196
-
1197
- return retVal
1198
- }
1199
-
1200
- function removeIframeListeners(iframe) {
1201
- var iframeId = iframe.id;
1202
- delete settings[iframeId];
1203
- }
1204
-
1205
- function closeIFrame(iframe) {
1206
- var iframeId = iframe.id;
1207
- if (chkEvent(iframeId, 'onClose', iframeId) === false) {
1208
- log(iframeId, 'Close iframe cancelled by onClose event');
1209
- return
1210
- }
1211
- log(iframeId, 'Removing iFrame: ' + iframeId);
1212
-
1213
- try {
1214
- // Catch race condition error with React
1215
- if (iframe.parentNode) {
1216
- iframe.parentNode.removeChild(iframe);
1217
- }
1218
- } catch (error) {
1219
- warn(error);
1220
- }
1221
-
1222
- chkEvent(iframeId, 'onClosed', iframeId);
1223
- log(iframeId, '--');
1224
- removeIframeListeners(iframe);
1225
- }
1226
-
1227
- function getPagePosition(iframeId) {
1228
- if (null === pagePosition) {
1229
- pagePosition = {
1230
- x:
1231
- window.pageXOffset === undefined$1
1232
- ? document.documentElement.scrollLeft
1233
- : window.pageXOffset,
1234
- y:
1235
- window.pageYOffset === undefined$1
1236
- ? document.documentElement.scrollTop
1237
- : window.pageYOffset
1238
- };
1239
- log(
1240
- iframeId,
1241
- 'Get page position: ' + pagePosition.x + ',' + pagePosition.y
1242
- );
1243
- }
1244
- }
1245
-
1246
- function setPagePosition(iframeId) {
1247
- if (null !== pagePosition) {
1248
- window.scrollTo(pagePosition.x, pagePosition.y);
1249
- log(
1250
- iframeId,
1251
- 'Set page position: ' + pagePosition.x + ',' + pagePosition.y
1252
- );
1253
- unsetPagePosition();
1254
- }
1255
- }
1256
-
1257
- function unsetPagePosition() {
1258
- pagePosition = null;
1259
- }
1260
-
1261
- function resetIFrame(messageData) {
1262
- function reset() {
1263
- setSize(messageData);
1264
- trigger('reset', 'reset', messageData.iframe, messageData.id);
1265
- }
1266
-
1267
- log(
1268
- messageData.id,
1269
- 'Size reset requested by ' +
1270
- ('init' === messageData.type ? 'host page' : 'iFrame')
1271
- );
1272
- getPagePosition(messageData.id);
1273
- syncResize(reset, messageData, 'reset');
1274
- }
1275
-
1276
- function setSize(messageData) {
1277
- function setDimension(dimension) {
1278
- if (!messageData.id) {
1279
- log('undefined', 'messageData id not set');
1280
- return
1281
- }
1282
- messageData.iframe.style[dimension] = messageData[dimension] + 'px';
1283
- log(
1284
- messageData.id,
1285
- 'IFrame (' +
1286
- iframeId +
1287
- ') ' +
1288
- dimension +
1289
- ' set to ' +
1290
- messageData[dimension] +
1291
- 'px'
1292
- );
1293
- }
1294
-
1295
- function chkZero(dimension) {
1296
- // FireFox sets dimension of hidden iFrames to zero.
1297
- // So if we detect that set up an event to check for
1298
- // when iFrame becomes visible.
1299
-
1300
- /* istanbul ignore next */ // Not testable in PhantomJS
1301
- if (!hiddenCheckEnabled && '0' === messageData[dimension]) {
1302
- hiddenCheckEnabled = true;
1303
- log(iframeId, 'Hidden iFrame detected, creating visibility listener');
1304
- fixHiddenIFrames();
1305
- }
1306
- }
1307
-
1308
- function processDimension(dimension) {
1309
- setDimension(dimension);
1310
- chkZero(dimension);
1311
- }
1312
-
1313
- var iframeId = messageData.iframe.id;
1314
-
1315
- if (settings[iframeId]) {
1316
- if (settings[iframeId].sizeHeight) {
1317
- processDimension('height');
1318
- }
1319
- if (settings[iframeId].sizeWidth) {
1320
- processDimension('width');
1321
- }
1322
- }
1323
- }
1324
-
1325
- function syncResize(func, messageData, doNotSync) {
1326
- /* istanbul ignore if */ // Not testable in PhantomJS
1327
- if (
1328
- doNotSync !== messageData.type &&
1329
- requestAnimationFrame &&
1330
- // including check for jasmine because had trouble getting spy to work in unit test using requestAnimationFrame
1331
- !window.jasmine
1332
- ) {
1333
- log(messageData.id, 'Requesting animation frame');
1334
- requestAnimationFrame(func);
1335
- } else {
1336
- func();
1337
- }
1338
- }
1339
-
1340
- function trigger(calleeMsg, msg, iframe, id, noResponseWarning) {
1341
- function postMessageToIFrame() {
1342
- var target = settings[id] && settings[id].targetOrigin;
1343
- log(
1344
- id,
1345
- '[' +
1346
- calleeMsg +
1347
- '] Sending msg to iframe[' +
1348
- id +
1349
- '] (' +
1350
- msg +
1351
- ') targetOrigin: ' +
1352
- target
1353
- );
1354
- iframe.contentWindow.postMessage(msgId + msg, target);
1355
- }
1356
-
1357
- function iFrameNotFound() {
1358
- warn(id, '[' + calleeMsg + '] IFrame(' + id + ') not found');
1359
- }
1360
-
1361
- function chkAndSend() {
1362
- if (
1363
- iframe &&
1364
- 'contentWindow' in iframe &&
1365
- null !== iframe.contentWindow
1366
- ) {
1367
- // Null test for PhantomJS
1368
- postMessageToIFrame();
1369
- } else {
1370
- iFrameNotFound();
1371
- }
1372
- }
1373
-
1374
- function warnOnNoResponse() {
1375
- function warning() {
1376
- if (settings[id] && !settings[id].loaded && !errorShown) {
1377
- errorShown = true;
1378
- warn(
1379
- id,
1380
- 'IFrame has not responded within ' +
1381
- settings[id].warningTimeout / 1000 +
1382
- ' seconds. Check iFrameResizer.contentWindow.js has been loaded in iFrame. This message can be ignored if everything is working, or you can set the warningTimeout option to a higher value or zero to suppress this warning.'
1383
- );
1384
- }
1385
- }
1386
-
1387
- if (
1388
- !!noResponseWarning &&
1389
- settings[id] &&
1390
- !!settings[id].warningTimeout
1391
- ) {
1392
- settings[id].msgTimeout = setTimeout(
1393
- warning,
1394
- settings[id].warningTimeout
1395
- );
1396
- }
1397
- }
1398
-
1399
- var errorShown = false;
1400
-
1401
- id = id || iframe.id;
1402
-
1403
- if (settings[id]) {
1404
- chkAndSend();
1405
- warnOnNoResponse();
1406
- }
1407
- }
1408
-
1409
- function createOutgoingMsg(iframeId) {
1410
- return (
1411
- iframeId +
1412
- ':' +
1413
- settings[iframeId].bodyMarginV1 +
1414
- ':' +
1415
- settings[iframeId].sizeWidth +
1416
- ':' +
1417
- settings[iframeId].log +
1418
- ':' +
1419
- settings[iframeId].interval +
1420
- ':' +
1421
- settings[iframeId].enablePublicMethods +
1422
- ':' +
1423
- settings[iframeId].autoResize +
1424
- ':' +
1425
- settings[iframeId].bodyMargin +
1426
- ':' +
1427
- settings[iframeId].heightCalculationMethod +
1428
- ':' +
1429
- settings[iframeId].bodyBackground +
1430
- ':' +
1431
- settings[iframeId].bodyPadding +
1432
- ':' +
1433
- settings[iframeId].tolerance +
1434
- ':' +
1435
- settings[iframeId].inPageLinks +
1436
- ':' +
1437
- settings[iframeId].resizeFrom +
1438
- ':' +
1439
- settings[iframeId].widthCalculationMethod +
1440
- ':' +
1441
- settings[iframeId].mouseEvents
1442
- )
1443
- }
1444
-
1445
- function isNumber(value) {
1446
- return typeof value === 'number'
1447
- }
1448
-
1449
- function setupIFrame(iframe, options) {
1450
- function setLimits() {
1451
- function addStyle(style) {
1452
- var styleValue = settings[iframeId][style];
1453
- if (Infinity !== styleValue && 0 !== styleValue) {
1454
- iframe.style[style] = isNumber(styleValue)
1455
- ? styleValue + 'px'
1456
- : styleValue;
1457
- log(iframeId, 'Set ' + style + ' = ' + iframe.style[style]);
1458
- }
1459
- }
1460
-
1461
- function chkMinMax(dimension) {
1462
- if (
1463
- settings[iframeId]['min' + dimension] >
1464
- settings[iframeId]['max' + dimension]
1465
- ) {
1466
- throw new Error(
1467
- 'Value for min' +
1468
- dimension +
1469
- ' can not be greater than max' +
1470
- dimension
1471
- )
1472
- }
1473
- }
1474
-
1475
- chkMinMax('Height');
1476
- chkMinMax('Width');
1477
-
1478
- addStyle('maxHeight');
1479
- addStyle('minHeight');
1480
- addStyle('maxWidth');
1481
- addStyle('minWidth');
1482
- }
1483
-
1484
- function newId() {
1485
- var id = (options && options.id) || defaults.id + count++;
1486
- if (null !== document.getElementById(id)) {
1487
- id += count++;
1488
- }
1489
- return id
1490
- }
1491
-
1492
- function ensureHasId(iframeId) {
1493
- if (typeof iframeId !== 'string') {
1494
- throw new TypeError('Invaild id for iFrame. Expected String')
1495
- }
1496
-
1497
- if ('' === iframeId) {
1498
- // eslint-disable-next-line no-multi-assign
1499
- iframe.id = iframeId = newId();
1500
- logEnabled = (options || {}).log;
1501
- log(
1502
- iframeId,
1503
- 'Added missing iframe ID: ' + iframeId + ' (' + iframe.src + ')'
1504
- );
1505
- }
1506
-
1507
- return iframeId
1508
- }
1509
-
1510
- function setScrolling() {
1511
- log(
1512
- iframeId,
1513
- 'IFrame scrolling ' +
1514
- (settings[iframeId] && settings[iframeId].scrolling
1515
- ? 'enabled'
1516
- : 'disabled') +
1517
- ' for ' +
1518
- iframeId
1519
- );
1520
- iframe.style.overflow =
1521
- false === (settings[iframeId] && settings[iframeId].scrolling)
1522
- ? 'hidden'
1523
- : 'auto';
1524
- switch (settings[iframeId] && settings[iframeId].scrolling) {
1525
- case 'omit': {
1526
- break
1527
- }
1528
-
1529
- case true: {
1530
- iframe.scrolling = 'yes';
1531
- break
1532
- }
1533
-
1534
- case false: {
1535
- iframe.scrolling = 'no';
1536
- break
1537
- }
1538
-
1539
- default: {
1540
- iframe.scrolling = settings[iframeId]
1541
- ? settings[iframeId].scrolling
1542
- : 'no';
1543
- }
1544
- }
1545
- }
1546
-
1547
- // The V1 iFrame script expects an int, where as in V2 expects a CSS
1548
- // string value such as '1px 3em', so if we have an int for V2, set V1=V2
1549
- // and then convert V2 to a string PX value.
1550
- function setupBodyMarginValues() {
1551
- if (
1552
- 'number' ===
1553
- typeof (settings[iframeId] && settings[iframeId].bodyMargin) ||
1554
- '0' === (settings[iframeId] && settings[iframeId].bodyMargin)
1555
- ) {
1556
- settings[iframeId].bodyMarginV1 = settings[iframeId].bodyMargin;
1557
- settings[iframeId].bodyMargin =
1558
- '' + settings[iframeId].bodyMargin + 'px';
1559
- }
1560
- }
1561
-
1562
- function checkReset() {
1563
- // Reduce scope of firstRun to function, because IE8's JS execution
1564
- // context stack is borked and this value gets externally
1565
- // changed midway through running this function!!!
1566
- var firstRun = settings[iframeId] && settings[iframeId].firstRun,
1567
- resetRequertMethod =
1568
- settings[iframeId] &&
1569
- settings[iframeId].heightCalculationMethod in resetRequiredMethods;
1570
-
1571
- if (!firstRun && resetRequertMethod) {
1572
- resetIFrame({ iframe: iframe, height: 0, width: 0, type: 'init' });
1573
- }
1574
- }
1575
-
1576
- function setupIFrameObject() {
1577
- if (settings[iframeId]) {
1578
- settings[iframeId].iframe.iFrameResizer = {
1579
- close: closeIFrame.bind(null, settings[iframeId].iframe),
1580
-
1581
- removeListeners: removeIframeListeners.bind(
1582
- null,
1583
- settings[iframeId].iframe
1584
- ),
1585
-
1586
- resize: trigger.bind(
1587
- null,
1588
- 'Window resize',
1589
- 'resize',
1590
- settings[iframeId].iframe
1591
- ),
1592
-
1593
- moveToAnchor: function (anchor) {
1594
- trigger(
1595
- 'Move to anchor',
1596
- 'moveToAnchor:' + anchor,
1597
- settings[iframeId].iframe,
1598
- iframeId
1599
- );
1600
- },
1601
-
1602
- sendMessage: function (message) {
1603
- message = JSON.stringify(message);
1604
- trigger(
1605
- 'Send Message',
1606
- 'message:' + message,
1607
- settings[iframeId].iframe,
1608
- iframeId
1609
- );
1610
- }
1611
- };
1612
- }
1613
- }
1614
-
1615
- // We have to call trigger twice, as we can not be sure if all
1616
- // iframes have completed loading when this code runs. The
1617
- // event listener also catches the page changing in the iFrame.
1618
- function init(msg) {
1619
- function iFrameLoaded() {
1620
- trigger('iFrame.onload', msg, iframe, undefined$1, true);
1621
- checkReset();
1622
- }
1623
-
1624
- function createDestroyObserver(MutationObserver) {
1625
- if (!iframe.parentNode) {
1626
- return
1627
- }
1628
-
1629
- var destroyObserver = new MutationObserver(function (mutations) {
1630
- mutations.forEach(function (mutation) {
1631
- var removedNodes = Array.prototype.slice.call(mutation.removedNodes); // Transform NodeList into an Array
1632
- removedNodes.forEach(function (removedNode) {
1633
- if (removedNode === iframe) {
1634
- closeIFrame(iframe);
1635
- }
1636
- });
1637
- });
1638
- });
1639
- destroyObserver.observe(iframe.parentNode, {
1640
- childList: true
1641
- });
1642
- }
1643
-
1644
- var MutationObserver = getMutationObserver();
1645
- if (MutationObserver) {
1646
- createDestroyObserver(MutationObserver);
1647
- }
1648
-
1649
- addEventListener(iframe, 'load', iFrameLoaded);
1650
- trigger('init', msg, iframe, undefined$1, true);
1651
- }
1652
-
1653
- function checkOptions(options) {
1654
- if ('object' !== typeof options) {
1655
- throw new TypeError('Options is not an object')
1656
- }
1657
- }
1658
-
1659
- function copyOptions(options) {
1660
- // eslint-disable-next-line no-restricted-syntax
1661
- for (var option in defaults) {
1662
- if (Object.prototype.hasOwnProperty.call(defaults, option)) {
1663
- settings[iframeId][option] = Object.prototype.hasOwnProperty.call(
1664
- options,
1665
- option
1666
- )
1667
- ? options[option]
1668
- : defaults[option];
1669
- }
1670
- }
1671
- }
1672
-
1673
- function getTargetOrigin(remoteHost) {
1674
- return '' === remoteHost ||
1675
- null !== remoteHost.match(/^(about:blank|javascript:|file:\/\/)/)
1676
- ? '*'
1677
- : remoteHost
1678
- }
1679
-
1680
- function depricate(key) {
1681
- var splitName = key.split('Callback');
1682
-
1683
- if (splitName.length === 2) {
1684
- var name =
1685
- 'on' + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1);
1686
- this[name] = this[key];
1687
- delete this[key];
1688
- warn(
1689
- iframeId,
1690
- "Deprecated: '" +
1691
- key +
1692
- "' has been renamed '" +
1693
- name +
1694
- "'. The old method will be removed in the next major version."
1695
- );
1696
- }
1697
- }
1698
-
1699
- function processOptions(options) {
1700
- options = options || {};
1701
-
1702
- settings[iframeId] = Object.create(null); // Protect against prototype attacks
1703
- settings[iframeId].iframe = iframe;
1704
- settings[iframeId].firstRun = true;
1705
- settings[iframeId].remoteHost =
1706
- iframe.src && iframe.src.split('/').slice(0, 3).join('/');
1707
-
1708
- checkOptions(options);
1709
- Object.keys(options).forEach(depricate, options);
1710
- copyOptions(options);
1711
-
1712
- if (settings[iframeId]) {
1713
- settings[iframeId].targetOrigin =
1714
- true === settings[iframeId].checkOrigin
1715
- ? getTargetOrigin(settings[iframeId].remoteHost)
1716
- : '*';
1717
- }
1718
- }
1719
-
1720
- function beenHere() {
1721
- return iframeId in settings && 'iFrameResizer' in iframe
1722
- }
1723
-
1724
- var iframeId = ensureHasId(iframe.id);
1725
-
1726
- if (beenHere()) {
1727
- warn(iframeId, 'Ignored iFrame, already setup.');
1728
- } else {
1729
- processOptions(options);
1730
- setScrolling();
1731
- setLimits();
1732
- setupBodyMarginValues();
1733
- init(createOutgoingMsg(iframeId));
1734
- setupIFrameObject();
1735
- }
1736
- }
1737
-
1738
- function debouce(fn, time) {
1739
- if (null === timer) {
1740
- timer = setTimeout(function () {
1741
- timer = null;
1742
- fn();
1743
- }, time);
1744
- }
1745
- }
1746
-
1747
- var frameTimer = {};
1748
- function debounceFrameEvents(fn, time, frameId) {
1749
- if (!frameTimer[frameId]) {
1750
- frameTimer[frameId] = setTimeout(function () {
1751
- frameTimer[frameId] = null;
1752
- fn();
1753
- }, time);
1754
- }
1755
- }
1756
-
1757
- // Not testable in PhantomJS
1758
- /* istanbul ignore next */
1759
-
1760
- function fixHiddenIFrames() {
1761
- function checkIFrames() {
1762
- function checkIFrame(settingId) {
1763
- function chkDimension(dimension) {
1764
- return (
1765
- '0px' ===
1766
- (settings[settingId] && settings[settingId].iframe.style[dimension])
1767
- )
1768
- }
1769
-
1770
- function isVisible(el) {
1771
- return null !== el.offsetParent
1772
- }
1773
-
1774
- if (
1775
- settings[settingId] &&
1776
- isVisible(settings[settingId].iframe) &&
1777
- (chkDimension('height') || chkDimension('width'))
1778
- ) {
1779
- trigger(
1780
- 'Visibility change',
1781
- 'resize',
1782
- settings[settingId].iframe,
1783
- settingId
1784
- );
1785
- }
1786
- }
1787
-
1788
- Object.keys(settings).forEach(function (key) {
1789
- checkIFrame(key);
1790
- });
1791
- }
1792
-
1793
- function mutationObserved(mutations) {
1794
- log(
1795
- 'window',
1796
- 'Mutation observed: ' + mutations[0].target + ' ' + mutations[0].type
1797
- );
1798
- debouce(checkIFrames, 16);
1799
- }
1800
-
1801
- function createMutationObserver() {
1802
- var target = document.querySelector('body'),
1803
- config = {
1804
- attributes: true,
1805
- attributeOldValue: false,
1806
- characterData: true,
1807
- characterDataOldValue: false,
1808
- childList: true,
1809
- subtree: true
1810
- },
1811
- observer = new MutationObserver(mutationObserved);
1812
-
1813
- observer.observe(target, config);
1814
- }
1815
-
1816
- var MutationObserver = getMutationObserver();
1817
- if (MutationObserver) {
1818
- createMutationObserver();
1819
- }
1820
- }
1821
-
1822
- function resizeIFrames(event) {
1823
- function resize() {
1824
- sendTriggerMsg('Window ' + event, 'resize');
1825
- }
1826
-
1827
- log('window', 'Trigger event: ' + event);
1828
- debouce(resize, 16);
1829
- }
1830
-
1831
- // Not testable in PhantomJS
1832
- /* istanbul ignore next */
1833
- function tabVisible() {
1834
- function resize() {
1835
- sendTriggerMsg('Tab Visible', 'resize');
1836
- }
1837
-
1838
- if ('hidden' !== document.visibilityState) {
1839
- log('document', 'Trigger event: Visibility change');
1840
- debouce(resize, 16);
1841
- }
1842
- }
1843
-
1844
- function sendTriggerMsg(eventName, event) {
1845
- function isIFrameResizeEnabled(iframeId) {
1846
- return (
1847
- settings[iframeId] &&
1848
- 'parent' === settings[iframeId].resizeFrom &&
1849
- settings[iframeId].autoResize &&
1850
- !settings[iframeId].firstRun
1851
- )
1852
- }
1853
-
1854
- Object.keys(settings).forEach(function (iframeId) {
1855
- if (isIFrameResizeEnabled(iframeId)) {
1856
- trigger(eventName, event, settings[iframeId].iframe, iframeId);
1857
- }
1858
- });
1859
- }
1860
-
1861
- function setupEventListeners() {
1862
- addEventListener(window, 'message', iFrameListener);
1863
-
1864
- addEventListener(window, 'resize', function () {
1865
- resizeIFrames('resize');
1866
- });
1867
-
1868
- addEventListener(document, 'visibilitychange', tabVisible);
1869
-
1870
- addEventListener(document, '-webkit-visibilitychange', tabVisible);
1871
- }
1872
-
1873
- function factory() {
1874
- function init(options, element) {
1875
- function chkType() {
1876
- if (!element.tagName) {
1877
- throw new TypeError('Object is not a valid DOM element')
1878
- } else if ('IFRAME' !== element.tagName.toUpperCase()) {
1879
- throw new TypeError(
1880
- 'Expected <IFRAME> tag, found <' + element.tagName + '>'
1881
- )
1882
- }
1883
- }
1884
-
1885
- if (element) {
1886
- chkType();
1887
- setupIFrame(element, options);
1888
- iFrames.push(element);
1889
- }
1890
- }
1891
-
1892
- function warnDeprecatedOptions(options) {
1893
- if (options && options.enablePublicMethods) {
1894
- warn(
1895
- 'enablePublicMethods option has been removed, public methods are now always available in the iFrame'
1896
- );
1897
- }
1898
- }
1899
-
1900
- var iFrames;
1901
-
1902
- setupRequestAnimationFrame();
1903
- setupEventListeners();
1904
-
1905
- return function iFrameResizeF(options, target) {
1906
- iFrames = []; // Only return iFrames past in on this call
1907
-
1908
- warnDeprecatedOptions(options);
1909
-
1910
- switch (typeof target) {
1911
- case 'undefined':
1912
- case 'string': {
1913
- Array.prototype.forEach.call(
1914
- document.querySelectorAll(target || 'iframe'),
1915
- init.bind(undefined$1, options)
1916
- );
1917
- break
1918
- }
1919
-
1920
- case 'object': {
1921
- init(options, target);
1922
- break
1923
- }
1924
-
1925
- default: {
1926
- throw new TypeError('Unexpected data type (' + typeof target + ')')
1927
- }
1928
- }
1929
-
1930
- return iFrames
1931
- }
1932
- }
1933
-
1934
- function createJQueryPublicMethod($) {
1935
- if (!$.fn) {
1936
- info('', 'Unable to bind to jQuery, it is not fully loaded.');
1937
- } else if (!$.fn.iFrameResize) {
1938
- $.fn.iFrameResize = function $iFrameResizeF(options) {
1939
- function init(index, element) {
1940
- setupIFrame(element, options);
1941
- }
1942
-
1943
- return this.filter('iframe').each(init).end()
1944
- };
1945
- }
1946
- }
1947
-
1948
- if (window.jQuery !== undefined$1) {
1949
- createJQueryPublicMethod(window.jQuery);
1950
- }
1951
-
1952
- if (typeof define === 'function' && define.amd) {
1953
- define([], factory);
1954
- } else if (typeof module === 'object' && typeof module.exports === 'object') {
1955
- // Node for browserfy
1956
- module.exports = factory();
1957
- }
1958
- window.iFrameResize = window.iFrameResize || factory();
1959
- })();
1960
-
1961
- /*
1962
- * File: iframeResizer.contentWindow.js
1963
- * Desc: Include this file in any page being loaded into an iframe
1964
- * to force the iframe to resize to the content size.
1965
- * Requires: iframeResizer.js on host page.
1966
- * Doc: https://github.com/davidjbradshaw/iframe-resizer
1967
- * Author: David J. Bradshaw - dave@bradshaw.net
1968
- *
1969
- */
1970
- (function (undefined$1) {
1971
- if (typeof window === 'undefined') return // don't run for server side render
1972
-
1973
- var autoResize = true,
1974
- base = 10,
1975
- bodyBackground = '',
1976
- bodyMargin = 0,
1977
- bodyMarginStr = '',
1978
- bodyObserver = null,
1979
- bodyPadding = '',
1980
- calculateWidth = false,
1981
- doubleEventList = { resize: 1, click: 1 },
1982
- eventCancelTimer = 128,
1983
- firstRun = true,
1984
- height = 1,
1985
- heightCalcModeDefault = 'bodyOffset',
1986
- heightCalcMode = heightCalcModeDefault,
1987
- initLock = true,
1988
- initMsg = '',
1989
- inPageLinks = {},
1990
- interval = 32,
1991
- intervalTimer = null,
1992
- logging = false,
1993
- mouseEvents = false,
1994
- msgID = '[iFrameSizer]', // Must match host page msg ID
1995
- msgIdLen = msgID.length,
1996
- myID = '',
1997
- resetRequiredMethods = {
1998
- max: 1,
1999
- min: 1,
2000
- bodyScroll: 1,
2001
- documentElementScroll: 1
2002
- },
2003
- resizeFrom = 'child',
2004
- target = window.parent,
2005
- targetOriginDefault = '*',
2006
- tolerance = 0,
2007
- triggerLocked = false,
2008
- triggerLockedTimer = null,
2009
- throttledTimer = 16,
2010
- width = 1,
2011
- widthCalcModeDefault = 'scroll',
2012
- widthCalcMode = widthCalcModeDefault,
2013
- win = window,
2014
- onMessage = function () {
2015
- warn('onMessage function not defined');
2016
- },
2017
- onReady = function () {},
2018
- onPageInfo = function () {},
2019
- customCalcMethods = {
2020
- height: function () {
2021
- warn('Custom height calculation function not defined');
2022
- return document.documentElement.offsetHeight
2023
- },
2024
- width: function () {
2025
- warn('Custom width calculation function not defined');
2026
- return document.body.scrollWidth
2027
- }
2028
- },
2029
- eventHandlersByName = {},
2030
- passiveSupported = false;
2031
-
2032
- function noop() {}
2033
-
2034
- try {
2035
- var options = Object.create(
2036
- {},
2037
- {
2038
- passive: {
2039
- // eslint-disable-next-line getter-return
2040
- get: function () {
2041
- passiveSupported = true;
2042
- }
2043
- }
2044
- }
2045
- );
2046
- window.addEventListener('test', noop, options);
2047
- window.removeEventListener('test', noop, options);
2048
- } catch (error) {
2049
- /* */
2050
- }
2051
-
2052
- function addEventListener(el, evt, func, options) {
2053
- el.addEventListener(evt, func, passiveSupported ? options || {} : false);
2054
- }
2055
-
2056
- function removeEventListener(el, evt, func) {
2057
- el.removeEventListener(evt, func, false);
2058
- }
2059
-
2060
- function capitalizeFirstLetter(string) {
2061
- return string.charAt(0).toUpperCase() + string.slice(1)
2062
- }
2063
-
2064
- // Based on underscore.js
2065
- function throttle(func) {
2066
- var context,
2067
- args,
2068
- result,
2069
- timeout = null,
2070
- previous = 0,
2071
- later = function () {
2072
- previous = Date.now();
2073
- timeout = null;
2074
- result = func.apply(context, args);
2075
- if (!timeout) {
2076
- // eslint-disable-next-line no-multi-assign
2077
- context = args = null;
2078
- }
2079
- };
2080
-
2081
- return function () {
2082
- var now = Date.now();
2083
-
2084
- if (!previous) {
2085
- previous = now;
2086
- }
2087
-
2088
- var remaining = throttledTimer - (now - previous);
2089
-
2090
- context = this;
2091
- args = arguments;
2092
-
2093
- if (remaining <= 0 || remaining > throttledTimer) {
2094
- if (timeout) {
2095
- clearTimeout(timeout);
2096
- timeout = null;
2097
- }
2098
-
2099
- previous = now;
2100
- result = func.apply(context, args);
2101
-
2102
- if (!timeout) {
2103
- // eslint-disable-next-line no-multi-assign
2104
- context = args = null;
2105
- }
2106
- } else if (!timeout) {
2107
- timeout = setTimeout(later, remaining);
2108
- }
2109
-
2110
- return result
2111
- }
2112
- }
2113
-
2114
- function formatLogMsg(msg) {
2115
- return msgID + '[' + myID + '] ' + msg
2116
- }
2117
-
2118
- function log(msg) {
2119
- if (logging && 'object' === typeof window.console) {
2120
- // eslint-disable-next-line no-console
2121
- console.log(formatLogMsg(msg));
2122
- }
2123
- }
2124
-
2125
- function warn(msg) {
2126
- if ('object' === typeof window.console) {
2127
- // eslint-disable-next-line no-console
2128
- console.warn(formatLogMsg(msg));
2129
- }
2130
- }
2131
-
2132
- function init() {
2133
- readDataFromParent();
2134
- log('Initialising iFrame (' + window.location.href + ')');
2135
- readDataFromPage();
2136
- setMargin();
2137
- setBodyStyle('background', bodyBackground);
2138
- setBodyStyle('padding', bodyPadding);
2139
- injectClearFixIntoBodyElement();
2140
- checkHeightMode();
2141
- checkWidthMode();
2142
- stopInfiniteResizingOfIFrame();
2143
- setupPublicMethods();
2144
- setupMouseEvents();
2145
- startEventListeners();
2146
- inPageLinks = setupInPageLinks();
2147
- sendSize('init', 'Init message from host page');
2148
- onReady();
2149
- }
2150
-
2151
- function readDataFromParent() {
2152
- function strBool(str) {
2153
- return 'true' === str
2154
- }
2155
-
2156
- var data = initMsg.slice(msgIdLen).split(':');
2157
-
2158
- myID = data[0];
2159
- bodyMargin = undefined$1 === data[1] ? bodyMargin : Number(data[1]); // For V1 compatibility
2160
- calculateWidth = undefined$1 === data[2] ? calculateWidth : strBool(data[2]);
2161
- logging = undefined$1 === data[3] ? logging : strBool(data[3]);
2162
- interval = undefined$1 === data[4] ? interval : Number(data[4]);
2163
- autoResize = undefined$1 === data[6] ? autoResize : strBool(data[6]);
2164
- bodyMarginStr = data[7];
2165
- heightCalcMode = undefined$1 === data[8] ? heightCalcMode : data[8];
2166
- bodyBackground = data[9];
2167
- bodyPadding = data[10];
2168
- tolerance = undefined$1 === data[11] ? tolerance : Number(data[11]);
2169
- inPageLinks.enable = undefined$1 === data[12] ? false : strBool(data[12]);
2170
- resizeFrom = undefined$1 === data[13] ? resizeFrom : data[13];
2171
- widthCalcMode = undefined$1 === data[14] ? widthCalcMode : data[14];
2172
- mouseEvents = undefined$1 === data[15] ? mouseEvents : strBool(data[15]);
2173
- }
2174
-
2175
- function depricate(key) {
2176
- var splitName = key.split('Callback');
2177
-
2178
- if (splitName.length === 2) {
2179
- var name =
2180
- 'on' + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1);
2181
- this[name] = this[key];
2182
- delete this[key];
2183
- warn(
2184
- "Deprecated: '" +
2185
- key +
2186
- "' has been renamed '" +
2187
- name +
2188
- "'. The old method will be removed in the next major version."
2189
- );
2190
- }
2191
- }
2192
-
2193
- function readDataFromPage() {
2194
- function readData() {
2195
- var data = window.iFrameResizer;
2196
-
2197
- log('Reading data from page: ' + JSON.stringify(data));
2198
- Object.keys(data).forEach(depricate, data);
2199
-
2200
- onMessage = 'onMessage' in data ? data.onMessage : onMessage;
2201
- onReady = 'onReady' in data ? data.onReady : onReady;
2202
- targetOriginDefault =
2203
- 'targetOrigin' in data ? data.targetOrigin : targetOriginDefault;
2204
- heightCalcMode =
2205
- 'heightCalculationMethod' in data
2206
- ? data.heightCalculationMethod
2207
- : heightCalcMode;
2208
- widthCalcMode =
2209
- 'widthCalculationMethod' in data
2210
- ? data.widthCalculationMethod
2211
- : widthCalcMode;
2212
- }
2213
-
2214
- function setupCustomCalcMethods(calcMode, calcFunc) {
2215
- if ('function' === typeof calcMode) {
2216
- log('Setup custom ' + calcFunc + 'CalcMethod');
2217
- customCalcMethods[calcFunc] = calcMode;
2218
- calcMode = 'custom';
2219
- }
2220
-
2221
- return calcMode
2222
- }
2223
-
2224
- if (
2225
- 'iFrameResizer' in window &&
2226
- Object === window.iFrameResizer.constructor
2227
- ) {
2228
- readData();
2229
- heightCalcMode = setupCustomCalcMethods(heightCalcMode, 'height');
2230
- widthCalcMode = setupCustomCalcMethods(widthCalcMode, 'width');
2231
- }
2232
-
2233
- log('TargetOrigin for parent set to: ' + targetOriginDefault);
2234
- }
2235
-
2236
- function chkCSS(attr, value) {
2237
- if (-1 !== value.indexOf('-')) {
2238
- warn('Negative CSS value ignored for ' + attr);
2239
- value = '';
2240
- }
2241
- return value
2242
- }
2243
-
2244
- function setBodyStyle(attr, value) {
2245
- if (undefined$1 !== value && '' !== value && 'null' !== value) {
2246
- document.body.style[attr] = value;
2247
- log('Body ' + attr + ' set to "' + value + '"');
2248
- }
2249
- }
2250
-
2251
- function setMargin() {
2252
- // If called via V1 script, convert bodyMargin from int to str
2253
- if (undefined$1 === bodyMarginStr) {
2254
- bodyMarginStr = bodyMargin + 'px';
2255
- }
2256
-
2257
- setBodyStyle('margin', chkCSS('margin', bodyMarginStr));
2258
- }
2259
-
2260
- function stopInfiniteResizingOfIFrame() {
2261
- document.documentElement.style.height = '';
2262
- document.body.style.height = '';
2263
- log('HTML & body height set to "auto"');
2264
- }
2265
-
2266
- function manageTriggerEvent(options) {
2267
- var listener = {
2268
- add: function (eventName) {
2269
- function handleEvent() {
2270
- sendSize(options.eventName, options.eventType);
2271
- }
2272
-
2273
- eventHandlersByName[eventName] = handleEvent;
2274
-
2275
- addEventListener(window, eventName, handleEvent, { passive: true });
2276
- },
2277
- remove: function (eventName) {
2278
- var handleEvent = eventHandlersByName[eventName];
2279
- delete eventHandlersByName[eventName];
2280
-
2281
- removeEventListener(window, eventName, handleEvent);
2282
- }
2283
- };
2284
-
2285
- if (options.eventNames && Array.prototype.map) {
2286
- options.eventName = options.eventNames[0];
2287
- options.eventNames.map(listener[options.method]);
2288
- } else {
2289
- listener[options.method](options.eventName);
2290
- }
2291
-
2292
- log(
2293
- capitalizeFirstLetter(options.method) +
2294
- ' event listener: ' +
2295
- options.eventType
2296
- );
2297
- }
2298
-
2299
- function manageEventListeners(method) {
2300
- manageTriggerEvent({
2301
- method: method,
2302
- eventType: 'Animation Start',
2303
- eventNames: ['animationstart', 'webkitAnimationStart']
2304
- });
2305
- manageTriggerEvent({
2306
- method: method,
2307
- eventType: 'Animation Iteration',
2308
- eventNames: ['animationiteration', 'webkitAnimationIteration']
2309
- });
2310
- manageTriggerEvent({
2311
- method: method,
2312
- eventType: 'Animation End',
2313
- eventNames: ['animationend', 'webkitAnimationEnd']
2314
- });
2315
- manageTriggerEvent({
2316
- method: method,
2317
- eventType: 'Input',
2318
- eventName: 'input'
2319
- });
2320
- manageTriggerEvent({
2321
- method: method,
2322
- eventType: 'Mouse Up',
2323
- eventName: 'mouseup'
2324
- });
2325
- manageTriggerEvent({
2326
- method: method,
2327
- eventType: 'Mouse Down',
2328
- eventName: 'mousedown'
2329
- });
2330
- manageTriggerEvent({
2331
- method: method,
2332
- eventType: 'Orientation Change',
2333
- eventName: 'orientationchange'
2334
- });
2335
- manageTriggerEvent({
2336
- method: method,
2337
- eventType: 'Print',
2338
- eventNames: ['afterprint', 'beforeprint']
2339
- });
2340
- manageTriggerEvent({
2341
- method: method,
2342
- eventType: 'Ready State Change',
2343
- eventName: 'readystatechange'
2344
- });
2345
- manageTriggerEvent({
2346
- method: method,
2347
- eventType: 'Touch Start',
2348
- eventName: 'touchstart'
2349
- });
2350
- manageTriggerEvent({
2351
- method: method,
2352
- eventType: 'Touch End',
2353
- eventName: 'touchend'
2354
- });
2355
- manageTriggerEvent({
2356
- method: method,
2357
- eventType: 'Touch Cancel',
2358
- eventName: 'touchcancel'
2359
- });
2360
- manageTriggerEvent({
2361
- method: method,
2362
- eventType: 'Transition Start',
2363
- eventNames: [
2364
- 'transitionstart',
2365
- 'webkitTransitionStart',
2366
- 'MSTransitionStart',
2367
- 'oTransitionStart',
2368
- 'otransitionstart'
2369
- ]
2370
- });
2371
- manageTriggerEvent({
2372
- method: method,
2373
- eventType: 'Transition Iteration',
2374
- eventNames: [
2375
- 'transitioniteration',
2376
- 'webkitTransitionIteration',
2377
- 'MSTransitionIteration',
2378
- 'oTransitionIteration',
2379
- 'otransitioniteration'
2380
- ]
2381
- });
2382
- manageTriggerEvent({
2383
- method: method,
2384
- eventType: 'Transition End',
2385
- eventNames: [
2386
- 'transitionend',
2387
- 'webkitTransitionEnd',
2388
- 'MSTransitionEnd',
2389
- 'oTransitionEnd',
2390
- 'otransitionend'
2391
- ]
2392
- });
2393
- if ('child' === resizeFrom) {
2394
- manageTriggerEvent({
2395
- method: method,
2396
- eventType: 'IFrame Resized',
2397
- eventName: 'resize'
2398
- });
2399
- }
2400
- }
2401
-
2402
- function checkCalcMode(calcMode, calcModeDefault, modes, type) {
2403
- if (calcModeDefault !== calcMode) {
2404
- if (!(calcMode in modes)) {
2405
- warn(
2406
- calcMode + ' is not a valid option for ' + type + 'CalculationMethod.'
2407
- );
2408
- calcMode = calcModeDefault;
2409
- }
2410
- log(type + ' calculation method set to "' + calcMode + '"');
2411
- }
2412
-
2413
- return calcMode
2414
- }
2415
-
2416
- function checkHeightMode() {
2417
- heightCalcMode = checkCalcMode(
2418
- heightCalcMode,
2419
- heightCalcModeDefault,
2420
- getHeight,
2421
- 'height'
2422
- );
2423
- }
2424
-
2425
- function checkWidthMode() {
2426
- widthCalcMode = checkCalcMode(
2427
- widthCalcMode,
2428
- widthCalcModeDefault,
2429
- getWidth,
2430
- 'width'
2431
- );
2432
- }
2433
-
2434
- function startEventListeners() {
2435
- if (true === autoResize) {
2436
- manageEventListeners('add');
2437
- setupMutationObserver();
2438
- } else {
2439
- log('Auto Resize disabled');
2440
- }
2441
- }
2442
-
2443
- // function stopMsgsToParent() {
2444
- // log('Disable outgoing messages')
2445
- // sendPermit = false
2446
- // }
2447
-
2448
- // function removeMsgListener() {
2449
- // log('Remove event listener: Message')
2450
- // removeEventListener(window, 'message', receiver)
2451
- // }
2452
-
2453
- function disconnectMutationObserver() {
2454
- if (null !== bodyObserver) {
2455
- /* istanbul ignore next */ // Not testable in PhantonJS
2456
- bodyObserver.disconnect();
2457
- }
2458
- }
2459
-
2460
- function stopEventListeners() {
2461
- manageEventListeners('remove');
2462
- disconnectMutationObserver();
2463
- clearInterval(intervalTimer);
2464
- }
2465
-
2466
- // function teardown() {
2467
- // stopMsgsToParent()
2468
- // removeMsgListener()
2469
- // if (true === autoResize) stopEventListeners()
2470
- // }
2471
-
2472
- function injectClearFixIntoBodyElement() {
2473
- var clearFix = document.createElement('div');
2474
- clearFix.style.clear = 'both';
2475
- // Guard against the following having been globally redefined in CSS.
2476
- clearFix.style.display = 'block';
2477
- clearFix.style.height = '0';
2478
- document.body.appendChild(clearFix);
2479
- }
2480
-
2481
- function setupInPageLinks() {
2482
- function getPagePosition() {
2483
- return {
2484
- x:
2485
- window.pageXOffset === undefined$1
2486
- ? document.documentElement.scrollLeft
2487
- : window.pageXOffset,
2488
- y:
2489
- window.pageYOffset === undefined$1
2490
- ? document.documentElement.scrollTop
2491
- : window.pageYOffset
2492
- }
2493
- }
2494
-
2495
- function getElementPosition(el) {
2496
- var elPosition = el.getBoundingClientRect(),
2497
- pagePosition = getPagePosition();
2498
-
2499
- return {
2500
- x: parseInt(elPosition.left, 10) + parseInt(pagePosition.x, 10),
2501
- y: parseInt(elPosition.top, 10) + parseInt(pagePosition.y, 10)
2502
- }
2503
- }
2504
-
2505
- function findTarget(location) {
2506
- function jumpToTarget(target) {
2507
- var jumpPosition = getElementPosition(target);
2508
-
2509
- log(
2510
- 'Moving to in page link (#' +
2511
- hash +
2512
- ') at x: ' +
2513
- jumpPosition.x +
2514
- ' y: ' +
2515
- jumpPosition.y
2516
- );
2517
- sendMsg(jumpPosition.y, jumpPosition.x, 'scrollToOffset'); // X&Y reversed at sendMsg uses height/width
2518
- }
2519
-
2520
- var hash = location.split('#')[1] || location, // Remove # if present
2521
- hashData = decodeURIComponent(hash),
2522
- target =
2523
- document.getElementById(hashData) ||
2524
- document.getElementsByName(hashData)[0];
2525
-
2526
- if (undefined$1 === target) {
2527
- log(
2528
- 'In page link (#' +
2529
- hash +
2530
- ') not found in iFrame, so sending to parent'
2531
- );
2532
- sendMsg(0, 0, 'inPageLink', '#' + hash);
2533
- } else {
2534
- jumpToTarget(target);
2535
- }
2536
- }
2537
-
2538
- function checkLocationHash() {
2539
- var hash = window.location.hash;
2540
- var href = window.location.href;
2541
-
2542
- if ('' !== hash && '#' !== hash) {
2543
- findTarget(href);
2544
- }
2545
- }
2546
-
2547
- function bindAnchors() {
2548
- function setupLink(el) {
2549
- function linkClicked(e) {
2550
- e.preventDefault();
2551
-
2552
- /* jshint validthis:true */
2553
- findTarget(this.getAttribute('href'));
2554
- }
2555
-
2556
- if ('#' !== el.getAttribute('href')) {
2557
- addEventListener(el, 'click', linkClicked);
2558
- }
2559
- }
2560
-
2561
- Array.prototype.forEach.call(
2562
- document.querySelectorAll('a[href^="#"]'),
2563
- setupLink
2564
- );
2565
- }
2566
-
2567
- function bindLocationHash() {
2568
- addEventListener(window, 'hashchange', checkLocationHash);
2569
- }
2570
-
2571
- function initCheck() {
2572
- // Check if page loaded with location hash after init resize
2573
- setTimeout(checkLocationHash, eventCancelTimer);
2574
- }
2575
-
2576
- function enableInPageLinks() {
2577
- /* istanbul ignore else */ // Not testable in phantonJS
2578
- if (Array.prototype.forEach && document.querySelectorAll) {
2579
- log('Setting up location.hash handlers');
2580
- bindAnchors();
2581
- bindLocationHash();
2582
- initCheck();
2583
- } else {
2584
- warn(
2585
- 'In page linking not fully supported in this browser! (See README.md for IE8 workaround)'
2586
- );
2587
- }
2588
- }
2589
-
2590
- if (inPageLinks.enable) {
2591
- enableInPageLinks();
2592
- } else {
2593
- log('In page linking not enabled');
2594
- }
2595
-
2596
- return {
2597
- findTarget: findTarget
2598
- }
2599
- }
2600
-
2601
- function setupMouseEvents() {
2602
- if (mouseEvents !== true) return
2603
-
2604
- function sendMouse(e) {
2605
- sendMsg(0, 0, e.type, e.screenY + ':' + e.screenX);
2606
- }
2607
-
2608
- function addMouseListener(evt, name) {
2609
- log('Add event listener: ' + name);
2610
- addEventListener(window.document, evt, sendMouse);
2611
- }
2612
-
2613
- addMouseListener('mouseenter', 'Mouse Enter');
2614
- addMouseListener('mouseleave', 'Mouse Leave');
2615
- }
2616
-
2617
- function setupPublicMethods() {
2618
- log('Enable public methods');
2619
-
2620
- win.parentIFrame = {
2621
- autoResize: function autoResizeF(resize) {
2622
- if (true === resize && false === autoResize) {
2623
- autoResize = true;
2624
- startEventListeners();
2625
- } else if (false === resize && true === autoResize) {
2626
- autoResize = false;
2627
- stopEventListeners();
2628
- }
2629
- sendMsg(0, 0, 'autoResize', JSON.stringify(autoResize));
2630
- return autoResize
2631
- },
2632
-
2633
- close: function closeF() {
2634
- sendMsg(0, 0, 'close');
2635
- // teardown()
2636
- },
2637
-
2638
- getId: function getIdF() {
2639
- return myID
2640
- },
2641
-
2642
- getPageInfo: function getPageInfoF(callback) {
2643
- if ('function' === typeof callback) {
2644
- onPageInfo = callback;
2645
- sendMsg(0, 0, 'pageInfo');
2646
- } else {
2647
- onPageInfo = function () {};
2648
- sendMsg(0, 0, 'pageInfoStop');
2649
- }
2650
- },
2651
-
2652
- moveToAnchor: function moveToAnchorF(hash) {
2653
- inPageLinks.findTarget(hash);
2654
- },
2655
-
2656
- reset: function resetF() {
2657
- resetIFrame('parentIFrame.reset');
2658
- },
2659
-
2660
- scrollTo: function scrollToF(x, y) {
2661
- sendMsg(y, x, 'scrollTo'); // X&Y reversed at sendMsg uses height/width
2662
- },
2663
-
2664
- scrollToOffset: function scrollToF(x, y) {
2665
- sendMsg(y, x, 'scrollToOffset'); // X&Y reversed at sendMsg uses height/width
2666
- },
2667
-
2668
- sendMessage: function sendMessageF(msg, targetOrigin) {
2669
- sendMsg(0, 0, 'message', JSON.stringify(msg), targetOrigin);
2670
- },
2671
-
2672
- setHeightCalculationMethod: function setHeightCalculationMethodF(
2673
- heightCalculationMethod
2674
- ) {
2675
- heightCalcMode = heightCalculationMethod;
2676
- checkHeightMode();
2677
- },
2678
-
2679
- setWidthCalculationMethod: function setWidthCalculationMethodF(
2680
- widthCalculationMethod
2681
- ) {
2682
- widthCalcMode = widthCalculationMethod;
2683
- checkWidthMode();
2684
- },
2685
-
2686
- setTargetOrigin: function setTargetOriginF(targetOrigin) {
2687
- log('Set targetOrigin: ' + targetOrigin);
2688
- targetOriginDefault = targetOrigin;
2689
- },
2690
-
2691
- size: function sizeF(customHeight, customWidth) {
2692
- var valString =
2693
- '' + (customHeight || '') + (customWidth ? ',' + customWidth : '');
2694
- sendSize(
2695
- 'size',
2696
- 'parentIFrame.size(' + valString + ')',
2697
- customHeight,
2698
- customWidth
2699
- );
2700
- }
2701
- };
2702
- }
2703
-
2704
- function initInterval() {
2705
- if (0 !== interval) {
2706
- log('setInterval: ' + interval + 'ms');
2707
- intervalTimer = setInterval(function () {
2708
- sendSize('interval', 'setInterval: ' + interval);
2709
- }, Math.abs(interval));
2710
- }
2711
- }
2712
-
2713
- // Not testable in PhantomJS
2714
- /* istanbul ignore next */
2715
- function setupBodyMutationObserver() {
2716
- function addImageLoadListners(mutation) {
2717
- function addImageLoadListener(element) {
2718
- if (false === element.complete) {
2719
- log('Attach listeners to ' + element.src);
2720
- element.addEventListener('load', imageLoaded, false);
2721
- element.addEventListener('error', imageError, false);
2722
- elements.push(element);
2723
- }
2724
- }
2725
-
2726
- if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
2727
- addImageLoadListener(mutation.target);
2728
- } else if (mutation.type === 'childList') {
2729
- Array.prototype.forEach.call(
2730
- mutation.target.querySelectorAll('img'),
2731
- addImageLoadListener
2732
- );
2733
- }
2734
- }
2735
-
2736
- function removeFromArray(element) {
2737
- elements.splice(elements.indexOf(element), 1);
2738
- }
2739
-
2740
- function removeImageLoadListener(element) {
2741
- log('Remove listeners from ' + element.src);
2742
- element.removeEventListener('load', imageLoaded, false);
2743
- element.removeEventListener('error', imageError, false);
2744
- removeFromArray(element);
2745
- }
2746
-
2747
- function imageEventTriggered(event, type, typeDesc) {
2748
- removeImageLoadListener(event.target);
2749
- sendSize(type, typeDesc + ': ' + event.target.src);
2750
- }
2751
-
2752
- function imageLoaded(event) {
2753
- imageEventTriggered(event, 'imageLoad', 'Image loaded');
2754
- }
2755
-
2756
- function imageError(event) {
2757
- imageEventTriggered(event, 'imageLoadFailed', 'Image load failed');
2758
- }
2759
-
2760
- function mutationObserved(mutations) {
2761
- sendSize(
2762
- 'mutationObserver',
2763
- 'mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type
2764
- );
2765
-
2766
- // Deal with WebKit / Blink asyncing image loading when tags are injected into the page
2767
- mutations.forEach(addImageLoadListners);
2768
- }
2769
-
2770
- function createMutationObserver() {
2771
- var target = document.querySelector('body'),
2772
- config = {
2773
- attributes: true,
2774
- attributeOldValue: false,
2775
- characterData: true,
2776
- characterDataOldValue: false,
2777
- childList: true,
2778
- subtree: true
2779
- };
2780
-
2781
- observer = new MutationObserver(mutationObserved);
2782
-
2783
- log('Create body MutationObserver');
2784
- observer.observe(target, config);
2785
-
2786
- return observer
2787
- }
2788
-
2789
- var elements = [],
2790
- MutationObserver =
2791
- window.MutationObserver || window.WebKitMutationObserver,
2792
- observer = createMutationObserver();
2793
-
2794
- return {
2795
- disconnect: function () {
2796
- if ('disconnect' in observer) {
2797
- log('Disconnect body MutationObserver');
2798
- observer.disconnect();
2799
- elements.forEach(removeImageLoadListener);
2800
- }
2801
- }
2802
- }
2803
- }
2804
-
2805
- function setupMutationObserver() {
2806
- var forceIntervalTimer = 0 > interval;
2807
-
2808
- // Not testable in PhantomJS
2809
- /* istanbul ignore if */ if (
2810
- window.MutationObserver ||
2811
- window.WebKitMutationObserver
2812
- ) {
2813
- if (forceIntervalTimer) {
2814
- initInterval();
2815
- } else {
2816
- bodyObserver = setupBodyMutationObserver();
2817
- }
2818
- } else {
2819
- log('MutationObserver not supported in this browser!');
2820
- initInterval();
2821
- }
2822
- }
2823
-
2824
- // document.documentElement.offsetHeight is not reliable, so
2825
- // we have to jump through hoops to get a better value.
2826
- function getComputedStyle(prop, el) {
2827
- var retVal = 0;
2828
- el = el || document.body; // Not testable in phantonJS
2829
-
2830
- retVal = document.defaultView.getComputedStyle(el, null);
2831
- retVal = null === retVal ? 0 : retVal[prop];
2832
-
2833
- return parseInt(retVal, base)
2834
- }
2835
-
2836
- function chkEventThottle(timer) {
2837
- if (timer > throttledTimer / 2) {
2838
- throttledTimer = 2 * timer;
2839
- log('Event throttle increased to ' + throttledTimer + 'ms');
2840
- }
2841
- }
2842
-
2843
- // Idea from https://github.com/guardian/iframe-messenger
2844
- function getMaxElement(side, elements) {
2845
- var elementsLength = elements.length,
2846
- elVal = 0,
2847
- maxVal = 0,
2848
- Side = capitalizeFirstLetter(side),
2849
- timer = Date.now();
2850
-
2851
- for (var i = 0; i < elementsLength; i++) {
2852
- elVal =
2853
- elements[i].getBoundingClientRect()[side] +
2854
- getComputedStyle('margin' + Side, elements[i]);
2855
- if (elVal > maxVal) {
2856
- maxVal = elVal;
2857
- }
2858
- }
2859
-
2860
- timer = Date.now() - timer;
2861
-
2862
- log('Parsed ' + elementsLength + ' HTML elements');
2863
- log('Element position calculated in ' + timer + 'ms');
2864
-
2865
- chkEventThottle(timer);
2866
-
2867
- return maxVal
2868
- }
2869
-
2870
- function getAllMeasurements(dimensions) {
2871
- return [
2872
- dimensions.bodyOffset(),
2873
- dimensions.bodyScroll(),
2874
- dimensions.documentElementOffset(),
2875
- dimensions.documentElementScroll()
2876
- ]
2877
- }
2878
-
2879
- function getTaggedElements(side, tag) {
2880
- function noTaggedElementsFound() {
2881
- warn('No tagged elements (' + tag + ') found on page');
2882
- return document.querySelectorAll('body *')
2883
- }
2884
-
2885
- var elements = document.querySelectorAll('[' + tag + ']');
2886
-
2887
- if (elements.length === 0) noTaggedElementsFound();
2888
-
2889
- return getMaxElement(side, elements)
2890
- }
2891
-
2892
- function getAllElements() {
2893
- return document.querySelectorAll('body *')
2894
- }
2895
-
2896
- var getHeight = {
2897
- bodyOffset: function getBodyOffsetHeight() {
2898
- return (
2899
- document.body.offsetHeight +
2900
- getComputedStyle('marginTop') +
2901
- getComputedStyle('marginBottom')
2902
- )
2903
- },
2904
-
2905
- offset: function () {
2906
- return getHeight.bodyOffset() // Backwards compatibility
2907
- },
2908
-
2909
- bodyScroll: function getBodyScrollHeight() {
2910
- return document.body.scrollHeight
2911
- },
2912
-
2913
- custom: function getCustomWidth() {
2914
- return customCalcMethods.height()
2915
- },
2916
-
2917
- documentElementOffset: function getDEOffsetHeight() {
2918
- return document.documentElement.offsetHeight
2919
- },
2920
-
2921
- documentElementScroll: function getDEScrollHeight() {
2922
- return document.documentElement.scrollHeight
2923
- },
2924
-
2925
- max: function getMaxHeight() {
2926
- return Math.max.apply(null, getAllMeasurements(getHeight))
2927
- },
2928
-
2929
- min: function getMinHeight() {
2930
- return Math.min.apply(null, getAllMeasurements(getHeight))
2931
- },
2932
-
2933
- grow: function growHeight() {
2934
- return getHeight.max() // Run max without the forced downsizing
2935
- },
2936
-
2937
- lowestElement: function getBestHeight() {
2938
- return Math.max(
2939
- getHeight.bodyOffset() || getHeight.documentElementOffset(),
2940
- getMaxElement('bottom', getAllElements())
2941
- )
2942
- },
2943
-
2944
- taggedElement: function getTaggedElementsHeight() {
2945
- return getTaggedElements('bottom', 'data-iframe-height')
2946
- }
2947
- },
2948
- getWidth = {
2949
- bodyScroll: function getBodyScrollWidth() {
2950
- return document.body.scrollWidth
2951
- },
2952
-
2953
- bodyOffset: function getBodyOffsetWidth() {
2954
- return document.body.offsetWidth
2955
- },
2956
-
2957
- custom: function getCustomWidth() {
2958
- return customCalcMethods.width()
2959
- },
2960
-
2961
- documentElementScroll: function getDEScrollWidth() {
2962
- return document.documentElement.scrollWidth
2963
- },
2964
-
2965
- documentElementOffset: function getDEOffsetWidth() {
2966
- return document.documentElement.offsetWidth
2967
- },
2968
-
2969
- scroll: function getMaxWidth() {
2970
- return Math.max(getWidth.bodyScroll(), getWidth.documentElementScroll())
2971
- },
2972
-
2973
- max: function getMaxWidth() {
2974
- return Math.max.apply(null, getAllMeasurements(getWidth))
2975
- },
2976
-
2977
- min: function getMinWidth() {
2978
- return Math.min.apply(null, getAllMeasurements(getWidth))
2979
- },
2980
-
2981
- rightMostElement: function rightMostElement() {
2982
- return getMaxElement('right', getAllElements())
2983
- },
2984
-
2985
- taggedElement: function getTaggedElementsWidth() {
2986
- return getTaggedElements('right', 'data-iframe-width')
2987
- }
2988
- };
2989
-
2990
- function sizeIFrame(
2991
- triggerEvent,
2992
- triggerEventDesc,
2993
- customHeight,
2994
- customWidth
2995
- ) {
2996
- function resizeIFrame() {
2997
- height = currentHeight;
2998
- width = currentWidth;
2999
-
3000
- sendMsg(height, width, triggerEvent);
3001
- }
3002
-
3003
- function isSizeChangeDetected() {
3004
- function checkTolarance(a, b) {
3005
- var retVal = Math.abs(a - b) <= tolerance;
3006
- return !retVal
3007
- }
3008
-
3009
- currentHeight =
3010
- undefined$1 === customHeight ? getHeight[heightCalcMode]() : customHeight;
3011
- currentWidth =
3012
- undefined$1 === customWidth ? getWidth[widthCalcMode]() : customWidth;
3013
-
3014
- return (
3015
- checkTolarance(height, currentHeight) ||
3016
- (calculateWidth && checkTolarance(width, currentWidth))
3017
- )
3018
- }
3019
-
3020
- function isForceResizableEvent() {
3021
- return !(triggerEvent in { init: 1, interval: 1, size: 1 })
3022
- }
3023
-
3024
- function isForceResizableCalcMode() {
3025
- return (
3026
- heightCalcMode in resetRequiredMethods ||
3027
- (calculateWidth && widthCalcMode in resetRequiredMethods)
3028
- )
3029
- }
3030
-
3031
- function logIgnored() {
3032
- log('No change in size detected');
3033
- }
3034
-
3035
- function checkDownSizing() {
3036
- if (isForceResizableEvent() && isForceResizableCalcMode()) {
3037
- resetIFrame(triggerEventDesc);
3038
- } else if (!(triggerEvent in { interval: 1 })) {
3039
- logIgnored();
3040
- }
3041
- }
3042
-
3043
- var currentHeight, currentWidth;
3044
-
3045
- if (isSizeChangeDetected() || 'init' === triggerEvent) {
3046
- lockTrigger();
3047
- resizeIFrame();
3048
- } else {
3049
- checkDownSizing();
3050
- }
3051
- }
3052
-
3053
- var sizeIFrameThrottled = throttle(sizeIFrame);
3054
-
3055
- function sendSize(triggerEvent, triggerEventDesc, customHeight, customWidth) {
3056
- function recordTrigger() {
3057
- if (!(triggerEvent in { reset: 1, resetPage: 1, init: 1 })) {
3058
- log('Trigger event: ' + triggerEventDesc);
3059
- }
3060
- }
3061
-
3062
- function isDoubleFiredEvent() {
3063
- return triggerLocked && triggerEvent in doubleEventList
3064
- }
3065
-
3066
- if (isDoubleFiredEvent()) {
3067
- log('Trigger event cancelled: ' + triggerEvent);
3068
- } else {
3069
- recordTrigger();
3070
- if (triggerEvent === 'init') {
3071
- sizeIFrame(triggerEvent, triggerEventDesc, customHeight, customWidth);
3072
- } else {
3073
- sizeIFrameThrottled(
3074
- triggerEvent,
3075
- triggerEventDesc,
3076
- customHeight,
3077
- customWidth
3078
- );
3079
- }
3080
- }
3081
- }
3082
-
3083
- function lockTrigger() {
3084
- if (!triggerLocked) {
3085
- triggerLocked = true;
3086
- log('Trigger event lock on');
3087
- }
3088
- clearTimeout(triggerLockedTimer);
3089
- triggerLockedTimer = setTimeout(function () {
3090
- triggerLocked = false;
3091
- log('Trigger event lock off');
3092
- log('--');
3093
- }, eventCancelTimer);
3094
- }
3095
-
3096
- function triggerReset(triggerEvent) {
3097
- height = getHeight[heightCalcMode]();
3098
- width = getWidth[widthCalcMode]();
3099
-
3100
- sendMsg(height, width, triggerEvent);
3101
- }
3102
-
3103
- function resetIFrame(triggerEventDesc) {
3104
- var hcm = heightCalcMode;
3105
- heightCalcMode = heightCalcModeDefault;
3106
-
3107
- log('Reset trigger event: ' + triggerEventDesc);
3108
- lockTrigger();
3109
- triggerReset('reset');
3110
-
3111
- heightCalcMode = hcm;
3112
- }
3113
-
3114
- function sendMsg(height, width, triggerEvent, msg, targetOrigin) {
3115
- function setTargetOrigin() {
3116
- if (undefined$1 === targetOrigin) {
3117
- targetOrigin = targetOriginDefault;
3118
- } else {
3119
- log('Message targetOrigin: ' + targetOrigin);
3120
- }
3121
- }
3122
-
3123
- function sendToParent() {
3124
- var size = height + ':' + width,
3125
- message =
3126
- myID +
3127
- ':' +
3128
- size +
3129
- ':' +
3130
- triggerEvent +
3131
- (undefined$1 === msg ? '' : ':' + msg);
3132
-
3133
- log('Sending message to host page (' + message + ')');
3134
- target.postMessage(msgID + message, targetOrigin);
3135
- }
3136
-
3137
- {
3138
- setTargetOrigin();
3139
- sendToParent();
3140
- }
3141
- }
3142
-
3143
- function receiver(event) {
3144
- var processRequestFromParent = {
3145
- init: function initFromParent() {
3146
- initMsg = event.data;
3147
- target = event.source;
3148
-
3149
- init();
3150
- firstRun = false;
3151
- setTimeout(function () {
3152
- initLock = false;
3153
- }, eventCancelTimer);
3154
- },
3155
-
3156
- reset: function resetFromParent() {
3157
- if (initLock) {
3158
- log('Page reset ignored by init');
3159
- } else {
3160
- log('Page size reset by host page');
3161
- triggerReset('resetPage');
3162
- }
3163
- },
3164
-
3165
- resize: function resizeFromParent() {
3166
- sendSize('resizeParent', 'Parent window requested size check');
3167
- },
3168
-
3169
- moveToAnchor: function moveToAnchorF() {
3170
- inPageLinks.findTarget(getData());
3171
- },
3172
- inPageLink: function inPageLinkF() {
3173
- this.moveToAnchor();
3174
- }, // Backward compatibility
3175
-
3176
- pageInfo: function pageInfoFromParent() {
3177
- var msgBody = getData();
3178
- log('PageInfoFromParent called from parent: ' + msgBody);
3179
- onPageInfo(JSON.parse(msgBody));
3180
- log(' --');
3181
- },
3182
-
3183
- message: function messageFromParent() {
3184
- var msgBody = getData();
3185
-
3186
- log('onMessage called from parent: ' + msgBody);
3187
- // eslint-disable-next-line sonarjs/no-extra-arguments
3188
- onMessage(JSON.parse(msgBody));
3189
- log(' --');
3190
- }
3191
- };
3192
-
3193
- function isMessageForUs() {
3194
- return msgID === ('' + event.data).slice(0, msgIdLen) // ''+ Protects against non-string messages
3195
- }
3196
-
3197
- function getMessageType() {
3198
- return event.data.split(']')[1].split(':')[0]
3199
- }
3200
-
3201
- function getData() {
3202
- return event.data.slice(event.data.indexOf(':') + 1)
3203
- }
3204
-
3205
- function isMiddleTier() {
3206
- return (
3207
- (!(typeof module !== 'undefined' && module.exports) &&
3208
- 'iFrameResize' in window) ||
3209
- (window.jQuery !== undefined$1 &&
3210
- 'iFrameResize' in window.jQuery.prototype)
3211
- )
3212
- }
3213
-
3214
- function isInitMsg() {
3215
- // Test if this message is from a child below us. This is an ugly test, however, updating
3216
- // the message format would break backwards compatibility.
3217
- return event.data.split(':')[2] in { true: 1, false: 1 }
3218
- }
3219
-
3220
- function callFromParent() {
3221
- var messageType = getMessageType();
3222
-
3223
- if (messageType in processRequestFromParent) {
3224
- processRequestFromParent[messageType]();
3225
- } else if (!isMiddleTier() && !isInitMsg()) {
3226
- warn('Unexpected message (' + event.data + ')');
3227
- }
3228
- }
3229
-
3230
- function processMessage() {
3231
- if (false === firstRun) {
3232
- callFromParent();
3233
- } else if (isInitMsg()) {
3234
- processRequestFromParent.init();
3235
- } else {
3236
- log(
3237
- 'Ignored message of type "' +
3238
- getMessageType() +
3239
- '". Received before initialization.'
3240
- );
3241
- }
3242
- }
3243
-
3244
- if (isMessageForUs()) {
3245
- processMessage();
3246
- }
3247
- }
3248
-
3249
- // Normally the parent kicks things off when it detects the iFrame has loaded.
3250
- // If this script is async-loaded, then tell parent page to retry init.
3251
- function chkLateLoaded() {
3252
- if ('loading' !== document.readyState) {
3253
- window.parent.postMessage('[iFrameResizerChild]Ready', '*');
3254
- }
3255
- }
3256
-
3257
- addEventListener(window, 'message', receiver);
3258
- addEventListener(window, 'readystatechange', chkLateLoaded);
3259
- chkLateLoaded();
3260
-
3261
-
3262
- })();
3263
-
3264
- var CONTAINER_ID = "__authsignal-popup-container";
3265
- var CONTENT_ID = "__authsignal-popup-content";
3266
- var OVERLAY_ID = "__authsignal-popup-overlay";
3267
- var STYLE_ID = "__authsignal-popup-style";
3268
- var IFRAME_ID = "__authsignal-popup-iframe";
3269
- var DEFAULT_WIDTH = "385px";
3270
- var PopupHandler = /** @class */ (function () {
3271
- function PopupHandler(_a) {
3272
- var width = _a.width;
3273
- this.popup = null;
3274
- this.isHeightAutoResized = true;
3275
- if (document.querySelector("#".concat(CONTAINER_ID))) {
3276
- throw new Error("Multiple instances of Authsignal popup is not supported.");
3277
- }
3278
- this.create({ width: width });
3279
- }
3280
- PopupHandler.prototype.create = function (_a) {
3281
- var _this = this;
3282
- var _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH : _b;
3283
- var isWidthValidCSSValue = CSS.supports("width", width);
3284
- var popupWidth = width;
3285
- if (!isWidthValidCSSValue) {
3286
- console.warn("Invalid CSS value for `popupOptions.width`. Using default value instead.");
3287
- popupWidth = DEFAULT_WIDTH;
3288
- }
3289
- // Create dialog container
3290
- var container = document.createElement("div");
3291
- container.setAttribute("id", CONTAINER_ID);
3292
- container.setAttribute("aria-hidden", "true");
3293
- // Create dialog overlay
3294
- var overlay = document.createElement("div");
3295
- overlay.setAttribute("id", OVERLAY_ID);
3296
- overlay.setAttribute("data-a11y-dialog-hide", "true");
3297
- // Create dialog content
3298
- var content = document.createElement("div");
3299
- content.setAttribute("id", CONTENT_ID);
3300
- document.body.appendChild(container);
3301
- // Create CSS for dialog
3302
- var style = document.createElement("style");
3303
- style.setAttribute("id", STYLE_ID);
3304
- style.textContent = "\n #".concat(CONTAINER_ID, ",\n #").concat(OVERLAY_ID, " {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n\n #").concat(CONTAINER_ID, " {\n z-index: 2147483647;\n display: flex;\n }\n\n #").concat(CONTAINER_ID, "[aria-hidden='true'] {\n display: none;\n }\n\n #").concat(OVERLAY_ID, " {\n background-color: rgba(0, 0, 0, 0.18);\n }\n\n #").concat(CONTENT_ID, " {\n margin: auto;\n z-index: 2147483647;\n position: relative;\n background-color: transparent;\n border-radius: 8px;\n width: ").concat(popupWidth, ";\n }\n\n #").concat(CONTENT_ID, " iframe {\n width: 1px;\n min-width: 100%;\n border-radius: inherit;\n max-height: 65vh;\n }\n ");
3305
- // Attach the created elements
3306
- document.head.insertAdjacentElement("beforeend", style);
3307
- container.appendChild(overlay);
3308
- container.appendChild(content);
3309
- this.popup = new A11yDialog(container);
3310
- // Make sure to remove any trace of the dialog on hide
3311
- this.popup.on("hide", function () {
3312
- _this.destroy();
3313
- });
3314
- };
3315
- PopupHandler.prototype.destroy = function () {
3316
- var dialogEl = document.querySelector("#".concat(CONTAINER_ID));
3317
- var styleEl = document.querySelector("#".concat(STYLE_ID));
3318
- if (dialogEl && styleEl) {
3319
- document.body.removeChild(dialogEl);
3320
- document.head.removeChild(styleEl);
3321
- }
3322
- };
3323
- PopupHandler.prototype.show = function (_a) {
3324
- var _this = this;
3325
- var url = _a.url;
3326
- if (!this.popup) {
3327
- throw new Error("Popup is not initialized");
3328
- }
3329
- var iframe = document.createElement("iframe");
3330
- iframe.setAttribute("id", IFRAME_ID);
3331
- iframe.setAttribute("name", "authsignal");
3332
- iframe.setAttribute("title", "Authsignal multi-factor authentication");
3333
- iframe.setAttribute("src", url);
3334
- iframe.setAttribute("frameborder", "0");
3335
- iframe.setAttribute("allow", "publickey-credentials-get *; clipboard-write");
3336
- var dialogContent = document.querySelector("#".concat(CONTENT_ID));
3337
- if (dialogContent) {
3338
- dialogContent.appendChild(iframe);
3339
- }
3340
- // @ts-expect-error can't get typescript import to behave nicely, this works though
3341
- iFrameResize({
3342
- checkOrigin: false,
3343
- scrolling: true,
3344
- onInit: function () {
3345
- var _a;
3346
- (_a = _this.popup) === null || _a === void 0 ? void 0 : _a.show();
3347
- }
3348
- }, iframe);
3349
- };
3350
- PopupHandler.prototype.close = function () {
3351
- if (!this.popup) {
3352
- throw new Error("Popup is not initialized");
3353
- }
3354
- this.popup.hide();
3355
- };
3356
- PopupHandler.prototype.on = function (event, handler) {
3357
- if (!this.popup) {
3358
- throw new Error("Popup is not initialized");
3359
- }
3360
- this.popup.on(event, handler);
3361
- };
3362
- return PopupHandler;
3363
- }());
3364
-
3365
- /******************************************************************************
3366
- Copyright (c) Microsoft Corporation.
3367
-
3368
- Permission to use, copy, modify, and/or distribute this software for any
3369
- purpose with or without fee is hereby granted.
3370
-
3371
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
3372
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
3373
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
3374
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
3375
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
3376
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3377
- PERFORMANCE OF THIS SOFTWARE.
3378
- ***************************************************************************** */
3379
-
3380
- function __rest(s, e) {
3381
- var t = {};
3382
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
3383
- t[p] = s[p];
3384
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
3385
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
3386
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
3387
- t[p[i]] = s[p[i]];
3388
- }
3389
- return t;
3390
- }
3391
-
3392
- function __awaiter(thisArg, _arguments, P, generator) {
3393
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3394
- return new (P || (P = Promise))(function (resolve, reject) {
3395
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
3396
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
3397
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
3398
- step((generator = generator.apply(thisArg, _arguments || [])).next());
3399
- });
3400
- }
3401
-
3402
- function __generator(thisArg, body) {
3403
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
3404
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
3405
- function verb(n) { return function (v) { return step([n, v]); }; }
3406
- function step(op) {
3407
- if (f) throw new TypeError("Generator is already executing.");
3408
- while (_) try {
3409
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
3410
- if (y = 0, t) op = [op[0] & 2, t.value];
3411
- switch (op[0]) {
3412
- case 0: case 1: t = op; break;
3413
- case 4: _.label++; return { value: op[1], done: false };
3414
- case 5: _.label++; y = op[1]; op = [0]; continue;
3415
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
3416
- default:
3417
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
3418
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
3419
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
3420
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
3421
- if (t[2]) _.ops.pop();
3422
- _.trys.pop(); continue;
3423
- }
3424
- op = body.call(thisArg, _);
3425
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
3426
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
3427
- }
3428
- }
3429
-
3430
- /* [@simplewebauthn/browser@7.2.0] */
3431
- function utf8StringToBuffer(value) {
3432
- return new TextEncoder().encode(value);
3433
- }
3434
-
3435
- function bufferToBase64URLString(buffer) {
3436
- const bytes = new Uint8Array(buffer);
3437
- let str = '';
3438
- for (const charCode of bytes) {
3439
- str += String.fromCharCode(charCode);
3440
- }
3441
- const base64String = btoa(str);
3442
- return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
3443
- }
3444
-
3445
- function base64URLStringToBuffer(base64URLString) {
3446
- const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
3447
- const padLength = (4 - (base64.length % 4)) % 4;
3448
- const padded = base64.padEnd(base64.length + padLength, '=');
3449
- const binary = atob(padded);
3450
- const buffer = new ArrayBuffer(binary.length);
3451
- const bytes = new Uint8Array(buffer);
3452
- for (let i = 0; i < binary.length; i++) {
3453
- bytes[i] = binary.charCodeAt(i);
3454
- }
3455
- return buffer;
3456
- }
3457
-
3458
- function browserSupportsWebAuthn() {
3459
- return (window?.PublicKeyCredential !== undefined && typeof window.PublicKeyCredential === 'function');
3460
- }
3461
-
3462
- function toPublicKeyCredentialDescriptor(descriptor) {
3463
- const { id } = descriptor;
3464
- return {
3465
- ...descriptor,
3466
- id: base64URLStringToBuffer(id),
3467
- transports: descriptor.transports,
3468
- };
3469
- }
3470
-
3471
- function isValidDomain(hostname) {
3472
- return (hostname === 'localhost' || /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname));
3473
- }
3474
-
3475
- class WebAuthnError extends Error {
3476
- code;
3477
- constructor({ message, code, cause, name, }) {
3478
- super(message, { cause });
3479
- this.name = name ?? cause.name;
3480
- this.code = code;
3481
- }
3482
- }
3483
-
3484
- function identifyRegistrationError({ error, options, }) {
3485
- const { publicKey } = options;
3486
- if (!publicKey) {
3487
- throw Error('options was missing required publicKey property');
3488
- }
3489
- if (error.name === 'AbortError') {
3490
- if (options.signal instanceof AbortSignal) {
3491
- return new WebAuthnError({
3492
- message: 'Registration ceremony was sent an abort signal',
3493
- code: 'ERROR_CEREMONY_ABORTED',
3494
- cause: error,
3495
- });
3496
- }
3497
- }
3498
- else if (error.name === 'ConstraintError') {
3499
- if (publicKey.authenticatorSelection?.requireResidentKey === true) {
3500
- return new WebAuthnError({
3501
- message: 'Discoverable credentials were required but no available authenticator supported it',
3502
- code: 'ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT',
3503
- cause: error,
3504
- });
3505
- }
3506
- else if (publicKey.authenticatorSelection?.userVerification === 'required') {
3507
- return new WebAuthnError({
3508
- message: 'User verification was required but no available authenticator supported it',
3509
- code: 'ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT',
3510
- cause: error,
3511
- });
3512
- }
3513
- }
3514
- else if (error.name === 'InvalidStateError') {
3515
- return new WebAuthnError({
3516
- message: 'The authenticator was previously registered',
3517
- code: 'ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED',
3518
- cause: error
3519
- });
3520
- }
3521
- else if (error.name === 'NotAllowedError') {
3522
- return new WebAuthnError({
3523
- message: error.message,
3524
- code: 'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY',
3525
- cause: error,
3526
- });
3527
- }
3528
- else if (error.name === 'NotSupportedError') {
3529
- const validPubKeyCredParams = publicKey.pubKeyCredParams.filter(param => param.type === 'public-key');
3530
- if (validPubKeyCredParams.length === 0) {
3531
- return new WebAuthnError({
3532
- message: 'No entry in pubKeyCredParams was of type "public-key"',
3533
- code: 'ERROR_MALFORMED_PUBKEYCREDPARAMS',
3534
- cause: error,
3535
- });
3536
- }
3537
- return new WebAuthnError({
3538
- message: 'No available authenticator supported any of the specified pubKeyCredParams algorithms',
3539
- code: 'ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG',
3540
- cause: error,
3541
- });
3542
- }
3543
- else if (error.name === 'SecurityError') {
3544
- const effectiveDomain = window.location.hostname;
3545
- if (!isValidDomain(effectiveDomain)) {
3546
- return new WebAuthnError({
3547
- message: `${window.location.hostname} is an invalid domain`,
3548
- code: 'ERROR_INVALID_DOMAIN',
3549
- cause: error
3550
- });
3551
- }
3552
- else if (publicKey.rp.id !== effectiveDomain) {
3553
- return new WebAuthnError({
3554
- message: `The RP ID "${publicKey.rp.id}" is invalid for this domain`,
3555
- code: 'ERROR_INVALID_RP_ID',
3556
- cause: error,
3557
- });
3558
- }
3559
- }
3560
- else if (error.name === 'TypeError') {
3561
- if (publicKey.user.id.byteLength < 1 || publicKey.user.id.byteLength > 64) {
3562
- return new WebAuthnError({
3563
- message: 'User ID was not between 1 and 64 characters',
3564
- code: 'ERROR_INVALID_USER_ID_LENGTH',
3565
- cause: error,
3566
- });
3567
- }
3568
- }
3569
- else if (error.name === 'UnknownError') {
3570
- return new WebAuthnError({
3571
- message: 'The authenticator was unable to process the specified options, or could not create a new credential',
3572
- code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR',
3573
- cause: error,
3574
- });
3575
- }
3576
- return error;
3577
- }
3578
-
3579
- class WebAuthnAbortService {
3580
- controller;
3581
- createNewAbortSignal() {
3582
- if (this.controller) {
3583
- const abortError = new Error('Cancelling existing WebAuthn API call for new one');
3584
- abortError.name = 'AbortError';
3585
- this.controller.abort(abortError);
3586
- }
3587
- const newController = new AbortController();
3588
- this.controller = newController;
3589
- return newController.signal;
3590
- }
3591
- }
3592
- const webauthnAbortService = new WebAuthnAbortService();
3593
-
3594
- const attachments = ['cross-platform', 'platform'];
3595
- function toAuthenticatorAttachment(attachment) {
3596
- if (!attachment) {
3597
- return;
3598
- }
3599
- if (attachments.indexOf(attachment) < 0) {
3600
- return;
3601
- }
3602
- return attachment;
3603
- }
3604
-
3605
- async function startRegistration(creationOptionsJSON) {
3606
- if (!browserSupportsWebAuthn()) {
3607
- throw new Error('WebAuthn is not supported in this browser');
3608
- }
3609
- const publicKey = {
3610
- ...creationOptionsJSON,
3611
- challenge: base64URLStringToBuffer(creationOptionsJSON.challenge),
3612
- user: {
3613
- ...creationOptionsJSON.user,
3614
- id: utf8StringToBuffer(creationOptionsJSON.user.id),
3615
- },
3616
- excludeCredentials: creationOptionsJSON.excludeCredentials?.map(toPublicKeyCredentialDescriptor),
3617
- };
3618
- const options = { publicKey };
3619
- options.signal = webauthnAbortService.createNewAbortSignal();
3620
- let credential;
3621
- try {
3622
- credential = (await navigator.credentials.create(options));
3623
- }
3624
- catch (err) {
3625
- throw identifyRegistrationError({ error: err, options });
3626
- }
3627
- if (!credential) {
3628
- throw new Error('Registration was not completed');
3629
- }
3630
- const { id, rawId, response, type } = credential;
3631
- let transports = undefined;
3632
- if (typeof response.getTransports === 'function') {
3633
- transports = response.getTransports();
3634
- }
3635
- return {
3636
- id,
3637
- rawId: bufferToBase64URLString(rawId),
3638
- response: {
3639
- attestationObject: bufferToBase64URLString(response.attestationObject),
3640
- clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
3641
- transports,
3642
- },
3643
- type,
3644
- clientExtensionResults: credential.getClientExtensionResults(),
3645
- authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment),
3646
- };
3647
- }
3648
-
3649
- function bufferToUTF8String(value) {
3650
- return new TextDecoder('utf-8').decode(value);
3651
- }
3652
-
3653
- async function browserSupportsWebAuthnAutofill() {
3654
- const globalPublicKeyCredential = window.PublicKeyCredential;
3655
- return (globalPublicKeyCredential.isConditionalMediationAvailable !== undefined &&
3656
- globalPublicKeyCredential.isConditionalMediationAvailable());
3657
- }
3658
-
3659
- function identifyAuthenticationError({ error, options, }) {
3660
- const { publicKey } = options;
3661
- if (!publicKey) {
3662
- throw Error('options was missing required publicKey property');
3663
- }
3664
- if (error.name === 'AbortError') {
3665
- if (options.signal instanceof AbortSignal) {
3666
- return new WebAuthnError({
3667
- message: 'Authentication ceremony was sent an abort signal',
3668
- code: 'ERROR_CEREMONY_ABORTED',
3669
- cause: error,
3670
- });
3671
- }
3672
- }
3673
- else if (error.name === 'NotAllowedError') {
3674
- return new WebAuthnError({
3675
- message: error.message,
3676
- code: 'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY',
3677
- cause: error,
3678
- });
3679
- }
3680
- else if (error.name === 'SecurityError') {
3681
- const effectiveDomain = window.location.hostname;
3682
- if (!isValidDomain(effectiveDomain)) {
3683
- return new WebAuthnError({
3684
- message: `${window.location.hostname} is an invalid domain`,
3685
- code: 'ERROR_INVALID_DOMAIN',
3686
- cause: error,
3687
- });
3688
- }
3689
- else if (publicKey.rpId !== effectiveDomain) {
3690
- return new WebAuthnError({
3691
- message: `The RP ID "${publicKey.rpId}" is invalid for this domain`,
3692
- code: 'ERROR_INVALID_RP_ID',
3693
- cause: error,
3694
- });
3695
- }
3696
- }
3697
- else if (error.name === 'UnknownError') {
3698
- return new WebAuthnError({
3699
- message: 'The authenticator was unable to process the specified options, or could not create a new assertion signature',
3700
- code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR',
3701
- cause: error,
3702
- });
3703
- }
3704
- return error;
3705
- }
3706
-
3707
- async function startAuthentication(requestOptionsJSON, useBrowserAutofill = false) {
3708
- if (!browserSupportsWebAuthn()) {
3709
- throw new Error('WebAuthn is not supported in this browser');
3710
- }
3711
- let allowCredentials;
3712
- if (requestOptionsJSON.allowCredentials?.length !== 0) {
3713
- allowCredentials = requestOptionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor);
3714
- }
3715
- const publicKey = {
3716
- ...requestOptionsJSON,
3717
- challenge: base64URLStringToBuffer(requestOptionsJSON.challenge),
3718
- allowCredentials,
3719
- };
3720
- const options = {};
3721
- if (useBrowserAutofill) {
3722
- if (!(await browserSupportsWebAuthnAutofill())) {
3723
- throw Error('Browser does not support WebAuthn autofill');
3724
- }
3725
- const eligibleInputs = document.querySelectorAll("input[autocomplete*='webauthn']");
3726
- if (eligibleInputs.length < 1) {
3727
- throw Error('No <input> with `"webauthn"` in its `autocomplete` attribute was detected');
3728
- }
3729
- options.mediation = 'conditional';
3730
- publicKey.allowCredentials = [];
3731
- }
3732
- options.publicKey = publicKey;
3733
- options.signal = webauthnAbortService.createNewAbortSignal();
3734
- let credential;
3735
- try {
3736
- credential = (await navigator.credentials.get(options));
3737
- }
3738
- catch (err) {
3739
- throw identifyAuthenticationError({ error: err, options });
3740
- }
3741
- if (!credential) {
3742
- throw new Error('Authentication was not completed');
3743
- }
3744
- const { id, rawId, response, type } = credential;
3745
- let userHandle = undefined;
3746
- if (response.userHandle) {
3747
- userHandle = bufferToUTF8String(response.userHandle);
3748
- }
3749
- return {
3750
- id,
3751
- rawId: bufferToBase64URLString(rawId),
3752
- response: {
3753
- authenticatorData: bufferToBase64URLString(response.authenticatorData),
3754
- clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
3755
- signature: bufferToBase64URLString(response.signature),
3756
- userHandle,
3757
- },
3758
- type,
3759
- clientExtensionResults: credential.getClientExtensionResults(),
3760
- authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment),
3761
- };
3762
- }
3763
-
3764
- // eslint-lint-disable-next-line @typescript-eslint/naming-convention
3765
- class HTTPError extends Error {
3766
- constructor(response, request, options) {
3767
- const code = (response.status || response.status === 0) ? response.status : '';
3768
- const title = response.statusText || '';
3769
- const status = `${code} ${title}`.trim();
3770
- const reason = status ? `status code ${status}` : 'an unknown error';
3771
- super(`Request failed with ${reason}`);
3772
- Object.defineProperty(this, "response", {
3773
- enumerable: true,
3774
- configurable: true,
3775
- writable: true,
3776
- value: void 0
3777
- });
3778
- Object.defineProperty(this, "request", {
3779
- enumerable: true,
3780
- configurable: true,
3781
- writable: true,
3782
- value: void 0
3783
- });
3784
- Object.defineProperty(this, "options", {
3785
- enumerable: true,
3786
- configurable: true,
3787
- writable: true,
3788
- value: void 0
3789
- });
3790
- this.name = 'HTTPError';
3791
- this.response = response;
3792
- this.request = request;
3793
- this.options = options;
3794
- }
3795
- }
3796
-
3797
- class TimeoutError extends Error {
3798
- constructor(request) {
3799
- super('Request timed out');
3800
- Object.defineProperty(this, "request", {
3801
- enumerable: true,
3802
- configurable: true,
3803
- writable: true,
3804
- value: void 0
3805
- });
3806
- this.name = 'TimeoutError';
3807
- this.request = request;
3808
- }
3809
- }
3810
-
3811
- // eslint-disable-next-line @typescript-eslint/ban-types
3812
- const isObject = (value) => value !== null && typeof value === 'object';
3813
-
3814
- const validateAndMerge = (...sources) => {
3815
- for (const source of sources) {
3816
- if ((!isObject(source) || Array.isArray(source)) && typeof source !== 'undefined') {
3817
- throw new TypeError('The `options` argument must be an object');
3818
- }
3819
- }
3820
- return deepMerge({}, ...sources);
3821
- };
3822
- const mergeHeaders = (source1 = {}, source2 = {}) => {
3823
- const result = new globalThis.Headers(source1);
3824
- const isHeadersInstance = source2 instanceof globalThis.Headers;
3825
- const source = new globalThis.Headers(source2);
3826
- for (const [key, value] of source.entries()) {
3827
- if ((isHeadersInstance && value === 'undefined') || value === undefined) {
3828
- result.delete(key);
3829
- }
3830
- else {
3831
- result.set(key, value);
3832
- }
3833
- }
3834
- return result;
3835
- };
3836
- // TODO: Make this strongly-typed (no `any`).
3837
- const deepMerge = (...sources) => {
3838
- let returnValue = {};
3839
- let headers = {};
3840
- for (const source of sources) {
3841
- if (Array.isArray(source)) {
3842
- if (!Array.isArray(returnValue)) {
3843
- returnValue = [];
3844
- }
3845
- returnValue = [...returnValue, ...source];
3846
- }
3847
- else if (isObject(source)) {
3848
- for (let [key, value] of Object.entries(source)) {
3849
- if (isObject(value) && key in returnValue) {
3850
- value = deepMerge(returnValue[key], value);
3851
- }
3852
- returnValue = { ...returnValue, [key]: value };
3853
- }
3854
- if (isObject(source.headers)) {
3855
- headers = mergeHeaders(headers, source.headers);
3856
- returnValue.headers = headers;
3857
- }
3858
- }
3859
- }
3860
- return returnValue;
3861
- };
3862
-
3863
- const supportsRequestStreams = (() => {
3864
- let duplexAccessed = false;
3865
- let hasContentType = false;
3866
- const supportsReadableStream = typeof globalThis.ReadableStream === 'function';
3867
- const supportsRequest = typeof globalThis.Request === 'function';
3868
- if (supportsReadableStream && supportsRequest) {
3869
- hasContentType = new globalThis.Request('https://a.com', {
3870
- body: new globalThis.ReadableStream(),
3871
- method: 'POST',
3872
- // @ts-expect-error - Types are outdated.
3873
- get duplex() {
3874
- duplexAccessed = true;
3875
- return 'half';
3876
- },
3877
- }).headers.has('Content-Type');
3878
- }
3879
- return duplexAccessed && !hasContentType;
3880
- })();
3881
- const supportsAbortController = typeof globalThis.AbortController === 'function';
3882
- const supportsResponseStreams = typeof globalThis.ReadableStream === 'function';
3883
- const supportsFormData = typeof globalThis.FormData === 'function';
3884
- const requestMethods = ['get', 'post', 'put', 'patch', 'head', 'delete'];
3885
- const responseTypes = {
3886
- json: 'application/json',
3887
- text: 'text/*',
3888
- formData: 'multipart/form-data',
3889
- arrayBuffer: '*/*',
3890
- blob: '*/*',
3891
- };
3892
- // The maximum value of a 32bit int (see issue #117)
3893
- const maxSafeTimeout = 2147483647;
3894
- const stop = Symbol('stop');
3895
-
3896
- const normalizeRequestMethod = (input) => requestMethods.includes(input) ? input.toUpperCase() : input;
3897
- const retryMethods = ['get', 'put', 'head', 'delete', 'options', 'trace'];
3898
- const retryStatusCodes = [408, 413, 429, 500, 502, 503, 504];
3899
- const retryAfterStatusCodes = [413, 429, 503];
3900
- const defaultRetryOptions = {
3901
- limit: 2,
3902
- methods: retryMethods,
3903
- statusCodes: retryStatusCodes,
3904
- afterStatusCodes: retryAfterStatusCodes,
3905
- maxRetryAfter: Number.POSITIVE_INFINITY,
3906
- backoffLimit: Number.POSITIVE_INFINITY,
3907
- };
3908
- const normalizeRetryOptions = (retry = {}) => {
3909
- if (typeof retry === 'number') {
3910
- return {
3911
- ...defaultRetryOptions,
3912
- limit: retry,
3913
- };
3914
- }
3915
- if (retry.methods && !Array.isArray(retry.methods)) {
3916
- throw new Error('retry.methods must be an array');
3917
- }
3918
- if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {
3919
- throw new Error('retry.statusCodes must be an array');
3920
- }
3921
- return {
3922
- ...defaultRetryOptions,
3923
- ...retry,
3924
- afterStatusCodes: retryAfterStatusCodes,
3925
- };
3926
- };
3927
-
3928
- // `Promise.race()` workaround (#91)
3929
- async function timeout(request, abortController, options) {
3930
- return new Promise((resolve, reject) => {
3931
- const timeoutId = setTimeout(() => {
3932
- if (abortController) {
3933
- abortController.abort();
3934
- }
3935
- reject(new TimeoutError(request));
3936
- }, options.timeout);
3937
- void options
3938
- .fetch(request)
3939
- .then(resolve)
3940
- .catch(reject)
3941
- .then(() => {
3942
- clearTimeout(timeoutId);
3943
- });
3944
- });
3945
- }
3946
-
3947
- // DOMException is supported on most modern browsers and Node.js 18+.
3948
- // @see https://developer.mozilla.org/en-US/docs/Web/API/DOMException#browser_compatibility
3949
- const isDomExceptionSupported = Boolean(globalThis.DOMException);
3950
- // TODO: When targeting Node.js 18, use `signal.throwIfAborted()` (https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted)
3951
- function composeAbortError(signal) {
3952
- /*
3953
- NOTE: Use DomException with AbortError name as specified in MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort)
3954
- > When abort() is called, the fetch() promise rejects with an Error of type DOMException, with name AbortError.
3955
- */
3956
- if (isDomExceptionSupported) {
3957
- return new DOMException(signal?.reason ?? 'The operation was aborted.', 'AbortError');
3958
- }
3959
- // DOMException not supported. Fall back to use of error and override name.
3960
- const error = new Error(signal?.reason ?? 'The operation was aborted.');
3961
- error.name = 'AbortError';
3962
- return error;
3963
- }
3964
-
3965
- // https://github.com/sindresorhus/delay/tree/ab98ae8dfcb38e1593286c94d934e70d14a4e111
3966
- async function delay(ms, { signal }) {
3967
- return new Promise((resolve, reject) => {
3968
- if (signal) {
3969
- if (signal.aborted) {
3970
- reject(composeAbortError(signal));
3971
- return;
3972
- }
3973
- signal.addEventListener('abort', handleAbort, { once: true });
3974
- }
3975
- function handleAbort() {
3976
- reject(composeAbortError(signal));
3977
- clearTimeout(timeoutId);
3978
- }
3979
- const timeoutId = setTimeout(() => {
3980
- signal?.removeEventListener('abort', handleAbort);
3981
- resolve();
3982
- }, ms);
3983
- });
3984
- }
3985
-
3986
- class Ky {
3987
- // eslint-disable-next-line @typescript-eslint/promise-function-async
3988
- static create(input, options) {
3989
- const ky = new Ky(input, options);
3990
- const fn = async () => {
3991
- if (ky._options.timeout > maxSafeTimeout) {
3992
- throw new RangeError(`The \`timeout\` option cannot be greater than ${maxSafeTimeout}`);
3993
- }
3994
- // Delay the fetch so that body method shortcuts can set the Accept header
3995
- await Promise.resolve();
3996
- let response = await ky._fetch();
3997
- for (const hook of ky._options.hooks.afterResponse) {
3998
- // eslint-disable-next-line no-await-in-loop
3999
- const modifiedResponse = await hook(ky.request, ky._options, ky._decorateResponse(response.clone()));
4000
- if (modifiedResponse instanceof globalThis.Response) {
4001
- response = modifiedResponse;
4002
- }
4003
- }
4004
- ky._decorateResponse(response);
4005
- if (!response.ok && ky._options.throwHttpErrors) {
4006
- let error = new HTTPError(response, ky.request, ky._options);
4007
- for (const hook of ky._options.hooks.beforeError) {
4008
- // eslint-disable-next-line no-await-in-loop
4009
- error = await hook(error);
4010
- }
4011
- throw error;
4012
- }
4013
- // If `onDownloadProgress` is passed, it uses the stream API internally
4014
- /* istanbul ignore next */
4015
- if (ky._options.onDownloadProgress) {
4016
- if (typeof ky._options.onDownloadProgress !== 'function') {
4017
- throw new TypeError('The `onDownloadProgress` option must be a function');
4018
- }
4019
- if (!supportsResponseStreams) {
4020
- throw new Error('Streams are not supported in your environment. `ReadableStream` is missing.');
4021
- }
4022
- return ky._stream(response.clone(), ky._options.onDownloadProgress);
4023
- }
4024
- return response;
4025
- };
4026
- const isRetriableMethod = ky._options.retry.methods.includes(ky.request.method.toLowerCase());
4027
- const result = (isRetriableMethod ? ky._retry(fn) : fn());
4028
- for (const [type, mimeType] of Object.entries(responseTypes)) {
4029
- result[type] = async () => {
4030
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
4031
- ky.request.headers.set('accept', ky.request.headers.get('accept') || mimeType);
4032
- const awaitedResult = await result;
4033
- const response = awaitedResult.clone();
4034
- if (type === 'json') {
4035
- if (response.status === 204) {
4036
- return '';
4037
- }
4038
- const arrayBuffer = await response.clone().arrayBuffer();
4039
- const responseSize = arrayBuffer.byteLength;
4040
- if (responseSize === 0) {
4041
- return '';
4042
- }
4043
- if (options.parseJson) {
4044
- return options.parseJson(await response.text());
4045
- }
4046
- }
4047
- return response[type]();
4048
- };
4049
- }
4050
- return result;
4051
- }
4052
- // eslint-disable-next-line complexity
4053
- constructor(input, options = {}) {
4054
- Object.defineProperty(this, "request", {
4055
- enumerable: true,
4056
- configurable: true,
4057
- writable: true,
4058
- value: void 0
4059
- });
4060
- Object.defineProperty(this, "abortController", {
4061
- enumerable: true,
4062
- configurable: true,
4063
- writable: true,
4064
- value: void 0
4065
- });
4066
- Object.defineProperty(this, "_retryCount", {
4067
- enumerable: true,
4068
- configurable: true,
4069
- writable: true,
4070
- value: 0
4071
- });
4072
- Object.defineProperty(this, "_input", {
4073
- enumerable: true,
4074
- configurable: true,
4075
- writable: true,
4076
- value: void 0
4077
- });
4078
- Object.defineProperty(this, "_options", {
4079
- enumerable: true,
4080
- configurable: true,
4081
- writable: true,
4082
- value: void 0
4083
- });
4084
- this._input = input;
4085
- this._options = {
4086
- // TODO: credentials can be removed when the spec change is implemented in all browsers. Context: https://www.chromestatus.com/feature/4539473312350208
4087
- credentials: this._input.credentials || 'same-origin',
4088
- ...options,
4089
- headers: mergeHeaders(this._input.headers, options.headers),
4090
- hooks: deepMerge({
4091
- beforeRequest: [],
4092
- beforeRetry: [],
4093
- beforeError: [],
4094
- afterResponse: [],
4095
- }, options.hooks),
4096
- method: normalizeRequestMethod(options.method ?? this._input.method),
4097
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
4098
- prefixUrl: String(options.prefixUrl || ''),
4099
- retry: normalizeRetryOptions(options.retry),
4100
- throwHttpErrors: options.throwHttpErrors !== false,
4101
- timeout: typeof options.timeout === 'undefined' ? 10000 : options.timeout,
4102
- fetch: options.fetch ?? globalThis.fetch.bind(globalThis),
4103
- };
4104
- if (typeof this._input !== 'string' && !(this._input instanceof URL || this._input instanceof globalThis.Request)) {
4105
- throw new TypeError('`input` must be a string, URL, or Request');
4106
- }
4107
- if (this._options.prefixUrl && typeof this._input === 'string') {
4108
- if (this._input.startsWith('/')) {
4109
- throw new Error('`input` must not begin with a slash when using `prefixUrl`');
4110
- }
4111
- if (!this._options.prefixUrl.endsWith('/')) {
4112
- this._options.prefixUrl += '/';
4113
- }
4114
- this._input = this._options.prefixUrl + this._input;
4115
- }
4116
- if (supportsAbortController) {
4117
- this.abortController = new globalThis.AbortController();
4118
- if (this._options.signal) {
4119
- const originalSignal = this._options.signal;
4120
- this._options.signal.addEventListener('abort', () => {
4121
- this.abortController.abort(originalSignal.reason);
4122
- });
4123
- }
4124
- this._options.signal = this.abortController.signal;
4125
- }
4126
- if (supportsRequestStreams) {
4127
- // @ts-expect-error - Types are outdated.
4128
- this._options.duplex = 'half';
4129
- }
4130
- this.request = new globalThis.Request(this._input, this._options);
4131
- if (this._options.searchParams) {
4132
- // eslint-disable-next-line unicorn/prevent-abbreviations
4133
- const textSearchParams = typeof this._options.searchParams === 'string'
4134
- ? this._options.searchParams.replace(/^\?/, '')
4135
- : new URLSearchParams(this._options.searchParams).toString();
4136
- // eslint-disable-next-line unicorn/prevent-abbreviations
4137
- const searchParams = '?' + textSearchParams;
4138
- const url = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, searchParams);
4139
- // To provide correct form boundary, Content-Type header should be deleted each time when new Request instantiated from another one
4140
- if (((supportsFormData && this._options.body instanceof globalThis.FormData)
4141
- || this._options.body instanceof URLSearchParams) && !(this._options.headers && this._options.headers['content-type'])) {
4142
- this.request.headers.delete('content-type');
4143
- }
4144
- // The spread of `this.request` is required as otherwise it misses the `duplex` option for some reason and throws.
4145
- this.request = new globalThis.Request(new globalThis.Request(url, { ...this.request }), this._options);
4146
- }
4147
- if (this._options.json !== undefined) {
4148
- this._options.body = JSON.stringify(this._options.json);
4149
- this.request.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
4150
- this.request = new globalThis.Request(this.request, { body: this._options.body });
4151
- }
4152
- }
4153
- _calculateRetryDelay(error) {
4154
- this._retryCount++;
4155
- if (this._retryCount < this._options.retry.limit && !(error instanceof TimeoutError)) {
4156
- if (error instanceof HTTPError) {
4157
- if (!this._options.retry.statusCodes.includes(error.response.status)) {
4158
- return 0;
4159
- }
4160
- const retryAfter = error.response.headers.get('Retry-After');
4161
- if (retryAfter && this._options.retry.afterStatusCodes.includes(error.response.status)) {
4162
- let after = Number(retryAfter);
4163
- if (Number.isNaN(after)) {
4164
- after = Date.parse(retryAfter) - Date.now();
4165
- }
4166
- else {
4167
- after *= 1000;
4168
- }
4169
- if (typeof this._options.retry.maxRetryAfter !== 'undefined' && after > this._options.retry.maxRetryAfter) {
4170
- return 0;
4171
- }
4172
- return after;
4173
- }
4174
- if (error.response.status === 413) {
4175
- return 0;
4176
- }
4177
- }
4178
- const BACKOFF_FACTOR = 0.3;
4179
- return Math.min(this._options.retry.backoffLimit, BACKOFF_FACTOR * (2 ** (this._retryCount - 1)) * 1000);
4180
- }
4181
- return 0;
4182
- }
4183
- _decorateResponse(response) {
4184
- if (this._options.parseJson) {
4185
- response.json = async () => this._options.parseJson(await response.text());
4186
- }
4187
- return response;
4188
- }
4189
- async _retry(fn) {
4190
- try {
4191
- return await fn();
4192
- // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
4193
- }
4194
- catch (error) {
4195
- const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout);
4196
- if (ms !== 0 && this._retryCount > 0) {
4197
- await delay(ms, { signal: this._options.signal });
4198
- for (const hook of this._options.hooks.beforeRetry) {
4199
- // eslint-disable-next-line no-await-in-loop
4200
- const hookResult = await hook({
4201
- request: this.request,
4202
- options: this._options,
4203
- error: error,
4204
- retryCount: this._retryCount,
4205
- });
4206
- // If `stop` is returned from the hook, the retry process is stopped
4207
- if (hookResult === stop) {
4208
- return;
4209
- }
4210
- }
4211
- return this._retry(fn);
4212
- }
4213
- throw error;
4214
- }
4215
- }
4216
- async _fetch() {
4217
- for (const hook of this._options.hooks.beforeRequest) {
4218
- // eslint-disable-next-line no-await-in-loop
4219
- const result = await hook(this.request, this._options);
4220
- if (result instanceof Request) {
4221
- this.request = result;
4222
- break;
4223
- }
4224
- if (result instanceof Response) {
4225
- return result;
4226
- }
4227
- }
4228
- if (this._options.timeout === false) {
4229
- return this._options.fetch(this.request.clone());
4230
- }
4231
- return timeout(this.request.clone(), this.abortController, this._options);
4232
- }
4233
- /* istanbul ignore next */
4234
- _stream(response, onDownloadProgress) {
4235
- const totalBytes = Number(response.headers.get('content-length')) || 0;
4236
- let transferredBytes = 0;
4237
- if (response.status === 204) {
4238
- if (onDownloadProgress) {
4239
- onDownloadProgress({ percent: 1, totalBytes, transferredBytes }, new Uint8Array());
4240
- }
4241
- return new globalThis.Response(null, {
4242
- status: response.status,
4243
- statusText: response.statusText,
4244
- headers: response.headers,
4245
- });
4246
- }
4247
- return new globalThis.Response(new globalThis.ReadableStream({
4248
- async start(controller) {
4249
- const reader = response.body.getReader();
4250
- if (onDownloadProgress) {
4251
- onDownloadProgress({ percent: 0, transferredBytes: 0, totalBytes }, new Uint8Array());
4252
- }
4253
- async function read() {
4254
- const { done, value } = await reader.read();
4255
- if (done) {
4256
- controller.close();
4257
- return;
4258
- }
4259
- if (onDownloadProgress) {
4260
- transferredBytes += value.byteLength;
4261
- const percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
4262
- onDownloadProgress({ percent, transferredBytes, totalBytes }, value);
4263
- }
4264
- controller.enqueue(value);
4265
- await read();
4266
- }
4267
- await read();
4268
- },
4269
- }), {
4270
- status: response.status,
4271
- statusText: response.statusText,
4272
- headers: response.headers,
4273
- });
4274
- }
4275
- }
4276
-
4277
- /*! MIT License © Sindre Sorhus */
4278
- const createInstance = (defaults) => {
4279
- // eslint-disable-next-line @typescript-eslint/promise-function-async
4280
- const ky = (input, options) => Ky.create(input, validateAndMerge(defaults, options));
4281
- for (const method of requestMethods) {
4282
- // eslint-disable-next-line @typescript-eslint/promise-function-async
4283
- ky[method] = (input, options) => Ky.create(input, validateAndMerge(defaults, options, { method }));
4284
- }
4285
- ky.create = (newDefaults) => createInstance(validateAndMerge(newDefaults));
4286
- ky.extend = (newDefaults) => createInstance(validateAndMerge(defaults, newDefaults));
4287
- ky.stop = stop;
4288
- return ky;
4289
- };
4290
- const ky = createInstance();
4291
- var ky$1 = ky;
4292
-
4293
- var PasskeyApiClient = /** @class */ (function () {
4294
- function PasskeyApiClient(_a) {
4295
- var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
4296
- this.tenantId = tenantId;
4297
- this.api = ky$1.create({
4298
- prefixUrl: baseUrl
4299
- });
4300
- }
4301
- PasskeyApiClient.prototype.registrationOptions = function (_a) {
4302
- var token = _a.token, userName = _a.userName;
4303
- return __awaiter(this, void 0, void 0, function () {
4304
- var response;
4305
- return __generator(this, function (_b) {
4306
- switch (_b.label) {
4307
- case 0: return [4 /*yield*/, this.api.post("user-authenticators/passkey/registration-options", {
4308
- json: { userName: userName },
4309
- headers: {
4310
- Authorization: "Bearer ".concat(token)
4311
- }
4312
- })];
4313
- case 1:
4314
- response = _b.sent();
4315
- return [2 /*return*/, response.json()];
4316
- }
4317
- });
4318
- });
4319
- };
4320
- PasskeyApiClient.prototype.authenticationOptions = function (_a) {
4321
- var token = _a.token;
4322
- return __awaiter(this, void 0, void 0, function () {
4323
- var authorizationHeader, response;
4324
- return __generator(this, function (_b) {
4325
- switch (_b.label) {
4326
- case 0:
4327
- authorizationHeader = token ? "Bearer ".concat(token) : "Basic ".concat(Buffer.from(this.tenantId).toString("base64"));
4328
- return [4 /*yield*/, this.api.post("user-authenticators/passkey/authentication-options", {
4329
- json: {},
4330
- headers: {
4331
- Authorization: authorizationHeader
4332
- }
4333
- })];
4334
- case 1:
4335
- response = _b.sent();
4336
- return [2 /*return*/, response.json()];
4337
- }
4338
- });
4339
- });
4340
- };
4341
- PasskeyApiClient.prototype.addAuthenticator = function (_a) {
4342
- var token = _a.token, rest = __rest(_a, ["token"]);
4343
- return __awaiter(this, void 0, void 0, function () {
4344
- var response;
4345
- return __generator(this, function (_b) {
4346
- switch (_b.label) {
4347
- case 0: return [4 /*yield*/, this.api.post("user-authenticators/passkey", {
4348
- json: rest,
4349
- headers: {
4350
- Authorization: "Bearer ".concat(token)
4351
- }
4352
- })];
4353
- case 1:
4354
- response = _b.sent();
4355
- return [2 /*return*/, response.json()];
4356
- }
4357
- });
4358
- });
4359
- };
4360
- PasskeyApiClient.prototype.verify = function (_a) {
4361
- var token = _a.token, rest = __rest(_a, ["token"]);
4362
- return __awaiter(this, void 0, void 0, function () {
4363
- var authorizationHeader, response;
4364
- return __generator(this, function (_b) {
4365
- switch (_b.label) {
4366
- case 0:
4367
- authorizationHeader = token ? "Bearer ".concat(token) : "Basic ".concat(Buffer.from(this.tenantId).toString("base64"));
4368
- return [4 /*yield*/, this.api.post("verify/passkey", {
4369
- json: rest,
4370
- headers: {
4371
- Authorization: authorizationHeader
4372
- }
4373
- })];
4374
- case 1:
4375
- response = _b.sent();
4376
- return [2 /*return*/, response.json()];
4377
- }
4378
- });
4379
- });
4380
- };
4381
- return PasskeyApiClient;
4382
- }());
4383
-
4384
- var Passkey = /** @class */ (function () {
4385
- function Passkey(_a) {
4386
- var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
4387
- this.api = new PasskeyApiClient({ baseUrl: baseUrl, tenantId: tenantId });
4388
- }
4389
- Passkey.prototype.signUp = function (_a) {
4390
- var userName = _a.userName, token = _a.token;
4391
- return __awaiter(this, void 0, void 0, function () {
4392
- var optionsResponse, registrationResponse, addAuthenticatorResponse, error_1;
4393
- return __generator(this, function (_b) {
4394
- switch (_b.label) {
4395
- case 0: return [4 /*yield*/, this.api.registrationOptions({ userName: userName, token: token })];
4396
- case 1:
4397
- optionsResponse = _b.sent();
4398
- _b.label = 2;
4399
- case 2:
4400
- _b.trys.push([2, 5, , 6]);
4401
- return [4 /*yield*/, startRegistration(optionsResponse.options)];
4402
- case 3:
4403
- registrationResponse = _b.sent();
4404
- return [4 /*yield*/, this.api.addAuthenticator({
4405
- challengeId: optionsResponse.challengeId,
4406
- registrationCredential: registrationResponse,
4407
- token: token
4408
- })];
4409
- case 4:
4410
- addAuthenticatorResponse = _b.sent();
4411
- return [2 /*return*/, addAuthenticatorResponse === null || addAuthenticatorResponse === void 0 ? void 0 : addAuthenticatorResponse.accessToken];
4412
- case 5:
4413
- error_1 = _b.sent();
4414
- console.error(error_1);
4415
- return [3 /*break*/, 6];
4416
- case 6: return [2 /*return*/];
4417
- }
4418
- });
4419
- });
4420
- };
4421
- Passkey.prototype.signIn = function (params) {
4422
- return __awaiter(this, void 0, void 0, function () {
4423
- var optionsResponse, authenticationResponse, verifyResponse, error_2;
4424
- return __generator(this, function (_a) {
4425
- switch (_a.label) {
4426
- case 0:
4427
- if ((params === null || params === void 0 ? void 0 : params.token) && params.autofill) {
4428
- throw new Error("Autofill is not supported when providing a token");
4429
- }
4430
- return [4 /*yield*/, this.api.authenticationOptions({ token: params === null || params === void 0 ? void 0 : params.token })];
4431
- case 1:
4432
- optionsResponse = _a.sent();
4433
- _a.label = 2;
4434
- case 2:
4435
- _a.trys.push([2, 5, , 6]);
4436
- return [4 /*yield*/, startAuthentication(optionsResponse.options, params === null || params === void 0 ? void 0 : params.autofill)];
4437
- case 3:
4438
- authenticationResponse = _a.sent();
4439
- return [4 /*yield*/, this.api.verify({
4440
- challengeId: optionsResponse.challengeId,
4441
- authenticationCredential: authenticationResponse,
4442
- token: params === null || params === void 0 ? void 0 : params.token
4443
- })];
4444
- case 4:
4445
- verifyResponse = _a.sent();
4446
- return [2 /*return*/, verifyResponse === null || verifyResponse === void 0 ? void 0 : verifyResponse.accessToken];
4447
- case 5:
4448
- error_2 = _a.sent();
4449
- console.error(error_2);
4450
- return [3 /*break*/, 6];
4451
- case 6: return [2 /*return*/];
4452
- }
4453
- });
4454
- });
4455
- };
4456
- return Passkey;
4457
- }());
4458
-
4459
- var DEFAULT_COOKIE_NAME = "__as_aid";
4460
- var DEFAULT_BASE_URL = "https://challenge.authsignal.com/v1";
4461
- var Authsignal = /** @class */ (function () {
4462
- function Authsignal(_a) {
4463
- var cookieDomain = _a.cookieDomain, _b = _a.cookieName, cookieName = _b === void 0 ? DEFAULT_COOKIE_NAME : _b, _c = _a.baseUrl, baseUrl = _c === void 0 ? DEFAULT_BASE_URL : _c, tenantId = _a.tenantId;
4464
- this.anonymousId = "";
4465
- this.cookieDomain = "";
4466
- this.anonymousIdCookieName = "";
4467
- this._token = undefined;
4468
- this.cookieDomain = cookieDomain || getCookieDomain();
4469
- this.anonymousIdCookieName = cookieName;
4470
- this.passkey = new Passkey({ tenantId: tenantId, baseUrl: baseUrl });
4471
- var idCookie = getCookie(this.anonymousIdCookieName);
4472
- if (idCookie) {
4473
- this.anonymousId = idCookie;
4474
- }
4475
- else {
4476
- this.anonymousId = v4();
4477
- setCookie({
4478
- name: this.anonymousIdCookieName,
4479
- value: this.anonymousId,
4480
- expire: Infinity,
4481
- domain: this.cookieDomain,
4482
- secure: document.location.protocol !== "http:"
4483
- });
4484
- }
4485
- }
4486
- Authsignal.prototype.launch = function (url, options) {
4487
- var _this = this;
4488
- if (!(options === null || options === void 0 ? void 0 : options.mode) || options.mode === "redirect") {
4489
- window.location.href = url;
4490
- }
4491
- else {
4492
- var popupOptions = options.popupOptions;
4493
- var Popup_1 = new PopupHandler({ width: popupOptions === null || popupOptions === void 0 ? void 0 : popupOptions.width });
4494
- var popupUrl = "".concat(url, "&mode=popup");
4495
- Popup_1.show({ url: popupUrl });
4496
- return new Promise(function (resolve) {
4497
- var onMessage = function (event) {
4498
- var data = null;
4499
- try {
4500
- data = JSON.parse(event.data);
4501
- }
4502
- catch (_a) {
4503
- // Ignore if the event data is not valid JSON
4504
- }
4505
- if ((data === null || data === void 0 ? void 0 : data.event) === AuthsignalWindowMessage.AUTHSIGNAL_CLOSE_POPUP) {
4506
- _this._token = data.token;
4507
- Popup_1.close();
4508
- }
4509
- };
4510
- Popup_1.on("hide", function () {
4511
- resolve({ token: _this._token });
4512
- });
4513
- window.addEventListener("message", onMessage, false);
4514
- });
4515
- }
4516
- };
4517
- return Authsignal;
4518
- }());
4519
-
4520
- export { Authsignal, AuthsignalWindowMessage };