@@ -10,6 +10,7 @@ const DATA_CLONE_ERROR = 'DataCloneError';
10
10
export const ERR_CONNECTION_DESTROYED = 'ConnectionDestroyed' ;
11
11
export const ERR_CONNECTION_TIMEOUT = 'ConnectionTimeout' ;
12
12
export const ERR_NOT_IN_IFRAME = 'NotInIframe' ;
13
+ export const ERR_IFRAME_ALREADY_ATTACHED_TO_DOM = 'IframeAlreadyAttachedToDom' ;
13
14
14
15
const DEFAULT_PORTS = {
15
16
'http:' : '80' ,
@@ -22,6 +23,7 @@ const Penpal = {
22
23
ERR_CONNECTION_DESTROYED ,
23
24
ERR_CONNECTION_TIMEOUT ,
24
25
ERR_NOT_IN_IFRAME ,
26
+ ERR_IFRAME_ALREADY_ATTACHED_TO_DOM ,
25
27
26
28
/**
27
29
* Promise implementation.
@@ -336,26 +338,33 @@ const connectCallReceiver = (info, methods, destructionPromise) => {
336
338
* for the child to respond before rejecting the connection promise.
337
339
* @return {Child }
338
340
*/
339
- Penpal . connectToChild = ( { url, appendTo, methods = { } , timeout } ) => {
341
+ Penpal . connectToChild = ( { url, appendTo, iframe, methods = { } , timeout } ) => {
342
+ if ( iframe && iframe . parentNode ) {
343
+ const error = new Error (
344
+ 'connectToChild() must not be called with an iframe already attached to DOM'
345
+ ) ;
346
+ error . code = ERR_IFRAME_ALREADY_ATTACHED_TO_DOM ;
347
+ throw error ;
348
+ }
349
+
340
350
let destroy ;
351
+
341
352
const connectionDestructionPromise = new DestructionPromise (
342
353
resolveConnectionDestructionPromise => {
343
354
destroy = resolveConnectionDestructionPromise ;
344
355
}
345
356
) ;
346
357
347
358
const parent = window ;
348
- const iframe = document . createElement ( 'iframe' ) ;
349
-
350
- ( appendTo || document . body ) . appendChild ( iframe ) ;
359
+ iframe = iframe || document . createElement ( 'iframe' ) ;
360
+ iframe . src = url ;
351
361
352
362
connectionDestructionPromise . then ( ( ) => {
353
363
if ( iframe . parentNode ) {
354
364
iframe . parentNode . removeChild ( iframe ) ;
355
365
}
356
366
} ) ;
357
367
358
- const child = iframe . contentWindow || iframe . contentDocument . parentWindow ;
359
368
const childOrigin = getOriginFromUrl ( url ) ;
360
369
const promise = new Penpal . Promise ( ( resolveConnectionPromise , reject ) => {
361
370
let connectionTimeoutId ;
@@ -380,6 +389,7 @@ Penpal.connectToChild = ({ url, appendTo, methods = {}, timeout }) => {
380
389
let destroyCallReceiver ;
381
390
382
391
const handleMessage = event => {
392
+ const child = iframe . contentWindow || iframe . contentDocument . parentWindow ;
383
393
if (
384
394
event . source === child &&
385
395
event . origin === childOrigin &&
@@ -456,7 +466,7 @@ Penpal.connectToChild = ({ url, appendTo, methods = {}, timeout }) => {
456
466
} ) ;
457
467
458
468
log ( 'Parent: Loading iframe' ) ;
459
- iframe . src = url ;
469
+ ( appendTo || document . body ) . appendChild ( iframe ) ;
460
470
} ) ;
461
471
462
472
return {
0 commit comments