aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/bg/js/search.js41
-rw-r--r--ext/fg/js/float.js102
-rw-r--r--ext/mixed/js/display.js107
3 files changed, 126 insertions, 124 deletions
diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js
index b046806e..a3741da0 100644
--- a/ext/bg/js/search.js
+++ b/ext/bg/js/search.js
@@ -19,11 +19,8 @@
* ClipboardMonitor
* DOM
* Display
- * Frontend
- * PopupFactory
* QueryParser
* api
- * dynamicLoader
* wanakana
*/
@@ -63,11 +60,6 @@ class DisplaySearch extends Display {
this._runtimeMessageHandlers = new Map([
['updateSearchQuery', {async: false, handler: this._onExternalSearchUpdate.bind(this)}]
]);
-
- this.setOptionsContext({
- depth: 0,
- url: window.location.href
- });
}
async prepare() {
@@ -407,7 +399,11 @@ class DisplaySearch extends Display {
yomichan.off('optionsUpdated', onOptionsUpdated);
try {
- await this._setupNestedPopups();
+ await this.setupNestedPopups({
+ depth: 1,
+ proxy: false,
+ isSearchPage: true
+ });
} catch (e) {
yomichan.logError(e);
}
@@ -417,31 +413,4 @@ class DisplaySearch extends Display {
await onOptionsUpdated();
}
-
- async _setupNestedPopups() {
- await dynamicLoader.loadScripts([
- '/mixed/js/text-scanner.js',
- '/mixed/js/frame-client.js',
- '/fg/js/frame-offset-forwarder.js',
- '/fg/js/popup.js',
- '/fg/js/popup-factory.js',
- '/fg/js/frontend.js'
- ]);
-
- const {frameId} = await api.frameInformationGet();
-
- const popupFactory = new PopupFactory(frameId);
- popupFactory.prepare();
-
- const frontend = new Frontend(
- frameId,
- popupFactory,
- {
- depth: 1,
- proxy: false,
- isSearchPage: true
- }
- );
- await frontend.prepare();
- }
}
diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js
index 690d1b9e..f23a9b93 100644
--- a/ext/fg/js/float.js
+++ b/ext/fg/js/float.js
@@ -18,27 +18,15 @@
/* global
* Display
* FrameEndpoint
- * Frontend
- * PopupFactory
* api
- * dynamicLoader
*/
class DisplayFloat extends Display {
constructor() {
super(document.querySelector('#spinner'), document.querySelector('#definitions'));
- this._autoPlayAudioTimer = null;
this._nestedPopupsPrepared = false;
this._ownerFrameId = null;
this._frameEndpoint = new FrameEndpoint();
- this._messageHandlers = new Map([
- ['configure', {async: true, handler: this._onMessageConfigure.bind(this)}],
- ['setOptionsContext', {async: false, handler: this._onMessageSetOptionsContext.bind(this)}],
- ['setContent', {async: false, handler: this._onMessageSetContent.bind(this)}],
- ['clearAutoPlayTimer', {async: false, handler: this._onMessageClearAutoPlayTimer.bind(this)}],
- ['setCustomCss', {async: false, handler: this._onMessageSetCustomCss.bind(this)}],
- ['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}]
- ]);
this._windowMessageHandlers = new Map([
['extensionUnloaded', {async: false, handler: this._onMessageExtensionUnloaded.bind(this)}]
]);
@@ -49,13 +37,16 @@ class DisplayFloat extends Display {
this.registerHotkeys([
{key: 'C', modifiers: ['ctrl'], action: 'copy-host-selection'}
]);
+
+ this.autoPlayAudioDelay = 400;
}
async prepare() {
await super.prepare();
- api.crossFrame.registerHandlers([
- ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}]
+ this.registerMessageHandlers([
+ ['configure', {async: true, handler: this._onMessageConfigure.bind(this)}],
+ ['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}]
]);
window.addEventListener('message', this._onWindowMessage.bind(this), false);
@@ -98,29 +89,15 @@ class DisplayFloat extends Display {
}
}
- autoPlayAudio() {
- this._clearAutoPlayTimer();
- this._autoPlayAudioTimer = window.setTimeout(() => super.autoPlayAudio(), 400);
- }
-
- // Message handling
-
- _onMessage(data) {
+ authenticateMessageData(data) {
if (!this._frameEndpoint.authenticate(data)) {
throw new Error('Invalid authentication');
}
-
- const {action, params} = data.data;
- const handlerInfo = this._messageHandlers.get(action);
- if (typeof handlerInfo === 'undefined') {
- throw new Error(`Invalid action: ${action}`);
- }
-
- const {async, handler} = handlerInfo;
- const result = handler(params);
- return {async, result};
+ return data.data;
}
+ // Message handling
+
_onWindowMessage(e) {
const data = e.data;
if (!this._frameEndpoint.authenticate(data)) { return; }
@@ -148,22 +125,6 @@ class DisplayFloat extends Display {
this._setContentScale(scale);
}
- _onMessageSetOptionsContext({optionsContext}) {
- this.setOptionsContext(optionsContext);
- }
-
- _onMessageSetContent({type, details}) {
- this.setContent(type, details);
- }
-
- _onMessageClearAutoPlayTimer() {
- this._clearAutoPlayTimer.bind(this);
- }
-
- _onMessageSetCustomCss({css}) {
- this.setCustomCss(css);
- }
-
_onMessageSetContentScale({scale}) {
this._setContentScale(scale);
}
@@ -181,13 +142,6 @@ class DisplayFloat extends Display {
return true;
}
- _clearAutoPlayTimer() {
- if (this._autoPlayAudioTimer) {
- window.clearTimeout(this._autoPlayAudioTimer);
- this._autoPlayAudioTimer = null;
- }
- }
-
_setContentScale(scale) {
const body = document.body;
if (body === null) { return; }
@@ -207,7 +161,13 @@ class DisplayFloat extends Display {
yomichan.off('optionsUpdated', onOptionsUpdated);
try {
- await this._setupNestedPopups(id, depth, parentFrameId, url);
+ await this.setupNestedPopups({
+ id,
+ depth,
+ parentFrameId,
+ url,
+ proxy: true
+ });
} catch (e) {
yomichan.logError(e);
}
@@ -218,36 +178,6 @@ class DisplayFloat extends Display {
await onOptionsUpdated();
}
- async _setupNestedPopups(id, depth, parentFrameId, url) {
- await dynamicLoader.loadScripts([
- '/mixed/js/text-scanner.js',
- '/mixed/js/frame-client.js',
- '/fg/js/popup.js',
- '/fg/js/popup-proxy.js',
- '/fg/js/popup-factory.js',
- '/fg/js/frame-offset-forwarder.js',
- '/fg/js/frontend.js'
- ]);
-
- const {frameId} = await api.frameInformationGet();
-
- const popupFactory = new PopupFactory(frameId);
- popupFactory.prepare();
-
- const frontend = new Frontend(
- frameId,
- popupFactory,
- {
- id,
- depth,
- parentFrameId,
- url,
- proxy: true
- }
- );
- await frontend.prepare();
- }
-
_invoke(action, params={}) {
return api.crossFrame.invoke(this._ownerFrameId, action, params);
}
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index 82e77353..4e6794f3 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -20,11 +20,14 @@
* DOM
* DisplayContext
* DisplayGenerator
+ * Frontend
* MediaLoader
+ * PopupFactory
* WindowScroll
* api
* docRangeFromPoint
* docSentenceExtract
+ * dynamicLoader
*/
class Display {
@@ -32,7 +35,7 @@ class Display {
this._spinner = spinner;
this._container = container;
this._definitions = [];
- this._optionsContext = null;
+ this._optionsContext = {depth: 0, url: window.location.href};
this._options = null;
this._context = null;
this._index = 0;
@@ -53,11 +56,14 @@ class Display {
this._eventListenersActive = false;
this._clickScanPrevent = false;
this._setContentToken = null;
+ this._autoPlayAudioTimer = null;
+ this._autoPlayAudioDelay = 0;
this._mediaLoader = new MediaLoader();
this._displayGenerator = new DisplayGenerator({mediaLoader: this._mediaLoader});
this._windowScroll = new WindowScroll();
this._hotkeys = new Map();
this._actions = new Map();
+ this._messageHandlers = new Map();
this.registerActions([
['close', () => { this.onEscape(); }],
@@ -91,12 +97,29 @@ class Display {
{key: 'P', modifiers: ['alt'], action: 'play-audio'},
{key: 'V', modifiers: ['alt'], action: 'view-note'}
]);
+ this.registerMessageHandlers([
+ ['setOptionsContext', {async: false, handler: this._onMessageSetOptionsContext.bind(this)}],
+ ['setContent', {async: false, handler: this._onMessageSetContent.bind(this)}],
+ ['clearAutoPlayTimer', {async: false, handler: this._onMessageClearAutoPlayTimer.bind(this)}],
+ ['setCustomCss', {async: false, handler: this._onMessageSetCustomCss.bind(this)}]
+ ]);
+ }
+
+ get autoPlayAudioDelay() {
+ return this._autoPlayAudioDelay;
+ }
+
+ set autoPlayAudioDelay(value) {
+ this._autoPlayAudioDelay = value;
}
async prepare() {
this._setInteractive(true);
await this._displayGenerator.prepare();
yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this));
+ api.crossFrame.registerHandlers([
+ ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}]
+ ]);
}
onError(error) {
@@ -155,9 +178,28 @@ class Display {
}
autoPlayAudio() {
+ this.clearAutoPlayTimer();
+
if (this._definitions.length === 0) { return; }
- this._audioPlay(this._definitions[0], this._getFirstExpressionIndex(), 0);
+ const definition = this._definitions[0];
+ const expressionIndex = this._getFirstExpressionIndex();
+ const callback = () => {
+ this._audioPlay(definition, expressionIndex, 0);
+ };
+
+ if (this._autoPlayAudioDelay > 0) {
+ this._autoPlayAudioTimer = setTimeout(callback, this._autoPlayAudioDelay);
+ } else {
+ callback();
+ }
+ }
+
+ clearAutoPlayTimer() {
+ if (this._autoPlayAudioTimer !== null) {
+ clearTimeout(this._autoPlayAudioTimer);
+ this._autoPlayAudioTimer = null;
+ }
}
async setContent(type, details) {
@@ -228,6 +270,67 @@ class Display {
}
}
+ registerMessageHandlers(handlers) {
+ for (const [name, handlerInfo] of handlers) {
+ this._messageHandlers.set(name, handlerInfo);
+ }
+ }
+
+ async setupNestedPopups(frontendInitializationData) {
+ await dynamicLoader.loadScripts([
+ '/mixed/js/text-scanner.js',
+ '/mixed/js/frame-client.js',
+ '/fg/js/popup.js',
+ '/fg/js/popup-proxy.js',
+ '/fg/js/popup-factory.js',
+ '/fg/js/frame-offset-forwarder.js',
+ '/fg/js/frontend.js'
+ ]);
+
+ const {frameId} = await api.frameInformationGet();
+
+ const popupFactory = new PopupFactory(frameId);
+ popupFactory.prepare();
+
+ const frontend = new Frontend(frameId, popupFactory, frontendInitializationData);
+ await frontend.prepare();
+ }
+
+ authenticateMessageData(data) {
+ return data;
+ }
+
+ // Message handlers
+
+ _onMessage(data) {
+ data = this.authenticateMessageData(data);
+ const {action, params} = data;
+ const handlerInfo = this._messageHandlers.get(action);
+ if (typeof handlerInfo === 'undefined') {
+ throw new Error(`Invalid action: ${action}`);
+ }
+
+ const {async, handler} = handlerInfo;
+ const result = handler(params);
+ return {async, result};
+ }
+
+ _onMessageSetOptionsContext({optionsContext}) {
+ this.setOptionsContext(optionsContext);
+ }
+
+ _onMessageSetContent({type, details}) {
+ this.setContent(type, details);
+ }
+
+ _onMessageClearAutoPlayTimer() {
+ this.clearAutoPlayTimer();
+ }
+
+ _onMessageSetCustomCss({css}) {
+ this.setCustomCss(css);
+ }
+
// Private
_onExtensionUnloaded() {