From 0322d2bb60e757cbc16e37b9baed66420e2073b0 Mon Sep 17 00:00:00 2001 From: Tomas Mecir Date: Tue, 5 Apr 2022 15:12:41 +0200 Subject: [PATCH 1/2] * Fix links in new window by setting the base URL correctly * Update styles in the new window whenever they change in the parent. This is needed if the application mounts new React components inside the new window (React updates those styles on-demand instead of loading them at start). --- src/NewWindow.js | 167 ++++++++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 74 deletions(-) diff --git a/src/NewWindow.js b/src/NewWindow.js index 019980a..56143a5 100644 --- a/src/NewWindow.js +++ b/src/NewWindow.js @@ -99,7 +99,8 @@ class NewWindow extends React.PureComponent { // Open a new window. this.window = window.open(url, name, toWindowFeatures(features)) - this.container = this.window.document.createElement('div') + let doc = this.window.document; + this.container = doc.createElement('div') // When a new window use content from a cross-origin there's no way we can attach event // to it. Therefore, we need to detect in a interval when the new window was destroyed // or was closed. @@ -111,27 +112,32 @@ class NewWindow extends React.PureComponent { // Check if the new window was succesfully opened. if (this.window) { - this.window.document.title = title + doc.title = title; // Check if the container already exists as the window may have been already open - this.container = this.window.document.getElementById( + this.container = doc.getElementById( 'new-window-container' ) if (this.container === null) { - this.container = this.window.document.createElement('div') + // Set the base href for links. + this.base = doc.createElement('base'); + this.base.setAttribute('href', window.location.href); + doc.head.appendChild(this.base); + + this.container = doc.createElement('div') this.container.setAttribute('id', 'new-window-container') - this.window.document.body.appendChild(this.container) + doc.body.appendChild(this.container) } else { // Remove any existing content - const staticContainer = this.window.document.getElementById( + const staticContainer = doc.getElementById( 'new-window-container-static' ) - this.window.document.body.removeChild(staticContainer) + doc.body.removeChild(staticContainer) } // If specified, copy styles from parent window's document. if (this.props.copyStyles) { - setTimeout(() => copyStyles(document, this.window.document), 0) + setTimeout(() => this.copyStyles(document, doc), 0) } if (typeof onOpen === 'function') { @@ -180,6 +186,12 @@ class NewWindow extends React.PureComponent { // Remove checker interval. clearInterval(this.windowCheckerInterval) + // Clear the observer. + if (this.observer) { + this.observer.disconnect(); + this.observer = null; + } + // Call any function bound to the `onUnload` prop. const { onUnload } = this.props @@ -187,6 +199,79 @@ class NewWindow extends React.PureComponent { onUnload(null) } } + + /** + * Copy styles from a source document to a target. + * @param {Object} source + * @param {Object} target + * @private + */ + + copyStyles(source, target) { + // Store style tags, avoid reflow in the loop + const headFrag = target.createDocumentFragment() + + Array.from(source.styleSheets).forEach(styleSheet => { + // For