diff options
Diffstat (limited to 'ext/fg')
-rw-r--r-- | ext/fg/css/client.css | 8 | ||||
-rw-r--r-- | ext/fg/float.html | 12 | ||||
-rw-r--r-- | ext/fg/js/float.js | 21 | ||||
-rw-r--r-- | ext/fg/js/frontend.js | 8 | ||||
-rw-r--r-- | ext/fg/js/popup-proxy-host.js | 6 | ||||
-rw-r--r-- | ext/fg/js/popup-proxy.js | 5 | ||||
-rw-r--r-- | ext/fg/js/popup.js | 46 |
7 files changed, 73 insertions, 33 deletions
diff --git a/ext/fg/css/client.css b/ext/fg/css/client.css index a2b06d0f..84098653 100644 --- a/ext/fg/css/client.css +++ b/ext/fg/css/client.css @@ -21,7 +21,7 @@ iframe#yomichan-float { all: initial; background-color: #fff; border: 1px solid #999; - box-shadow: 0 0 10px rgba(0, 0, 0, .5); + box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); position: fixed; resize: both; visibility: hidden; @@ -29,6 +29,12 @@ iframe#yomichan-float { box-sizing: border-box; } +iframe#yomichan-float[data-yomichan-theme=dark] { + background-color: #1e1e1e; + border: 1px solid #666; + box-shadow: 0 0 10px rgba(255, 255, 255, 0.5); +} + iframe#yomichan-float.yomichan-float-full-width { border-left: none; border-right: none; diff --git a/ext/fg/float.html b/ext/fg/float.html index fe1aee8f..2504f448 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -1,18 +1,12 @@ <!DOCTYPE html> -<html lang="en"> +<html lang="en" class="yomichan-float"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title></title> - <link rel="stylesheet" href="/mixed/lib/bootstrap/css/bootstrap.min.css"> - <link rel="stylesheet" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="/mixed/css/display.css"> - <style type="text/css"> - .entry, .note { - padding-left: 10px; - padding-right: 10px; - } - </style> + <link rel="stylesheet" type="text/css" href="/mixed/css/display-default.css" data-yomichan-theme-name="default"> + <link rel="stylesheet alternate" type="text/css" href="/mixed/css/display-dark.css" data-yomichan-theme-name="dark"> </head> <body> <div id="spinner"> diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 5164cd8f..4b3cd848 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -21,7 +21,6 @@ class DisplayFloat extends Display { constructor() { super(document.querySelector('#spinner'), document.querySelector('#definitions')); this.autoPlayAudioTimer = null; - this.styleNode = null; this.optionsContext = { depth: 0, @@ -101,11 +100,6 @@ class DisplayFloat extends Display { async initialize(options, popupInfo, url, childrenSupported) { await super.initialize(options); - const css = options.general.customPopupCss; - if (css) { - this.setStyle(css); - } - const {id, depth, parentFrameId} = popupInfo; this.optionsContext.depth = depth; this.optionsContext.url = url; @@ -114,20 +108,6 @@ class DisplayFloat extends Display { popupNestedInitialize(id, depth, parentFrameId, url); } } - - setStyle(css) { - const parent = document.head; - - if (this.styleNode === null) { - this.styleNode = document.createElement('style'); - } - - this.styleNode.textContent = css; - - if (this.styleNode.parentNode !== parent) { - parent.appendChild(this.styleNode); - } - } } DisplayFloat.onKeyDownHandlers = { @@ -145,6 +125,7 @@ DisplayFloat.messageHandlers = { kanjiShow: (self, {definitions, context}) => self.kanjiShow(definitions, context), clearAutoPlayTimer: (self) => self.clearAutoPlayTimer(), orphaned: (self) => self.onOrphaned(), + setCustomCss: (self, {css}) => self.setCustomCss(css), initialize: (self, {options, popupInfo, url, childrenSupported}) => self.initialize(options, popupInfo, url, childrenSupported) }; diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 52a23889..3ddeae78 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -44,6 +44,8 @@ class Frontend { this.isPreparedPromiseResolve = null; this.isPreparedPromise = new Promise((resolve) => { this.isPreparedPromiseResolve = resolve; }); + + this.lastShowPromise = Promise.resolve(); } static create() { @@ -331,7 +333,7 @@ class Frontend { } catch (e) { if (window.yomichan_orphaned) { if (textSource && this.options.scanning.modifier !== 'none') { - this.popup.showOrphaned( + this.lastShowPromise = this.popup.showOrphaned( textSource.getRect(), textSource.getWritingMode() ); @@ -369,7 +371,7 @@ class Frontend { const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); const url = window.location.href; - this.popup.termsShow( + this.lastShowPromise = this.popup.termsShow( textSource.getRect(), textSource.getWritingMode(), definitions, @@ -399,7 +401,7 @@ class Frontend { const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); const url = window.location.href; - this.popup.kanjiShow( + this.lastShowPromise = this.popup.kanjiShow( textSource.getRect(), textSource.getWritingMode(), definitions, diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js index 74a5153a..bb323f64 100644 --- a/ext/fg/js/popup-proxy-host.js +++ b/ext/fg/js/popup-proxy-host.js @@ -45,6 +45,7 @@ class PopupProxyHost { containsPoint: ({id, x, y}) => this.containsPoint(id, x, y), termsShow: ({id, elementRect, writingMode, definitions, context}) => this.termsShow(id, elementRect, writingMode, definitions, context), kanjiShow: ({id, elementRect, writingMode, definitions, context}) => this.kanjiShow(id, elementRect, writingMode, definitions, context), + setCustomCss: ({id, css}) => this.setCustomCss(id, css), clearAutoPlayTimer: ({id}) => this.clearAutoPlayTimer(id) }); } @@ -126,6 +127,11 @@ class PopupProxyHost { return await popup.kanjiShow(elementRect, writingMode, definitions, context); } + async setCustomCss(id, css) { + const popup = this.getPopup(id); + return popup.setCustomCss(css); + } + async clearAutoPlayTimer(id) { const popup = this.getPopup(id); return popup.clearAutoPlayTimer(); diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index e8d6bc98..6ea94b6a 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -88,6 +88,11 @@ class PopupProxy { return await this.invokeHostApi('kanjiShow', {id, elementRect, writingMode, definitions, context}); } + async setCustomCss(css) { + const id = await this.getPopupId(); + return await this.invokeHostApi('setCustomCss', {id, css}); + } + async clearAutoPlayTimer() { if (this.id === null) { return; diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index f36bb436..ef4cdb67 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -85,6 +85,7 @@ class Popup { async setOptions(options) { this.options = options; + this.updateTheme(); } async show(elementRect, writingMode) { @@ -269,6 +270,47 @@ class Popup { } } + updateTheme() { + this.container.dataset.yomichanTheme = this.getTheme(this.options.general.popupOuterTheme); + } + + getTheme(themeName) { + if (themeName === 'auto') { + const color = [255, 255, 255]; + Popup.addColor(color, Popup.getColorInfo(window.getComputedStyle(document.documentElement).backgroundColor)); + Popup.addColor(color, Popup.getColorInfo(window.getComputedStyle(document.body).backgroundColor)); + const dark = (color[0] < 128 && color[1] < 128 && color[2] < 128); + themeName = dark ? 'dark' : 'default'; + } + + return themeName; + } + + static addColor(target, color) { + if (color === null) { return; } + + const a = color[3]; + if (a <= 0.0) { return; } + + const aInv = 1.0 - a; + for (let i = 0; i < 3; ++i) { + target[i] = target[i] * aInv + color[i] * a; + } + } + + static getColorInfo(cssColor) { + const m = /^\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d\.]+)\s*)?\)\s*$/.exec(cssColor); + if (m === null) { return null; } + + const m4 = m[4]; + return [ + Number.parseInt(m[1], 10), + Number.parseInt(m[2], 10), + Number.parseInt(m[3], 10), + m4 ? Math.max(0.0, Math.min(1.0, Number.parseFloat(m4))) : 1.0 + ]; + } + async containsPoint(x, y) { for (let popup = this; popup !== null && popup.isVisible(); popup = popup.child) { const rect = popup.container.getBoundingClientRect(); @@ -291,6 +333,10 @@ class Popup { this.invokeApi('kanjiShow', {definitions, context}); } + async setCustomCss(css) { + this.invokeApi('setCustomCss', {css}); + } + clearAutoPlayTimer() { if (this.isInjected) { this.invokeApi('clearAutoPlayTimer'); |