From 8dd98f602b29f637fa87d025d3762c9e851a7204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Fri, 7 Jul 2023 15:56:54 +0200 Subject: [PATCH] fix: Don't use copyStyleSheets with documentPIP (#8314) * Don't use copyStyleSheets * Move to dom.js * Add tests * Address feedback --- src/js/player.js | 4 +-- src/js/utils/dom.js | 27 ++++++++++++++++++++ test/unit/player.test.js | 1 + test/unit/utils/dom.test.js | 49 +++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index 604a78ec59..a39a873e5a 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -3095,9 +3095,9 @@ class Player extends Component { return window.documentPictureInPicture.requestWindow({ // The aspect ratio won't be correct, Chrome bug https://crbug.com/1407629 width: this.videoWidth(), - height: this.videoHeight(), - copyStyleSheets: true + height: this.videoHeight() }).then(pipWindow => { + Dom.copyStyleSheetsToWindow(pipWindow); this.el_.parentNode.insertBefore(pipContainer, this.el_); pipWindow.document.body.append(this.el_); diff --git a/src/js/utils/dom.js b/src/js/utils/dom.js index 80a92dd21d..4978bad96f 100644 --- a/src/js/utils/dom.js +++ b/src/js/utils/dom.js @@ -857,3 +857,30 @@ export function computedStyle(el, prop) { return ''; } + +/** + * Copy document style sheets to another window. + * + * @param {Window} win + * The window element you want to copy the document style sheets to. + * + */ +export function copyStyleSheetsToWindow(win) { + [...document.styleSheets].forEach((styleSheet) => { + try { + const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join(''); + const style = document.createElement('style'); + + style.textContent = cssRules; + win.document.head.appendChild(style); + } catch (e) { + const link = document.createElement('link'); + + link.rel = 'stylesheet'; + link.type = styleSheet.type; + link.media = styleSheet.media; + link.href = styleSheet.href; + win.document.head.appendChild(link); + } + }); +} diff --git a/test/unit/player.test.js b/test/unit/player.test.js index e283838e91..b1d6d77124 100644 --- a/test/unit/player.test.js +++ b/test/unit/player.test.js @@ -2919,6 +2919,7 @@ QUnit.test('docPiP moves player and triggers events', function(assert) { const fakePiPWindow = document.createElement('div'); fakePiPWindow.document = { + head: document.createElement('div'), body: document.createElement('div') }; fakePiPWindow.querySelector = function(sel) { diff --git a/test/unit/utils/dom.test.js b/test/unit/utils/dom.test.js index 811cd4c617..bda4bdda36 100644 --- a/test/unit/utils/dom.test.js +++ b/test/unit/utils/dom.test.js @@ -686,3 +686,52 @@ QUnit.test('isSingleLeftClick() checks return values for mousedown event', funct assert.ok(Dom.isSingleLeftClick(mouseEvent), 'a touch event on simulated mobiles is a single left click'); }); + +QUnit.test('Dom.copyStyleSheetsToWindow() copies all style sheets to a window', function(assert) { + const fakeWindow = document.createElement('div'); + const done = assert.async(); + + assert.expect(7); + + fakeWindow.document = { + head: document.createElement('div') + }; + + const style1 = document.createElement('style'); + + style1.textContent = 'body { background: white; }'; + document.head.appendChild(style1); + + const style2 = document.createElement('style'); + + style2.textContent = 'body { margin: 0px; }'; + document.head.appendChild(style2); + + const link = document.createElement('link'); + + link.rel = 'stylesheet'; + link.type = 'text/css'; + link.media = 'print'; + link.href = 'http://asdf.com/styles.css'; + + const containsRulesFromStyle = (el) => { + return Boolean([...fakeWindow.document.head.querySelectorAll('style')].find(s => { + return s.textContent.includes(el.textContent); + })); + }; + + link.onload = link.onerror = () => { + Dom.copyStyleSheetsToWindow(fakeWindow); + assert.strictEqual(fakeWindow.document.head.querySelectorAll('style, link').length, document.styleSheets.length, 'the fake window has as many