Merge pull request #367 from toasted-nutbread/defer-content-script-css-injection
Defer content script css injection
This commit is contained in:
commit
2ace8d4ffa
@ -499,19 +499,30 @@ class Backend {
|
|||||||
return Promise.resolve({frameId});
|
return Promise.resolve({frameId});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onApiInjectStylesheet({css}, sender) {
|
_onApiInjectStylesheet({type, value}, sender) {
|
||||||
if (!sender.tab) {
|
if (!sender.tab) {
|
||||||
return Promise.reject(new Error('Invalid tab'));
|
return Promise.reject(new Error('Invalid tab'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabId = sender.tab.id;
|
const tabId = sender.tab.id;
|
||||||
const frameId = sender.frameId;
|
const frameId = sender.frameId;
|
||||||
const details = {
|
const details = (
|
||||||
code: css,
|
type === 'file' ?
|
||||||
|
{
|
||||||
|
file: value,
|
||||||
|
runAt: 'document_start',
|
||||||
|
cssOrigin: 'author',
|
||||||
|
allFrames: false,
|
||||||
|
matchAboutBlank: true
|
||||||
|
} :
|
||||||
|
{
|
||||||
|
code: value,
|
||||||
runAt: 'document_start',
|
runAt: 'document_start',
|
||||||
cssOrigin: 'user',
|
cssOrigin: 'user',
|
||||||
allFrames: false
|
allFrames: false,
|
||||||
};
|
matchAboutBlank: true
|
||||||
|
}
|
||||||
|
);
|
||||||
if (typeof frameId === 'number') {
|
if (typeof frameId === 'number') {
|
||||||
details.frameId = frameId;
|
details.frameId = frameId;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ class SettingsPopupPreview {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.frontend = null;
|
this.frontend = null;
|
||||||
this.apiOptionsGetOld = apiOptionsGet;
|
this.apiOptionsGetOld = apiOptionsGet;
|
||||||
this.popupInjectOuterStylesheetOld = Popup.injectOuterStylesheet;
|
this.popup = null;
|
||||||
|
this.popupSetCustomOuterCssOld = null;
|
||||||
this.popupShown = false;
|
this.popupShown = false;
|
||||||
this.themeChangeTimeout = null;
|
this.themeChangeTimeout = null;
|
||||||
this.textSource = null;
|
this.textSource = null;
|
||||||
@ -50,19 +51,19 @@ class SettingsPopupPreview {
|
|||||||
const popupHost = new PopupProxyHost();
|
const popupHost = new PopupProxyHost();
|
||||||
await popupHost.prepare();
|
await popupHost.prepare();
|
||||||
|
|
||||||
const popup = popupHost.getOrCreatePopup();
|
this.popup = popupHost.getOrCreatePopup();
|
||||||
popup.setChildrenSupported(false);
|
this.popup.setChildrenSupported(false);
|
||||||
|
|
||||||
this.frontend = new Frontend(popup);
|
this.popupSetCustomOuterCssOld = this.popup.setCustomOuterCss;
|
||||||
|
this.popup.setCustomOuterCss = (...args) => this.popupSetCustomOuterCss(...args);
|
||||||
|
|
||||||
|
this.frontend = new Frontend(this.popup);
|
||||||
|
|
||||||
this.frontend.setEnabled = function () {};
|
this.frontend.setEnabled = function () {};
|
||||||
this.frontend.searchClear = function () {};
|
this.frontend.searchClear = function () {};
|
||||||
|
|
||||||
await this.frontend.prepare();
|
await this.frontend.prepare();
|
||||||
|
|
||||||
// Overwrite popup
|
|
||||||
Popup.injectOuterStylesheet = (...args) => this.popupInjectOuterStylesheet(...args);
|
|
||||||
|
|
||||||
// Update search
|
// Update search
|
||||||
this.updateSearch();
|
this.updateSearch();
|
||||||
}
|
}
|
||||||
@ -83,14 +84,13 @@ class SettingsPopupPreview {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
popupInjectOuterStylesheet(...args) {
|
async popupSetCustomOuterCss(...args) {
|
||||||
// This simulates the stylesheet priorities when injecting using the web extension API.
|
// This simulates the stylesheet priorities when injecting using the web extension API.
|
||||||
const result = this.popupInjectOuterStylesheetOld(...args);
|
const result = await this.popupSetCustomOuterCssOld.call(this.popup, ...args);
|
||||||
|
|
||||||
const outerStylesheet = Popup.outerStylesheet;
|
|
||||||
const node = document.querySelector('#client-css');
|
const node = document.querySelector('#client-css');
|
||||||
if (node !== null && outerStylesheet !== null) {
|
if (node !== null && result !== null) {
|
||||||
node.parentNode.insertBefore(outerStylesheet, node);
|
node.parentNode.insertBefore(result, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -137,7 +137,7 @@ class SettingsPopupPreview {
|
|||||||
|
|
||||||
setCustomOuterCss(css) {
|
setCustomOuterCss(css) {
|
||||||
if (this.frontend === null) { return; }
|
if (this.frontend === null) { return; }
|
||||||
this.frontend.popup.setCustomOuterCss(css, true);
|
this.frontend.popup.setCustomOuterCss(css, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSearch() {
|
async updateSearch() {
|
||||||
|
@ -31,7 +31,6 @@ class Popup {
|
|||||||
this._visible = false;
|
this._visible = false;
|
||||||
this._visibleOverride = null;
|
this._visibleOverride = null;
|
||||||
this._options = null;
|
this._options = null;
|
||||||
this._stylesheetInjectedViaApi = false;
|
|
||||||
this._contentScale = 1.0;
|
this._contentScale = 1.0;
|
||||||
this._containerSizeContentScale = null;
|
this._containerSizeContentScale = null;
|
||||||
|
|
||||||
@ -158,21 +157,13 @@ class Popup {
|
|||||||
this._container.dataset.yomichanSiteColor = this._getSiteColor();
|
this._container.dataset.yomichanSiteColor = this._getSiteColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setCustomOuterCss(css, injectDirectly) {
|
async setCustomOuterCss(css, useWebExtensionApi) {
|
||||||
// Cannot repeatedly inject stylesheets using web extension APIs since there is no way to remove them.
|
return await Popup._injectStylesheet(
|
||||||
if (this._stylesheetInjectedViaApi) { return; }
|
'yomichan-popup-outer-user-stylesheet',
|
||||||
|
'code',
|
||||||
if (injectDirectly || Popup._isOnExtensionPage()) {
|
css,
|
||||||
Popup.injectOuterStylesheet(css);
|
useWebExtensionApi
|
||||||
} else {
|
);
|
||||||
if (!css) { return; }
|
|
||||||
try {
|
|
||||||
await apiInjectStylesheet(css);
|
|
||||||
this._stylesheetInjectedViaApi = true;
|
|
||||||
} catch (e) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setChildrenSupported(value) {
|
setChildrenSupported(value) {
|
||||||
@ -187,26 +178,6 @@ class Popup {
|
|||||||
return this._container.getBoundingClientRect();
|
return this._container.getBoundingClientRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
static injectOuterStylesheet(css) {
|
|
||||||
if (Popup.outerStylesheet === null) {
|
|
||||||
if (!css) { return; }
|
|
||||||
Popup.outerStylesheet = document.createElement('style');
|
|
||||||
Popup.outerStylesheet.id = 'yomichan-popup-outer-stylesheet';
|
|
||||||
}
|
|
||||||
|
|
||||||
const outerStylesheet = Popup.outerStylesheet;
|
|
||||||
if (css) {
|
|
||||||
outerStylesheet.textContent = css;
|
|
||||||
|
|
||||||
const par = document.head;
|
|
||||||
if (par && outerStylesheet.parentNode !== par) {
|
|
||||||
par.appendChild(outerStylesheet);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
outerStylesheet.textContent = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private functions
|
// Private functions
|
||||||
|
|
||||||
_inject() {
|
_inject() {
|
||||||
@ -248,10 +219,24 @@ class Popup {
|
|||||||
});
|
});
|
||||||
this._observeFullscreen(true);
|
this._observeFullscreen(true);
|
||||||
this._onFullscreenChanged();
|
this._onFullscreenChanged();
|
||||||
this.setCustomOuterCss(this._options.general.customPopupOuterCss, false);
|
this._injectStyles();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _injectStyles() {
|
||||||
|
try {
|
||||||
|
await Popup._injectStylesheet('yomichan-popup-outer-stylesheet', 'file', '/fg/css/client.css', true);
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.setCustomOuterCss(this._options.general.customPopupOuterCss, true);
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_observeFullscreen(observe) {
|
_observeFullscreen(observe) {
|
||||||
if (!observe) {
|
if (!observe) {
|
||||||
this._fullscreenEventListeners.removeAllEventListeners();
|
this._fullscreenEventListeners.removeAllEventListeners();
|
||||||
@ -526,15 +511,6 @@ class Popup {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
static _isOnExtensionPage() {
|
|
||||||
try {
|
|
||||||
const url = chrome.runtime.getURL('/');
|
|
||||||
return window.location.href.substring(0, url.length) === url;
|
|
||||||
} catch (e) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static _getViewport(useVisualViewport) {
|
static _getViewport(useVisualViewport) {
|
||||||
const visualViewport = window.visualViewport;
|
const visualViewport = window.visualViewport;
|
||||||
if (visualViewport !== null && typeof visualViewport === 'object') {
|
if (visualViewport !== null && typeof visualViewport === 'object') {
|
||||||
@ -567,6 +543,80 @@ class Popup {
|
|||||||
bottom: window.innerHeight
|
bottom: window.innerHeight
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _isOnExtensionPage() {
|
||||||
|
try {
|
||||||
|
const url = chrome.runtime.getURL('/');
|
||||||
|
return window.location.href.substring(0, url.length) === url;
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async _injectStylesheet(id, type, value, useWebExtensionApi) {
|
||||||
|
const injectedStylesheets = Popup._injectedStylesheets;
|
||||||
|
|
||||||
|
if (Popup._isOnExtensionPage()) {
|
||||||
|
// Permissions error will occur if trying to use the WebExtension API to inject
|
||||||
|
// into an extension page.
|
||||||
|
useWebExtensionApi = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let styleNode = injectedStylesheets.get(id);
|
||||||
|
if (typeof styleNode !== 'undefined') {
|
||||||
|
if (styleNode === null) {
|
||||||
|
// Previously injected via WebExtension API
|
||||||
|
throw new Error(`Stylesheet with id ${id} has already been injected using the WebExtension API`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
styleNode = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useWebExtensionApi) {
|
||||||
|
// Inject via WebExtension API
|
||||||
|
if (styleNode !== null && styleNode.parentNode !== null) {
|
||||||
|
styleNode.parentNode.removeChild(styleNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiInjectStylesheet(type, value);
|
||||||
|
|
||||||
|
injectedStylesheets.set(id, null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create node in document
|
||||||
|
const parentNode = document.head;
|
||||||
|
if (parentNode === null) {
|
||||||
|
throw new Error('No parent node');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or reuse node
|
||||||
|
const isFile = (type === 'file');
|
||||||
|
const tagName = isFile ? 'link' : 'style';
|
||||||
|
if (styleNode === null || styleNode.nodeName.toLowerCase() !== tagName) {
|
||||||
|
if (styleNode !== null && styleNode.parentNode !== null) {
|
||||||
|
styleNode.parentNode.removeChild(styleNode);
|
||||||
|
}
|
||||||
|
styleNode = document.createElement(tagName);
|
||||||
|
styleNode.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update node style
|
||||||
|
if (isFile) {
|
||||||
|
styleNode.rel = value;
|
||||||
|
} else {
|
||||||
|
styleNode.textContent = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update parent
|
||||||
|
if (styleNode.parentNode !== parentNode) {
|
||||||
|
parentNode.appendChild(styleNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to map
|
||||||
|
injectedStylesheets.set(id, styleNode);
|
||||||
|
return styleNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Popup.outerStylesheet = null;
|
Popup._injectedStylesheets = new Map();
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
"fg/js/frontend.js",
|
"fg/js/frontend.js",
|
||||||
"fg/js/frontend-initialize.js"
|
"fg/js/frontend-initialize.js"
|
||||||
],
|
],
|
||||||
"css": ["fg/css/client.css"],
|
|
||||||
"match_about_blank": true,
|
"match_about_blank": true,
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
}],
|
}],
|
||||||
|
@ -89,8 +89,8 @@ function apiFrameInformationGet() {
|
|||||||
return _apiInvoke('frameInformationGet');
|
return _apiInvoke('frameInformationGet');
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiInjectStylesheet(css) {
|
function apiInjectStylesheet(type, value) {
|
||||||
return _apiInvoke('injectStylesheet', {css});
|
return _apiInvoke('injectStylesheet', {type, value});
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiGetEnvironmentInfo() {
|
function apiGetEnvironmentInfo() {
|
||||||
|
Loading…
Reference in New Issue
Block a user