aboutsummaryrefslogtreecommitdiff
path: root/ext/fg/js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/fg/js')
-rw-r--r--ext/fg/js/document.js6
-rw-r--r--ext/fg/js/float.js64
-rw-r--r--ext/fg/js/frontend-api-sender.js3
-rw-r--r--ext/fg/js/frontend-initialize.js10
-rw-r--r--ext/fg/js/frontend.js41
-rw-r--r--ext/fg/js/popup-nested.js4
-rw-r--r--ext/fg/js/popup-proxy-host.js67
-rw-r--r--ext/fg/js/popup-proxy.js4
-rw-r--r--ext/fg/js/popup.js7
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);
}