diff options
Diffstat (limited to 'ext/fg/js')
-rw-r--r-- | ext/fg/js/document.js | 6 | ||||
-rw-r--r-- | ext/fg/js/float.js | 64 | ||||
-rw-r--r-- | ext/fg/js/frontend-api-sender.js | 3 | ||||
-rw-r--r-- | ext/fg/js/frontend-initialize.js | 10 | ||||
-rw-r--r-- | ext/fg/js/frontend.js | 41 | ||||
-rw-r--r-- | ext/fg/js/popup-nested.js | 4 | ||||
-rw-r--r-- | ext/fg/js/popup-proxy-host.js | 67 | ||||
-rw-r--r-- | ext/fg/js/popup-proxy.js | 4 | ||||
-rw-r--r-- | ext/fg/js/popup.js | 7 |
9 files changed, 121 insertions, 85 deletions
diff --git a/ext/fg/js/document.js b/ext/fg/js/document.js index 35861475..490f61bb 100644 --- a/ext/fg/js/document.js +++ b/ext/fg/js/document.js @@ -16,7 +16,11 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global TextSourceElement, TextSourceRange, DOM*/ +/* global + * DOM + * TextSourceElement + * TextSourceRange + */ const REGEX_TRANSPARENT_COLOR = /rgba\s*\([^)]*,\s*0(?:\.0+)?\s*\)/; diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 8f21a9c5..393c2719 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -16,7 +16,12 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global popupNestedInitialize, apiForward, apiGetMessageToken, Display*/ +/* global + * Display + * apiForward + * apiGetMessageToken + * popupNestedInitialize + */ class DisplayFloat extends Display { constructor() { @@ -33,8 +38,27 @@ class DisplayFloat extends Display { this._messageToken = null; this._messageTokenPromise = null; - yomichan.on('orphaned', () => this.onOrphaned()); - window.addEventListener('message', (e) => this.onMessage(e), false); + this._onKeyDownHandlers = new Map([ + ['C', (e) => { + if (e.ctrlKey && !window.getSelection().toString()) { + this.onSelectionCopy(); + return true; + } + return false; + }], + ...this._onKeyDownHandlers + ]); + + this._windowMessageHandlers = new Map([ + ['setContent', ({type, details}) => this.setContent(type, details)], + ['clearAutoPlayTimer', () => this.clearAutoPlayTimer()], + ['setCustomCss', ({css}) => this.setCustomCss(css)], + ['prepare', ({options, popupInfo, url, childrenSupported, scale, uniqueId}) => this.prepare(options, popupInfo, url, childrenSupported, scale, uniqueId)], + ['setContentScale', ({scale}) => this.setContentScale(scale)] + ]); + + yomichan.on('orphaned', this.onOrphaned.bind(this)); + window.addEventListener('message', this.onMessage.bind(this), false); } async prepare(options, popupInfo, url, childrenSupported, scale, uniqueId) { @@ -96,18 +120,6 @@ class DisplayFloat extends Display { } } - onKeyDown(e) { - const key = Display.getKeyFromEvent(e); - const handler = DisplayFloat._onKeyDownHandlers.get(key); - if (typeof handler === 'function') { - if (handler(this, e)) { - e.preventDefault(); - return true; - } - } - return super.onKeyDown(e); - } - async getMessageToken() { // this._messageTokenPromise is used to ensure that only one call to apiGetMessageToken is made. if (this._messageTokenPromise === null) { @@ -126,10 +138,10 @@ class DisplayFloat extends Display { return; } - const handler = DisplayFloat._messageHandlers.get(action); + const handler = this._windowMessageHandlers.get(action); if (typeof handler !== 'function') { return; } - handler(this, params); + handler(params); } getOptionsContext() { @@ -153,22 +165,4 @@ class DisplayFloat extends Display { } } -DisplayFloat._onKeyDownHandlers = new Map([ - ['C', (self, e) => { - if (e.ctrlKey && !window.getSelection().toString()) { - self.onSelectionCopy(); - return true; - } - return false; - }] -]); - -DisplayFloat._messageHandlers = new Map([ - ['setContent', (self, {type, details}) => self.setContent(type, details)], - ['clearAutoPlayTimer', (self) => self.clearAutoPlayTimer()], - ['setCustomCss', (self, {css}) => self.setCustomCss(css)], - ['prepare', (self, {options, popupInfo, url, childrenSupported, scale, uniqueId}) => self.prepare(options, popupInfo, url, childrenSupported, scale, uniqueId)], - ['setContentScale', (self, {scale}) => self.setContentScale(scale)] -]); - DisplayFloat.instance = new DisplayFloat(); diff --git a/ext/fg/js/frontend-api-sender.js b/ext/fg/js/frontend-api-sender.js index 8dc6aaf3..4431df61 100644 --- a/ext/fg/js/frontend-api-sender.js +++ b/ext/fg/js/frontend-api-sender.js @@ -31,6 +31,8 @@ class FrontendApiSender { invoke(action, params, target) { if (this.disconnected) { + // attempt to reconnect the next time + this.disconnected = false; return Promise.reject(new Error('Disconnected')); } @@ -70,6 +72,7 @@ class FrontendApiSender { onDisconnect() { this.disconnected = true; + this.port = null; for (const id of this.callbacks.keys()) { this.onError(id, 'Disconnected'); diff --git a/ext/fg/js/frontend-initialize.js b/ext/fg/js/frontend-initialize.js index 54b874f2..8424b21d 100644 --- a/ext/fg/js/frontend-initialize.js +++ b/ext/fg/js/frontend-initialize.js @@ -16,9 +16,15 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global PopupProxyHost, PopupProxy, Frontend*/ +/* global + * Frontend + * PopupProxy + * PopupProxyHost + */ async function main() { + await yomichan.prepare(); + const data = window.frontendInitializationData || {}; const {id, depth=0, parentFrameId, ignoreNodes, url, proxy=false} = data; @@ -29,7 +35,7 @@ async function main() { const popupHost = new PopupProxyHost(); await popupHost.prepare(); - popup = popupHost.getOrCreatePopup(); + popup = popupHost.getOrCreatePopup(null, null, depth); } const frontend = new Frontend(popup, ignoreNodes); diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 67045241..768b9326 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -16,7 +16,14 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global apiGetZoom, apiOptionsGet, apiTermsFind, apiKanjiFind, docSentenceExtract, TextScanner*/ +/* global + * TextScanner + * apiGetZoom + * apiKanjiFind + * apiOptionsGet + * apiTermsFind + * docSentenceExtract + */ class Frontend extends TextScanner { constructor(popup, ignoreNodes) { @@ -39,6 +46,15 @@ class Frontend extends TextScanner { this._contentScale = 1.0; this._orphaned = true; this._lastShowPromise = Promise.resolve(); + + this._windowMessageHandlers = new Map([ + ['popupClose', () => this.onSearchClear(true)], + ['selectionCopy', () => document.execCommand('copy')] + ]); + + this._runtimeMessageHandlers = new Map([ + ['popupSetVisibleOverride', ({visible}) => { this.popup.setVisibleOverride(visible); }] + ]); } async prepare() { @@ -55,9 +71,9 @@ class Frontend extends TextScanner { window.visualViewport.addEventListener('resize', this.onVisualViewportResize.bind(this)); } - yomichan.on('orphaned', () => this.onOrphaned()); - yomichan.on('optionsUpdated', () => this.updateOptions()); - yomichan.on('zoomChanged', (e) => this.onZoomChanged(e)); + yomichan.on('orphaned', this.onOrphaned.bind(this)); + yomichan.on('optionsUpdated', this.updateOptions.bind(this)); + yomichan.on('zoomChanged', this.onZoomChanged.bind(this)); chrome.runtime.onMessage.addListener(this.onRuntimeMessage.bind(this)); this._updateContentScale(); @@ -72,17 +88,17 @@ class Frontend extends TextScanner { onWindowMessage(e) { const action = e.data; - const handler = Frontend._windowMessageHandlers.get(action); + const handler = this._windowMessageHandlers.get(action); if (typeof handler !== 'function') { return false; } - handler(this); + handler(); } onRuntimeMessage({action, params}, sender, callback) { - const handler = Frontend._runtimeMessageHandlers.get(action); + const handler = this._runtimeMessageHandlers.get(action); if (typeof handler !== 'function') { return false; } - const result = handler(this, params, sender); + const result = handler(params, sender); callback(result); return false; } @@ -237,12 +253,3 @@ class Frontend extends TextScanner { return visualViewport !== null && typeof visualViewport === 'object' ? visualViewport.scale : 1.0; } } - -Frontend._windowMessageHandlers = new Map([ - ['popupClose', (self) => self.onSearchClear(true)], - ['selectionCopy', () => document.execCommand('copy')] -]); - -Frontend._runtimeMessageHandlers = new Map([ - ['popupSetVisibleOverride', (self, {visible}) => { self.popup.setVisibleOverride(visible); }] -]); diff --git a/ext/fg/js/popup-nested.js b/ext/fg/js/popup-nested.js index 3e5f5b80..06f8fc4b 100644 --- a/ext/fg/js/popup-nested.js +++ b/ext/fg/js/popup-nested.js @@ -16,7 +16,9 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global apiOptionsGet*/ +/* global + * apiOptionsGet + */ let popupNestedInitialized = false; diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js index e55801ff..793d3949 100644 --- a/ext/fg/js/popup-proxy-host.js +++ b/ext/fg/js/popup-proxy-host.js @@ -16,7 +16,11 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global apiFrameInformationGet, FrontendApiReceiver, Popup*/ +/* global + * FrontendApiReceiver + * Popup + * apiFrameInformationGet + */ class PopupProxyHost { constructor() { @@ -34,20 +38,20 @@ class PopupProxyHost { if (typeof frameId !== 'number') { return; } this._apiReceiver = new FrontendApiReceiver(`popup-proxy-host#${frameId}`, new Map([ - ['getOrCreatePopup', ({id, parentId}) => this._onApiGetOrCreatePopup(id, parentId)], - ['setOptions', ({id, options}) => this._onApiSetOptions(id, options)], - ['hide', ({id, changeFocus}) => this._onApiHide(id, changeFocus)], - ['isVisible', ({id}) => this._onApiIsVisibleAsync(id)], - ['setVisibleOverride', ({id, visible}) => this._onApiSetVisibleOverride(id, visible)], - ['containsPoint', ({id, x, y}) => this._onApiContainsPoint(id, x, y)], - ['showContent', ({id, elementRect, writingMode, type, details}) => this._onApiShowContent(id, elementRect, writingMode, type, details)], - ['setCustomCss', ({id, css}) => this._onApiSetCustomCss(id, css)], - ['clearAutoPlayTimer', ({id}) => this._onApiClearAutoPlayTimer(id)], - ['setContentScale', ({id, scale}) => this._onApiSetContentScale(id, scale)] + ['getOrCreatePopup', this._onApiGetOrCreatePopup.bind(this)], + ['setOptions', this._onApiSetOptions.bind(this)], + ['hide', this._onApiHide.bind(this)], + ['isVisible', this._onApiIsVisibleAsync.bind(this)], + ['setVisibleOverride', this._onApiSetVisibleOverride.bind(this)], + ['containsPoint', this._onApiContainsPoint.bind(this)], + ['showContent', this._onApiShowContent.bind(this)], + ['setCustomCss', this._onApiSetCustomCss.bind(this)], + ['clearAutoPlayTimer', this._onApiClearAutoPlayTimer.bind(this)], + ['setContentScale', this._onApiSetContentScale.bind(this)] ])); } - getOrCreatePopup(id=null, parentId=null) { + getOrCreatePopup(id=null, parentId=null, depth=null) { // Find by existing id if (id !== null) { const popup = this._popups.get(id); @@ -76,7 +80,14 @@ class PopupProxyHost { } // Create new popup - const depth = (parent !== null ? parent.depth + 1 : 0); + if (parent !== null) { + if (depth !== null) { + throw new Error('Depth cannot be set when parent exists'); + } + depth = parent.depth + 1; + } else if (depth === null) { + depth = 0; + } const popup = new Popup(id, depth, this._frameIdPromise); if (parent !== null) { popup.setParent(parent); @@ -87,56 +98,57 @@ class PopupProxyHost { // Message handlers - async _onApiGetOrCreatePopup(id, parentId) { + async _onApiGetOrCreatePopup({id, parentId}) { const popup = this.getOrCreatePopup(id, parentId); return { id: popup.id }; } - async _onApiSetOptions(id, options) { + async _onApiSetOptions({id, options}) { const popup = this._getPopup(id); return await popup.setOptions(options); } - async _onApiHide(id, changeFocus) { + async _onApiHide({id, changeFocus}) { const popup = this._getPopup(id); return popup.hide(changeFocus); } - async _onApiIsVisibleAsync(id) { + async _onApiIsVisibleAsync({id}) { const popup = this._getPopup(id); return await popup.isVisible(); } - async _onApiSetVisibleOverride(id, visible) { + async _onApiSetVisibleOverride({id, visible}) { const popup = this._getPopup(id); return await popup.setVisibleOverride(visible); } - async _onApiContainsPoint(id, x, y) { + async _onApiContainsPoint({id, x, y}) { const popup = this._getPopup(id); + [x, y] = PopupProxyHost._convertPopupPointToRootPagePoint(popup, x, y); return await popup.containsPoint(x, y); } - async _onApiShowContent(id, elementRect, writingMode, type, details) { + async _onApiShowContent({id, elementRect, writingMode, type, details}) { const popup = this._getPopup(id); elementRect = PopupProxyHost._convertJsonRectToDOMRect(popup, elementRect); if (!PopupProxyHost._popupCanShow(popup)) { return; } return await popup.showContent(elementRect, writingMode, type, details); } - async _onApiSetCustomCss(id, css) { + async _onApiSetCustomCss({id, css}) { const popup = this._getPopup(id); return popup.setCustomCss(css); } - async _onApiClearAutoPlayTimer(id) { + async _onApiClearAutoPlayTimer({id}) { const popup = this._getPopup(id); return popup.clearAutoPlayTimer(); } - async _onApiSetContentScale(id, scale) { + async _onApiSetContentScale({id, scale}) { const popup = this._getPopup(id); return popup.setContentScale(scale); } @@ -152,14 +164,17 @@ class PopupProxyHost { } static _convertJsonRectToDOMRect(popup, jsonRect) { - let x = jsonRect.x; - let y = jsonRect.y; + const [x, y] = PopupProxyHost._convertPopupPointToRootPagePoint(popup, jsonRect.x, jsonRect.y); + return new DOMRect(x, y, jsonRect.width, jsonRect.height); + } + + static _convertPopupPointToRootPagePoint(popup, x, y) { if (popup.parent !== null) { const popupRect = popup.parent.getContainerRect(); x += popupRect.x; y += popupRect.y; } - return new DOMRect(x, y, jsonRect.width, jsonRect.height); + return [x, y]; } static _popupCanShow(popup) { diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index 093cdd2e..f7cef214 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -16,7 +16,9 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global FrontendApiSender*/ +/* global + * FrontendApiSender + */ class PopupProxy { constructor(id, depth, parentId, parentFrameId, url) { diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 4927f4bd..d752812e 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -16,7 +16,10 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -/*global apiInjectStylesheet, apiGetMessageToken*/ +/* global + * apiGetMessageToken + * apiInjectStylesheet + */ class Popup { constructor(id, depth, frameIdPromise) { @@ -260,7 +263,7 @@ class Popup { 'mozfullscreenchange', 'webkitfullscreenchange' ]; - const onFullscreenChanged = () => this._onFullscreenChanged(); + const onFullscreenChanged = this._onFullscreenChanged.bind(this); for (const eventName of fullscreenEvents) { this._fullscreenEventListeners.addEventListener(document, eventName, onFullscreenChanged, false); } |