diff options
| -rw-r--r-- | ext/bg/js/api.js | 52 | ||||
| -rw-r--r-- | ext/bg/js/backend.js | 84 | ||||
| -rw-r--r-- | ext/fg/js/float.js | 89 | ||||
| -rw-r--r-- | ext/fg/js/frontend.js | 64 | ||||
| -rw-r--r-- | ext/fg/js/popup.js | 20 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 259 | 
6 files changed, 271 insertions, 297 deletions
| diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 474fe604..222e7ffe 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -126,35 +126,35 @@ async function apiTemplateRender(template, data, dynamic) {  }  async function apiCommandExec(command) { -    const handlers = { -        search: () => { -            chrome.tabs.create({url: chrome.extension.getURL('/bg/search.html')}); -        }, - -        help: () => { -            chrome.tabs.create({url: 'https://foosoft.net/projects/yomichan/'}); -        }, - -        options: () => { -            chrome.runtime.openOptionsPage(); -        }, - -        toggle: async () => { -            const optionsContext = { -                depth: 0, -                url: window.location.href -            }; -            const options = await apiOptionsGet(optionsContext); -            options.general.enable = !options.general.enable; -            await apiOptionsSave('popup'); -        } -    }; - -    const handler = handlers[command]; -    if (handler) { +    const handlers = apiCommandExec.handlers; +    if (handlers.hasOwnProperty(command)) { +        const handler = handlers[command];          handler();      }  } +apiCommandExec.handlers = { +    search: () => { +        chrome.tabs.create({url: chrome.extension.getURL('/bg/search.html')}); +    }, + +    help: () => { +        chrome.tabs.create({url: 'https://foosoft.net/projects/yomichan/'}); +    }, + +    options: () => { +        chrome.runtime.openOptionsPage(); +    }, + +    toggle: async () => { +        const optionsContext = { +            depth: 0, +            url: window.location.href +        }; +        const options = await apiOptionsGet(optionsContext); +        options.general.enable = !options.general.enable; +        await apiOptionsSave('popup'); +    } +};  async function apiAudioGetUrl(definition, source) {      return audioBuildUrl(definition, source); diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 4068b760..3c5ad885 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -69,68 +69,13 @@ class Backend {      }      onMessage({action, params}, sender, callback) { -        const forward = (promise, callback) => { -            return promise.then(result => { -                callback({result}); -            }).catch(error => { -                callback({error: error.toString ? error.toString() : error}); -            }); -        }; - -        const handlers = { -            optionsGet: ({optionsContext, callback}) => { -                forward(apiOptionsGet(optionsContext), callback); -            }, - -            kanjiFind: ({text, optionsContext, callback}) => { -                forward(apiKanjiFind(text, optionsContext), callback); -            }, - -            termsFind: ({text, optionsContext, callback}) => { -                forward(apiTermsFind(text, optionsContext), callback); -            }, - -            definitionAdd: ({definition, mode, context, optionsContext, callback}) => { -                forward(apiDefinitionAdd(definition, mode, context, optionsContext), callback); -            }, - -            definitionsAddable: ({definitions, modes, optionsContext, callback}) => { -                forward(apiDefinitionsAddable(definitions, modes, optionsContext), callback); -            }, - -            noteView: ({noteId}) => { -                forward(apiNoteView(noteId), callback); -            }, - -            templateRender: ({template, data, dynamic, callback}) => { -                forward(apiTemplateRender(template, data, dynamic), callback); -            }, - -            commandExec: ({command, callback}) => { -                forward(apiCommandExec(command), callback); -            }, - -            audioGetUrl: ({definition, source, callback}) => { -                forward(apiAudioGetUrl(definition, source), callback); -            }, - -            screenshotGet: ({options}) => { -                forward(apiScreenshotGet(options, sender), callback); -            }, - -            forward: ({action, params}) => { -                forward(apiForward(action, params, sender), callback); -            }, - -            frameInformationGet: () => { -                forward(apiFrameInformationGet(sender), callback); -            } -        }; - -        const handler = handlers[action]; -        if (handler) { -            params.callback = callback; -            handler(params); +        const handlers = Backend.messageHandlers; +        if (handlers.hasOwnProperty(action)) { +            const handler = handlers[action]; +            const promise = handler(params, sender); +            promise +                .then(result => callback({result})) +                .catch(error => callback({error: typeof error.toString === 'function' ? error.toString() : error}));          }          return true; @@ -227,5 +172,20 @@ class Backend {      }  } +Backend.messageHandlers = { +    optionsGet: ({optionsContext}) => apiOptionsGet(optionsContext), +    kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext), +    termsFind: ({text, optionsContext}) => apiTermsFind(text, optionsContext), +    definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext), +    definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext), +    noteView: ({noteId}) => apiNoteView(noteId), +    templateRender: ({template, data, dynamic}) => apiTemplateRender(template, data, dynamic), +    commandExec: ({command}) => apiCommandExec(command), +    audioGetUrl: ({definition, source}) => apiAudioGetUrl(definition, source), +    screenshotGet: ({options}, sender) => apiScreenshotGet(options, sender), +    forward: ({action, params}, sender) => apiForward(action, params, sender), +    frameInformationGet: (params, sender) => apiFrameInformationGet(sender), +}; +  window.yomichan_backend = new Backend();  window.yomichan_backend.prepare(); diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 2e952efb..88842eef 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -63,60 +63,25 @@ class DisplayFloat extends Display {      }      onMessage(e) { -        const handlers = { -            termsShow: ({definitions, options, context}) => { -                this.termsShow(definitions, options, context); -            }, - -            kanjiShow: ({definitions, options, context}) => { -                this.kanjiShow(definitions, options, context); -            }, - -            clearAutoPlayTimer: () => { -                this.clearAutoPlayTimer(); -            }, - -            orphaned: () => { -                this.onOrphaned(); -            }, - -            setOptions: (options) => { -                const css = options.general.customPopupCss; -                if (css) { -                    this.setStyle(css); -                } -            }, - -            popupNestedInitialize: ({id, depth, parentFrameId, url}) => { -                this.optionsContext.depth = depth; -                this.optionsContext.url = url; -                popupNestedInitialize(id, depth, parentFrameId, url); -            } -        }; -          const {action, params} = e.data; -        const handler = handlers[action]; -        if (handler) { -            handler(params); +        const handlers = DisplayFloat.messageHandlers; +        if (handlers.hasOwnProperty(action)) { +            const handler = handlers[action]; +            handler(this, params);          }      }      onKeyDown(e) { -        const handlers = { -            67: /* c */ () => { -                if (e.ctrlKey && !window.getSelection().toString()) { -                    this.onSelectionCopy(); -                    return true; -                } +        const key = Display.getKeyFromEvent(e); +        const handlers = DisplayFloat.onKeyDownHandlers; +        if (handlers.hasOwnProperty(key)) { +            const handler = handlers[key]; +            if (handler(this, e)) { +                e.preventDefault(); +                return;              } -        }; - -        const handler = handlers[e.keyCode]; -        if (handler && handler()) { -            e.preventDefault(); -        } else { -            super.onKeyDown(e);          } +        super.onKeyDown(e);      }      autoPlayAudio() { @@ -131,6 +96,18 @@ class DisplayFloat extends Display {          }      } +    initialize(options, popupInfo, url) { +        const css = options.general.customPopupCss; +        if (css) { +            this.setStyle(css); +        } + +        const {id, depth, parentFrameId} = popupInfo; +        this.optionsContext.depth = depth; +        this.optionsContext.url = url; +        popupNestedInitialize(id, depth, parentFrameId, url); +    } +      setStyle(css) {          const parent = document.head; @@ -146,4 +123,22 @@ class DisplayFloat extends Display {      }  } +DisplayFloat.onKeyDownHandlers = { +    'C': (self, e) => { +        if (e.ctrlKey && !window.getSelection().toString()) { +            self.onSelectionCopy(); +            return true; +        } +        return false; +    } +}; + +DisplayFloat.messageHandlers = { +    termsShow: (self, {definitions, options, context}) => self.termsShow(definitions, options, context), +    kanjiShow: (self, {definitions, options, context}) => self.kanjiShow(definitions, options, context), +    clearAutoPlayTimer: (self) => self.clearAutoPlayTimer(), +    orphaned: (self) => self.onOrphaned(), +    initialize: (self, {options, popupInfo, url}) => self.initialize(options, popupInfo, url) +}; +  window.yomichan_display = new DisplayFloat(); diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 3292cac4..58dc0e4a 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -55,7 +55,7 @@ class Frontend {          try {              this.options = await apiOptionsGet(this.getOptionsContext()); -            window.addEventListener('message', this.onFrameMessage.bind(this)); +            window.addEventListener('message', this.onWindowMessage.bind(this));              window.addEventListener('mousedown', this.onMouseDown.bind(this));              window.addEventListener('mousemove', this.onMouseMove.bind(this));              window.addEventListener('mouseover', this.onMouseOver.bind(this)); @@ -71,7 +71,7 @@ class Frontend {                  window.addEventListener('contextmenu', this.onContextMenu.bind(this));              } -            chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this)); +            chrome.runtime.onMessage.addListener(this.onRuntimeMessage.bind(this));          } catch (e) {              this.onError(e);          } @@ -135,20 +135,12 @@ class Frontend {          this.popupTimerClear();      } -    onFrameMessage(e) { -        const handlers = { -            popupClose: () => { -                this.searchClear(true); -            }, - -            selectionCopy: () => { -                document.execCommand('copy'); -            } -        }; - -        const handler = handlers[e.data]; -        if (handler) { -            handler(); +    onWindowMessage(e) { +        const action = e.data; +        const handlers = Frontend.windowMessageHandlers; +        if (handlers.hasOwnProperty(action)) { +            const handler = handlers[action]; +            handler(this);          }      } @@ -240,20 +232,11 @@ class Frontend {          this.contextMenuChecking = false;      } -    onBgMessage({action, params}, sender, callback) { -        const handlers = { -            optionsUpdate: () => { -                this.updateOptions(); -            }, - -            popupSetVisible: ({visible}) => { -                this.popup.setVisible(visible); -            } -        }; - -        const handler = handlers[action]; -        if (handler) { -            handler(params); +    onRuntimeMessage({action, params}, sender, callback) { +        const handlers = Frontend.runtimeMessageHandlers; +        if (handlers.hasOwnProperty(action)) { +            const handler = handlers[action]; +            handler(this, params);              callback();          }      } @@ -529,4 +512,25 @@ class Frontend {      }  } +Frontend.windowMessageHandlers = { +    popupClose: (self) => { +        self.searchClear(true); +    }, + +    selectionCopy: () => { +        document.execCommand('copy'); +    } +}; + +Frontend.runtimeMessageHandlers = { +    optionsUpdate: (self) => { +        self.updateOptions(); +    }, + +    popupSetVisible: (self, {visible}) => { +        self.popup.setVisible(visible); +    } +}; + +  window.yomichan_frontend = Frontend.create(); diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 64da9aef..9dff6f28 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -56,17 +56,19 @@ class Popup {          return new Promise((resolve) => {              const parentFrameId = (typeof this.frameId === 'number' ? this.frameId : null);              this.container.addEventListener('load', () => { -                this.invokeApi('popupNestedInitialize', { -                    id: this.id, -                    depth: this.depth, -                    parentFrameId, +                this.invokeApi('initialize', { +                    options: { +                        general: { +                            customPopupCss: options.general.customPopupCss +                        } +                    }, +                    popupInfo: { +                        id: this.id, +                        depth: this.depth, +                        parentFrameId +                    },                      url: this.url                  }); -                this.invokeApi('setOptions', { -                    general: { -                        customPopupCss: options.general.customPopupCss -                    } -                });                  resolve();              });              this.observeFullscreen(); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 46016192..dc64dbea 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -150,135 +150,23 @@ class Display {      }      onKeyDown(e) { -        const noteTryAdd = mode => { -            const button = this.adderButtonFind(this.index, mode); -            if (button !== null && !button.classList.contains('disabled')) { -                this.noteAdd(this.definitions[this.index], mode); +        const key = Display.getKeyFromEvent(e); +        const handlers = Display.onKeyDownHandlers; +        if (handlers.hasOwnProperty(key)) { +            const handler = handlers[key]; +            if (handler(this, e)) { +                e.preventDefault();              } -        }; - -        const noteTryView = mode => { -            const button = this.viewerButtonFind(this.index); -            if (button !== null && !button.classList.contains('disabled')) { -                apiNoteView(button.dataset.noteId); -            } -        }; - -        const handlers = { -            27: /* escape */ () => { -                this.onSearchClear(); -                return true; -            }, - -            33: /* page up */ () => { -                if (e.altKey) { -                    this.entryScrollIntoView(this.index - 3, null, true); -                    return true; -                } -            }, - -            34: /* page down */ () => { -                if (e.altKey) { -                    this.entryScrollIntoView(this.index + 3, null, true); -                    return true; -                } -            }, - -            35: /* end */ () => { -                if (e.altKey) { -                    this.entryScrollIntoView(this.definitions.length - 1, null, true); -                    return true; -                } -            }, - -            36: /* home */ () => { -                if (e.altKey) { -                    this.entryScrollIntoView(0, null, true); -                    return true; -                } -            }, - -            38: /* up */ () => { -                if (e.altKey) { -                    this.entryScrollIntoView(this.index - 1, null, true); -                    return true; -                } -            }, - -            40: /* down */ () => { -                if (e.altKey) { -                    this.entryScrollIntoView(this.index + 1, null, true); -                    return true; -                } -            }, - -            66: /* b */ () => { -                if (e.altKey) { -                    this.sourceTermView(); -                    return true; -                } -            }, - -            69: /* e */ () => { -                if (e.altKey) { -                    noteTryAdd('term-kanji'); -                    return true; -                } -            }, - -            75: /* k */ () => { -                if (e.altKey) { -                    noteTryAdd('kanji'); -                    return true; -                } -            }, - -            82: /* r */ () => { -                if (e.altKey) { -                    noteTryAdd('term-kana'); -                    return true; -                } -            }, - -            80: /* p */ () => { -                if (e.altKey) { -                    const entry = this.getEntry(this.index); -                    if (entry !== null && entry.dataset.type === 'term') { -                        this.audioPlay(this.definitions[this.index], this.firstExpressionIndex); -                    } - -                    return true; -                } -            }, - -            86: /* v */ () => { -                if (e.altKey) { -                    noteTryView(); -                } -            } -        }; - -        const handler = handlers[e.keyCode]; -        if (handler && handler()) { -            e.preventDefault();          }      }      onWheel(e) { -        const handler = () => { -            if (e.altKey) { -                if (e.deltaY < 0) { // scroll up -                    this.entryScrollIntoView(this.index - 1, null, true); -                    return true; -                } else if (e.deltaY > 0) { // scroll down -                    this.entryScrollIntoView(this.index + 1, null, true); -                    return true; -                } +        if (e.altKey) { +            const delta = e.deltaY; +            if (delta !== 0) { +                this.entryScrollIntoView(this.index + (delta > 0 ? 1 : -1), null, true); +                e.preventDefault();              } -        }; - -        if (handler()) { -            e.preventDefault();          }      } @@ -459,6 +347,20 @@ class Display {          }      } +    noteTryAdd(mode) { +        const button = this.adderButtonFind(this.index, mode); +        if (button !== null && !button.classList.contains('disabled')) { +            this.noteAdd(this.definitions[this.index], mode); +        } +    } + +    noteTryView() { +        const button = this.viewerButtonFind(this.index); +        if (button !== null && !button.classList.contains('disabled')) { +            apiNoteView(button.dataset.noteId); +        } +    } +      async noteAdd(definition, mode) {          try {              this.setSpinnerVisible(true); @@ -634,4 +536,115 @@ class Display {          const documentRect = document.documentElement.getBoundingClientRect();          return elementRect.top - documentRect.top;      } + +    static getKeyFromEvent(event) { +        const key = event.key; +        return key.length === 1 ? key.toUpperCase() : key; +    }  } + +Display.onKeyDownHandlers = { +    'Escape': (self) => { +        self.onSearchClear(); +        return true; +    }, + +    'PageUp': (self, e) => { +        if (e.altKey) { +            self.entryScrollIntoView(self.index - 3, null, true); +            return true; +        } +        return false; +    }, + +    'PageDown': (self, e) => { +        if (e.altKey) { +            self.entryScrollIntoView(self.index + 3, null, true); +            return true; +        } +        return false; +    }, + +    'End': (self, e) => { +        if (e.altKey) { +            self.entryScrollIntoView(self.definitions.length - 1, null, true); +            return true; +        } +        return false; +    }, + +    'Home': (self, e) => { +        if (e.altKey) { +            self.entryScrollIntoView(0, null, true); +            return true; +        } +        return false; +    }, + +    'ArrowUp': (self, e) => { +        if (e.altKey) { +            self.entryScrollIntoView(self.index - 1, null, true); +            return true; +        } +        return false; +    }, + +    'ArrowDown': (self, e) => { +        if (e.altKey) { +            self.entryScrollIntoView(self.index + 1, null, true); +            return true; +        } +        return false; +    }, + +    'B': (self, e) => { +        if (e.altKey) { +            self.sourceTermView(); +            return true; +        } +        return false; +    }, + +    'E': (self, e) => { +        if (e.altKey) { +            self.noteTryAdd('term-kanji'); +            return true; +        } +        return false; +    }, + +    'K': (self, e) => { +        if (e.altKey) { +            self.noteTryAdd('kanji'); +            return true; +        } +        return false; +    }, + +    'R': (self, e) => { +        if (e.altKey) { +            self.noteTryAdd('term-kana'); +            return true; +        } +        return false; +    }, + +    'P': (self, e) => { +        if (e.altKey) { +            const entry = self.getEntry(self.index); +            if (entry !== null && entry.dataset.type === 'term') { +                self.audioPlay(self.definitions[self.index], self.firstExpressionIndex); +            } +            return true; +        } +        return false; +    }, + +    'V': (self, e) => { +        if (e.altKey) { +            self.noteTryView(); +            return true; +        } +        return false; +    } +}; |