diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-06-24 21:46:13 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-24 21:46:13 -0400 |
commit | 3e68af8666bdf9a6d8d605f7a3bb0432c8d6cb33 (patch) | |
tree | 5674e8a865b9a55983dd2e9d54a263fb0cb99105 /ext/mixed | |
parent | 96932119f8627725774ffdc66a82326d7302db30 (diff) |
Shadow DOM container for popup iframes (#623)
* Add support for injecting stylesheets into a custom parent node
* Add api.getStylesheetContent
* Add support for injecting a CSS file's content
* Add usePopupShadowDom option
* Use a per-parentNode cache
* Add support for using a shadow DOM wrapper around popup iframes
* Ignore the popup container instead of the frame
Diffstat (limited to 'ext/mixed')
-rw-r--r-- | ext/mixed/js/api.js | 4 | ||||
-rw-r--r-- | ext/mixed/js/dynamic-loader.js | 49 |
2 files changed, 44 insertions, 9 deletions
diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index c54196e2..5c17d50e 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -121,6 +121,10 @@ const api = (() => { return this._invoke('injectStylesheet', {type, value}); } + getStylesheetContent(url) { + return this._invoke('getStylesheetContent', {url}); + } + getEnvironmentInfo() { return this._invoke('getEnvironmentInfo'); } diff --git a/ext/mixed/js/dynamic-loader.js b/ext/mixed/js/dynamic-loader.js index 37f85112..981d1ee5 100644 --- a/ext/mixed/js/dynamic-loader.js +++ b/ext/mixed/js/dynamic-loader.js @@ -21,14 +21,36 @@ const dynamicLoader = (() => { const injectedStylesheets = new Map(); + const injectedStylesheetsWithParent = new WeakMap(); - async function loadStyle(id, type, value, useWebExtensionApi=false) { + function getInjectedStylesheet(id, parentNode) { + if (parentNode === null) { + return injectedStylesheets.get(id); + } + const map = injectedStylesheetsWithParent.get(parentNode); + return typeof map !== 'undefined' ? map.get(id) : void 0; + } + + function setInjectedStylesheet(id, parentNode, value) { + if (parentNode === null) { + injectedStylesheets.set(id, value); + return; + } + let map = injectedStylesheetsWithParent.get(parentNode); + if (typeof map === 'undefined') { + map = new Map(); + injectedStylesheetsWithParent.set(parentNode, map); + } + map.set(id, value); + } + + async function loadStyle(id, type, value, useWebExtensionApi=false, parentNode=null) { if (useWebExtensionApi && yomichan.isExtensionUrl(window.location.href)) { // Permissions error will occur if trying to use the WebExtension API to inject into an extension page useWebExtensionApi = false; } - let styleNode = injectedStylesheets.get(id); + let styleNode = getInjectedStylesheet(id, parentNode); if (typeof styleNode !== 'undefined') { if (styleNode === null) { // Previously injected via WebExtension API @@ -38,21 +60,30 @@ const dynamicLoader = (() => { styleNode = null; } + if (type === 'file-content') { + value = await api.getStylesheetContent(value); + type = 'code'; + useWebExtensionApi = false; + } + if (useWebExtensionApi) { // Inject via WebExtension API if (styleNode !== null && styleNode.parentNode !== null) { styleNode.parentNode.removeChild(styleNode); } - injectedStylesheets.set(id, null); + setInjectedStylesheet(id, parentNode, null); await api.injectStylesheet(type, value); return null; } // Create node in document - const parentNode = document.head; - if (parentNode === null) { - throw new Error('No parent node'); + let parentNode2 = parentNode; + if (parentNode2 === null) { + parentNode2 = document.head; + if (parentNode2 === null) { + throw new Error('No parent node'); + } } // Create or reuse node @@ -74,12 +105,12 @@ const dynamicLoader = (() => { } // Update parent - if (styleNode.parentNode !== parentNode) { - parentNode.appendChild(styleNode); + if (styleNode.parentNode !== parentNode2) { + parentNode2.appendChild(styleNode); } // Add to map - injectedStylesheets.set(id, styleNode); + setInjectedStylesheet(id, parentNode, styleNode); return styleNode; } |