diff options
Diffstat (limited to 'ext/mixed/js/display.js')
-rw-r--r-- | ext/mixed/js/display.js | 107 |
1 files changed, 105 insertions, 2 deletions
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() { |