aboutsummaryrefslogtreecommitdiff
path: root/ext/js/pages/settings/popup-preview-frame.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js/pages/settings/popup-preview-frame.js')
-rw-r--r--ext/js/pages/settings/popup-preview-frame.js102
1 files changed, 86 insertions, 16 deletions
diff --git a/ext/js/pages/settings/popup-preview-frame.js b/ext/js/pages/settings/popup-preview-frame.js
index 7a1a0b3a..60d264fa 100644
--- a/ext/js/pages/settings/popup-preview-frame.js
+++ b/ext/js/pages/settings/popup-preview-frame.js
@@ -22,32 +22,53 @@ import {TextSourceRange} from '../../dom/text-source-range.js';
import {yomitan} from '../../yomitan.js';
export class PopupPreviewFrame {
+ /**
+ * @param {number} tabId
+ * @param {number} frameId
+ * @param {import('../../app/popup-factory.js').PopupFactory} popupFactory
+ * @param {import('../../input/hotkey-handler.js').HotkeyHandler} hotkeyHandler
+ */
constructor(tabId, frameId, popupFactory, hotkeyHandler) {
+ /** @type {number} */
this._tabId = tabId;
+ /** @type {number} */
this._frameId = frameId;
+ /** @type {import('../../app/popup-factory.js').PopupFactory} */
this._popupFactory = popupFactory;
+ /** @type {import('../../input/hotkey-handler.js').HotkeyHandler} */
this._hotkeyHandler = hotkeyHandler;
+ /** @type {?Frontend} */
this._frontend = null;
+ /** @type {?(optionsContext: import('settings').OptionsContext) => Promise<import('settings').ProfileOptions>} */
this._apiOptionsGetOld = null;
+ /** @type {boolean} */
this._popupShown = false;
+ /** @type {?import('core').Timeout} */
this._themeChangeTimeout = null;
+ /** @type {?import('text-source').TextSource} */
this._textSource = null;
+ /** @type {?import('settings').OptionsContext} */
this._optionsContext = null;
+ /** @type {?HTMLElement} */
this._exampleText = null;
+ /** @type {?HTMLInputElement} */
this._exampleTextInput = null;
+ /** @type {string} */
this._targetOrigin = chrome.runtime.getURL('/').replace(/\/$/, '');
- this._windowMessageHandlers = new Map([
+ /** @type {Map<string, (params: import('core').SerializableObjectAny) => void>} */
+ this._windowMessageHandlers = new Map(/** @type {[key: string, handler: (params: import('core').SerializableObjectAny) => void][]} */ ([
['PopupPreviewFrame.setText', this._onSetText.bind(this)],
['PopupPreviewFrame.setCustomCss', this._setCustomCss.bind(this)],
['PopupPreviewFrame.setCustomOuterCss', this._setCustomOuterCss.bind(this)],
['PopupPreviewFrame.updateOptionsContext', this._updateOptionsContext.bind(this)]
- ]);
+ ]));
}
+ /** */
async prepare() {
- this._exampleText = document.querySelector('#example-text');
- this._exampleTextInput = document.querySelector('#example-text-input');
+ this._exampleText = /** @type {HTMLElement} */ (document.querySelector('#example-text'));
+ this._exampleTextInput = /** @type {HTMLInputElement} */ (document.querySelector('#example-text-input'));
if (this._exampleTextInput !== null && typeof wanakana !== 'undefined') {
wanakana.bind(this._exampleTextInput);
@@ -56,12 +77,14 @@ export class PopupPreviewFrame {
window.addEventListener('message', this._onMessage.bind(this), false);
// Setup events
- document.querySelector('#theme-dark-checkbox').addEventListener('change', this._onThemeDarkCheckboxChanged.bind(this), false);
+ const darkThemeCheckbox = /** @type {HTMLInputElement} */ (document.querySelector('#theme-dark-checkbox'));
+ darkThemeCheckbox.addEventListener('change', this._onThemeDarkCheckboxChanged.bind(this), false);
this._exampleText.addEventListener('click', this._onExampleTextClick.bind(this), false);
this._exampleTextInput.addEventListener('blur', this._onExampleTextInputBlur.bind(this), false);
this._exampleTextInput.addEventListener('input', this._onExampleTextInputInput.bind(this), false);
// Overwrite API functions
+ /** @type {?(optionsContext: import('settings').OptionsContext) => Promise<import('settings').ProfileOptions>} */
this._apiOptionsGetOld = yomitan.api.optionsGet.bind(yomitan.api);
yomitan.api.optionsGet = this._apiOptionsGet.bind(this);
@@ -84,7 +107,10 @@ export class PopupPreviewFrame {
await this._frontend.prepare();
this._frontend.setDisabledOverride(true);
this._frontend.canClearSelection = false;
- this._frontend.popup.on('customOuterCssChanged', this._onCustomOuterCssChanged.bind(this));
+ const {popup} = this._frontend;
+ if (popup !== null) {
+ popup.on('customOuterCssChanged', this._onCustomOuterCssChanged.bind(this));
+ }
// Update search
this._updateSearch();
@@ -92,8 +118,12 @@ export class PopupPreviewFrame {
// Private
- async _apiOptionsGet(...args) {
- const options = await this._apiOptionsGetOld(...args);
+ /**
+ * @param {import('settings').OptionsContext} optionsContext
+ * @returns {Promise<import('settings').ProfileOptions>}
+ */
+ async _apiOptionsGet(optionsContext) {
+ const options = await /** @type {(optionsContext: import('settings').OptionsContext) => Promise<import('settings').ProfileOptions>} */ (this._apiOptionsGetOld)(optionsContext);
options.general.enable = true;
options.general.debugInfo = false;
options.general.popupWidth = 400;
@@ -108,16 +138,24 @@ export class PopupPreviewFrame {
return options;
}
+ /**
+ * @param {import('popup').CustomOuterCssChangedEvent} details
+ */
_onCustomOuterCssChanged({node, inShadow}) {
if (node === null || inShadow) { return; }
const node2 = document.querySelector('#popup-outer-css');
if (node2 === null) { return; }
+ const {parentNode} = node2;
+ if (parentNode === null) { return; }
// This simulates the stylesheet priorities when injecting using the web extension API.
- node2.parentNode.insertBefore(node, node2);
+ parentNode.insertBefore(node, node2);
}
+ /**
+ * @param {MessageEvent<{action: string, params: import('core').SerializableObject}>} e
+ */
_onMessage(e) {
if (e.origin !== this._targetOrigin) { return; }
@@ -128,19 +166,24 @@ export class PopupPreviewFrame {
handler(params);
}
+ /**
+ * @param {Event} e
+ */
_onThemeDarkCheckboxChanged(e) {
- document.documentElement.classList.toggle('dark', e.target.checked);
+ const element = /** @type {HTMLInputElement} */ (e.currentTarget);
+ document.documentElement.classList.toggle('dark', element.checked);
if (this._themeChangeTimeout !== null) {
clearTimeout(this._themeChangeTimeout);
}
this._themeChangeTimeout = setTimeout(() => {
this._themeChangeTimeout = null;
- const popup = this._frontend.popup;
+ const popup = /** @type {Frontend} */ (this._frontend).popup;
if (popup === null) { return; }
popup.updateTheme();
}, 300);
}
+ /** */
_onExampleTextClick() {
if (this._exampleTextInput === null) { return; }
const visible = this._exampleTextInput.hidden;
@@ -150,19 +193,31 @@ export class PopupPreviewFrame {
this._exampleTextInput.select();
}
+ /** */
_onExampleTextInputBlur() {
if (this._exampleTextInput === null) { return; }
this._exampleTextInput.hidden = true;
}
+ /**
+ * @param {Event} e
+ */
_onExampleTextInputInput(e) {
- this._setText(e.currentTarget.value);
+ const element = /** @type {HTMLInputElement} */ (e.currentTarget);
+ this._setText(element.value, false);
}
+ /**
+ * @param {{text: string}} details
+ */
_onSetText({text}) {
this._setText(text, true);
}
+ /**
+ * @param {string} text
+ * @param {boolean} setInput
+ */
_setText(text, setInput) {
if (setInput && this._exampleTextInput !== null) {
this._exampleTextInput.value = text;
@@ -175,6 +230,9 @@ export class PopupPreviewFrame {
this._updateSearch();
}
+ /**
+ * @param {boolean} visible
+ */
_setInfoVisible(visible) {
const node = document.querySelector('.placeholder-info');
if (node === null) { return; }
@@ -182,6 +240,9 @@ export class PopupPreviewFrame {
node.classList.toggle('placeholder-info-visible', visible);
}
+ /**
+ * @param {{css: string}} details
+ */
_setCustomCss({css}) {
if (this._frontend === null) { return; }
const popup = this._frontend.popup;
@@ -189,6 +250,9 @@ export class PopupPreviewFrame {
popup.setCustomCss(css);
}
+ /**
+ * @param {{css: string}} details
+ */
_setCustomOuterCss({css}) {
if (this._frontend === null) { return; }
const popup = this._frontend.popup;
@@ -196,7 +260,11 @@ export class PopupPreviewFrame {
popup.setCustomOuterCss(css, false);
}
- async _updateOptionsContext({optionsContext}) {
+ /**
+ * @param {{optionsContext: import('settings').OptionsContext}} details
+ */
+ async _updateOptionsContext(details) {
+ const {optionsContext} = details;
this._optionsContext = optionsContext;
if (this._frontend === null) { return; }
this._frontend.setOptionsContextOverride(optionsContext);
@@ -204,6 +272,7 @@ export class PopupPreviewFrame {
await this._updateSearch();
}
+ /** */
async _updateSearch() {
if (this._exampleText === null) { return; }
@@ -213,16 +282,17 @@ export class PopupPreviewFrame {
const range = document.createRange();
range.selectNodeContents(textNode);
const source = TextSourceRange.create(range);
+ const frontend = /** @type {Frontend} */ (this._frontend);
try {
- await this._frontend.setTextSource(source);
+ await frontend.setTextSource(source);
} finally {
source.cleanup();
}
this._textSource = source;
- await this._frontend.showContentCompleted();
+ await frontend.showContentCompleted();
- const popup = this._frontend.popup;
+ const popup = frontend.popup;
if (popup !== null && popup.isVisibleSync()) {
this._popupShown = true;
}