Display refactoring (#674)
* Move setupNestedPopups to Display * Move auto-play timer and delay into Display * Move some message handler definitions into Display * Move default optionsContext definition
This commit is contained in:
parent
27e05f8001
commit
71b97c2019
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user