diff --git a/README.md b/README.md index 1f74a37..740fba4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ This polyfill will create a new style element for every `DocumentOrShadowRoot` i No changes will occur in a browser that supports the feature by default. +## Requirements + +This polyfill should work as-is in modern browsers, however, to support IE11, you will also need to consume a polyfill for [ECMAScript `Symbol`s](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol). One popular and well supported option is [Core-JS](https://www.npmjs.com/package/core-js) which includes polyfills for many other modern features alongside a polyfill for `Symbol`. + ## Installation The package can be installed either by copying the [polyfill file](./adoptedStyleSheets.js) or by [installing using npm](https://docs.npmjs.com/getting-started/). diff --git a/adoptedStyleSheets.js b/adoptedStyleSheets.js index c32dc3f..270dad3 100644 --- a/adoptedStyleSheets.js +++ b/adoptedStyleSheets.js @@ -39,7 +39,7 @@ // Move style elements created before document.body // to the iframe along with future styles deferredStyleSheets.forEach(nativeStyleSheet => { - frameBody.append(nativeStyleSheet); + frameBody.appendChild(nativeStyleSheet); nativeStyleSheet.disabled = false; }); @@ -112,78 +112,79 @@ // cannot be instantiated. The `new` operation will return the native // CSSStyleSheet object extracted from a style element appended to the // iframe. - class ConstructStyleSheet { - // Allows instanceof checks with the window.CSSStyleSheet. - static [Symbol.hasInstance](instance) { - return instance instanceof OldCSSStyleSheet; + function ConstructStyleSheet() { + // A style element to extract the native CSSStyleSheet object. + const basicStyleElement = document.createElement('style'); + + if (polyfillLoaded) { + // If the polyfill is ready, use the framebody + frameBody.appendChild(basicStyleElement); + } else { + // If the polyfill is not ready, move styles to head temporarily + document.head.appendChild(basicStyleElement); + basicStyleElement.disabled = true; + deferredStyleSheets.push(basicStyleElement); } - constructor() { - // A style element to extract the native CSSStyleSheet object. - const basicStyleElement = document.createElement('style'); + const nativeStyleSheet = basicStyleElement.sheet; - if (polyfillLoaded) { - // If the polyfill is ready, use the framebody - frameBody.append(basicStyleElement); - } else { - // If the polyfill is not ready, move styles to head temporarily - document.head.append(basicStyleElement); - basicStyleElement.disabled = true; - deferredStyleSheets.push(basicStyleElement); - } - - const nativeStyleSheet = basicStyleElement.sheet; - - // A support object to preserve all the polyfill data - constructStyleSheetRegistry.set(nativeStyleSheet, { - adopters: new Map(), - actions: [], - basicStyleElement, - }); - - return nativeStyleSheet; - } + // A support object to preserve all the polyfill data + constructStyleSheetRegistry.set(nativeStyleSheet, { + adopters: new Map(), + actions: [], + basicStyleElement, + }); - replace(contents) { - return new Promise((resolve, reject) => { - if (constructStyleSheetRegistry.has(this)) { - const {basicStyleElement} = constructStyleSheetRegistry.get(this); - - basicStyleElement.innerHTML = contents; - resolve(basicStyleElement.sheet); - updateAdopters(this); - } else { - reject( - new DOMException( - "Failed to execute 'replace' on 'CSSStyleSheet': Can't call replace on non-constructed CSSStyleSheets.", - 'NotAllowedError', - ), - ); - } - }); - } + return nativeStyleSheet; + } - replaceSync(contents) { - if (importPattern.test(contents)) { - throw new DOMException( - '@import rules are not allowed when creating stylesheet synchronously', - 'NotAllowedError', - ); + Object.defineProperty(ConstructStyleSheet, Symbol.hasInstance, { + get() { + return function(instance) { + return instance instanceof OldCSSStyleSheet; } + } + }); + ConstructStyleSheet.prototype.replace = function(contents) { + return new Promise((resolve, reject) => { if (constructStyleSheetRegistry.has(this)) { const {basicStyleElement} = constructStyleSheetRegistry.get(this); basicStyleElement.innerHTML = contents; + resolve(basicStyleElement.sheet); updateAdopters(this); - - return basicStyleElement.sheet; } else { - throw new DOMException( - "Failed to execute 'replaceSync' on 'CSSStyleSheet': Can't call replaceSync on non-constructed CSSStyleSheets.", - 'NotAllowedError', + reject( + new DOMException( + "Failed to execute 'replace' on 'CSSStyleSheet': Can't call replace on non-constructed CSSStyleSheets.", + 'NotAllowedError', + ), ); } + }); + } + + ConstructStyleSheet.prototype.replaceSync = function(contents) { + if (importPattern.test(contents)) { + throw new DOMException( + '@import rules are not allowed when creating stylesheet synchronously', + 'NotAllowedError', + ); + } + + if (constructStyleSheetRegistry.has(this)) { + const {basicStyleElement} = constructStyleSheetRegistry.get(this); + + basicStyleElement.innerHTML = contents; + updateAdopters(this); + + return basicStyleElement.sheet; + } else { + throw new DOMException( + "Failed to execute 'replaceSync' on 'CSSStyleSheet': Can't call replaceSync on non-constructed CSSStyleSheets.", + 'NotAllowedError', + ); } } @@ -208,7 +209,7 @@ const observer = observerRegistry.get(location); observer.disconnect(); - newStyles.append(adoptedStyleElement); + newStyles.appendChild(adoptedStyleElement); observer.observe(); } else { const clone = basicStyleElement.cloneNode(true); @@ -217,13 +218,18 @@ // element (e.g., it was disconnected). appliedActionsCursorRegistry.set(clone, 0); adopters.set(location, clone); - newStyles.append(clone); + newStyles.appendChild(clone); } } // Since we already removed all elements during appending them to the // document fragment, we can just re-add them again. - location.prepend(newStyles); + // we do this because IE11 doesn't support ParentNode.prepend + if (location.firstChild) { + location.insertBefore(newStyles, location.firstChild); + } else { + location.appendChild(newStyles); + } // We need to apply all actions we have done with the original CSSStyleSheet // to each new style element and to any other element that missed last