aboutsummaryrefslogtreecommitdiff
path: root/ext/mixed/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-06-24 21:46:13 -0400
committerGitHub <noreply@github.com>2020-06-24 21:46:13 -0400
commit3e68af8666bdf9a6d8d605f7a3bb0432c8d6cb33 (patch)
tree5674e8a865b9a55983dd2e9d54a263fb0cb99105 /ext/mixed/js
parent96932119f8627725774ffdc66a82326d7302db30 (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/js')
-rw-r--r--ext/mixed/js/api.js4
-rw-r--r--ext/mixed/js/dynamic-loader.js49
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;
}