Allow outer popup stylesheets to be injected

This commit is contained in:
toasted-nutbread 2019-10-13 11:46:27 -04:00
parent 3272948284
commit c9158a37b5
4 changed files with 84 additions and 0 deletions

View File

@ -241,3 +241,32 @@ function apiFrameInformationGet(sender) {
const frameId = sender.frameId; const frameId = sender.frameId;
return Promise.resolve({frameId}); return Promise.resolve({frameId});
} }
function apiInjectStylesheet(css, sender) {
if (!sender.tab) {
return Promise.reject(new Error('Invalid tab'));
}
const tabId = sender.tab.id;
const frameId = sender.frameId;
const details = {
code: css,
runAt: 'document_start',
cssOrigin: 'user',
allFrames: false
};
if (typeof frameId === 'number') {
details.frameId = frameId;
}
return new Promise((resolve, reject) => {
chrome.tabs.insertCSS(tabId, details, () => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve();
}
});
});
}

View File

@ -185,6 +185,7 @@ Backend.messageHandlers = {
screenshotGet: ({options}, sender) => apiScreenshotGet(options, sender), screenshotGet: ({options}, sender) => apiScreenshotGet(options, sender),
forward: ({action, params}, sender) => apiForward(action, params, sender), forward: ({action, params}, sender) => apiForward(action, params, sender),
frameInformationGet: (params, sender) => apiFrameInformationGet(sender), frameInformationGet: (params, sender) => apiFrameInformationGet(sender),
injectStylesheet: ({css}, sender) => apiInjectStylesheet(css, sender)
}; };
window.yomichan_backend = new Backend(); window.yomichan_backend = new Backend();

View File

@ -64,3 +64,7 @@ function apiForward(action, params) {
function apiFrameInformationGet() { function apiFrameInformationGet() {
return utilInvoke('frameInformationGet'); return utilInvoke('frameInformationGet');
} }
function apiInjectStylesheet(css) {
return utilInvoke('injectStylesheet', {css});
}

View File

@ -38,6 +38,7 @@ class Popup {
this.visible = false; this.visible = false;
this.visibleOverride = null; this.visibleOverride = null;
this.options = null; this.options = null;
this.stylesheetInjectedViaApi = false;
this.updateVisibility(); this.updateVisibility();
} }
@ -75,6 +76,7 @@ class Popup {
}); });
this.observeFullscreen(); this.observeFullscreen();
this.onFullscreenChanged(); this.onFullscreenChanged();
this.setCustomOuterCss(this.options.general.customPopupOuterCss, false);
this.isInjected = true; this.isInjected = true;
}); });
} }
@ -334,6 +336,23 @@ class Popup {
this.invokeApi('setCustomCss', {css}); this.invokeApi('setCustomCss', {css});
} }
async setCustomOuterCss(css, injectDirectly) {
// Cannot repeatedly inject stylesheets using web extension APIs since there is no way to remove them.
if (this.stylesheetInjectedViaApi) { return; }
if (injectDirectly || Popup.isOnExtensionPage()) {
Popup.injectOuterStylesheet(css);
} else {
if (!css) { return; }
try {
await apiInjectStylesheet(css);
this.stylesheetInjectedViaApi = true;
} catch (e) {
// NOP
}
}
}
clearAutoPlayTimer() { clearAutoPlayTimer() {
if (this.isInjected) { if (this.isInjected) {
this.invokeApi('clearAutoPlayTimer'); this.invokeApi('clearAutoPlayTimer');
@ -375,4 +394,35 @@ class Popup {
get url() { get url() {
return window.location.href; return window.location.href;
} }
static isOnExtensionPage() {
try {
const url = chrome.runtime.getURL('/');
return window.location.href.substr(0, url.length) === url;
} catch (e) {
// NOP
} }
}
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 = '';
}
}
}
Popup.outerStylesheet = null;