diff --git a/README.md b/README.md index 658bf69..015289f 100644 --- a/README.md +++ b/README.md @@ -102,3 +102,6 @@ from the `element.adoptedStyleSheets` array. The behavior here is supposed to emulate a `FrozenArray`, so modifying the array in question will have no effect until the value is changed using a setter. +## A note about versioning + +This packages doesn't necessarily follow semantic versioning. As the spec is still under consideration and implementation by browser vendors, the features supported by this package will change (generally following Chrome's implementation). \ No newline at end of file diff --git a/src/ConstructStyleSheet.js b/src/ConstructStyleSheet.js index 7de4112..2391569 100644 --- a/src/ConstructStyleSheet.js +++ b/src/ConstructStyleSheet.js @@ -4,9 +4,7 @@ import { sheetMetadataRegistry, state, } from './shared'; -import {instanceOfStyleSheet} from './utils'; - -const importPattern = /@import/; +import {instanceOfStyleSheet, rejectImports} from './utils'; const cssStyleSheetMethods = [ 'addImport', @@ -96,17 +94,18 @@ export default class ConstructStyleSheet { } replace(contents) { + const sanitized = rejectImports(contents); return new Promise((resolve, reject) => { if (sheetMetadataRegistry.has(this)) { const {basicStyleElement} = sheetMetadataRegistry.get(this); - basicStyleElement.innerHTML = contents; + basicStyleElement.innerHTML = sanitized; resolve(basicStyleElement.sheet); updateAdopters(this); } else { reject( new Error( - "Failed to execute 'replace' on 'CSSStyleSheet': Can't call replace on non-constructed CSSStyleSheets.", + "Can't call replace on non-constructed CSSStyleSheets.", ), ); } @@ -114,16 +113,12 @@ export default class ConstructStyleSheet { } replaceSync(contents) { - if (importPattern.test(contents)) { - throw new Error( - '@import rules are not allowed when creating stylesheet synchronously', - ); - } + const sanitized = rejectImports(contents); if (sheetMetadataRegistry.has(this)) { const {basicStyleElement} = sheetMetadataRegistry.get(this); - basicStyleElement.innerHTML = contents; + basicStyleElement.innerHTML = sanitized; updateAdopters(this); return basicStyleElement.sheet; diff --git a/src/adopt.js b/src/adopt.js index 7d18b02..4bf512d 100644 --- a/src/adopt.js +++ b/src/adopt.js @@ -78,7 +78,6 @@ export function adoptStyleSheets(location) { export function removeExcludedStyleSheets(location, oldSheets) { const sheets = getAdoptedStyleSheet(location); - for (let i = 0, len = oldSheets.length; i < len; i++) { if (sheets.indexOf(oldSheets[i]) > -1) { continue; @@ -86,7 +85,13 @@ export function removeExcludedStyleSheets(location, oldSheets) { const {adopters} = sheetMetadataRegistry.get(oldSheets[i]); const observer = observerRegistry.get(location); - const styleElement = adopters.get(location); + let styleElement = adopters.get(location); + + // In case the sheet was saved to document.head + // before the document was ready + if (!styleElement) { + styleElement = adopters.get(document.head); + } observer.disconnect(); styleElement.parentNode.removeChild(styleElement); diff --git a/src/utils.js b/src/utils.js index 2e3fd25..0f2176e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,7 @@ import {adoptedSheetsRegistry, frame, OldCSSStyleSheet} from './shared'; +const importPattern = /@import\surl(.*?);/gi; + export function instanceOfStyleSheet(instance) { return ( instance instanceof OldCSSStyleSheet || @@ -41,3 +43,17 @@ export function getAdoptedStyleSheet(location) { : location, ); } + +export function rejectImports(contents) { + const imports = contents.match(importPattern, '') || []; + let sheetContent = contents; + if (imports.length) { + console.warn( + '@import rules are not allowed here. See https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418' + ); + imports.forEach(_import => { + sheetContent = sheetContent.replace(_import, ''); + }); + } + return sheetContent; +} diff --git a/test/polyfill.test.js b/test/polyfill.test.js index eeb9d30..e01e5f0 100644 --- a/test/polyfill.test.js +++ b/test/polyfill.test.js @@ -73,7 +73,7 @@ describe('Constructible Style Sheets polyfill', () => { .replace('.only-test { color: blue; }') .catch(error => { expect(error.message).toBe( - "Failed to execute 'replace' on 'CSSStyleSheet': Can't call replace on non-constructed CSSStyleSheets.", + "Can't call replace on non-constructed CSSStyleSheets.", ); }); });