diff --git a/ext/css/search.css b/ext/css/search.css index 47a1c4c8..f529fbb6 100644 --- a/ext/css/search.css +++ b/ext/css/search.css @@ -130,7 +130,7 @@ h1 { .search-options { display: flex; flex-flow: row wrap; - margin: 0.5em -1em; + margin: 0.5em calc(-1 * var(--main-content-horizontal-padding)); align-items: center; } .search-option { @@ -167,4 +167,12 @@ h1 { #intro>p { margin: 0; } - +:root[data-search-mode=action-popup] #intro, +:root[data-search-mode=action-popup] #search-option-clipboard-monitor-container { + display: none; +} +:root[data-search-mode=action-popup], +:root[data-search-mode=action-popup] body { + width: 640px; + height: 480px; +} diff --git a/ext/js/display/display.js b/ext/js/display/display.js index 6895ea74..7bfe3add 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -1571,7 +1571,11 @@ class Display extends EventDispatcher { audioDetails = {sources: sources2, preferredAudioIndex, customSourceUrl, customSourceType}; } - const screenshotDetails = (AnkiUtil.fieldsObjectContainsMarker(fields, 'screenshot') ? {tabId: this._contentOriginTabId, frameId: this._contentOriginFrameId, format, quality} : null); + const screenshotDetails = ( + AnkiUtil.fieldsObjectContainsMarker(fields, 'screenshot') && typeof this._contentOriginTabId === 'number' ? + {tabId: this._contentOriginTabId, frameId: this._contentOriginFrameId, format, quality} : + null + ); const clipboardDetails = { image: AnkiUtil.fieldsObjectContainsMarker(fields, 'clipboard-image'), diff --git a/ext/js/display/search-action-popup-controller.js b/ext/js/display/search-action-popup-controller.js new file mode 100644 index 00000000..ab5a4976 --- /dev/null +++ b/ext/js/display/search-action-popup-controller.js @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +class SearchActionPopupController { + constructor(searchPersistentStateController) { + this._searchPersistentStateController = searchPersistentStateController; + } + + prepare() { + const searchParams = new URLSearchParams(location.search); + if (searchParams.get('action-popup') !== 'true') { return; } + + searchParams.delete('action-popup'); + let search = searchParams.toString(); + if (search.length > 0) { search = `?${search}`; } + const url = `${location.protocol}//${location.host}${location.pathname}${search}${location.hash}`; + history.replaceState(history.state, '', url); + + this._searchPersistentStateController.mode = 'action-popup'; + } +} diff --git a/ext/js/display/search-display-controller.js b/ext/js/display/search-display-controller.js index 95f8b6c1..8743166b 100644 --- a/ext/js/display/search-display-controller.js +++ b/ext/js/display/search-display-controller.js @@ -84,6 +84,10 @@ class SearchDisplayController { this._onDisplayOptionsUpdated({options: this._display.getOptions()}); } + setMode(mode) { + this._setMode(mode, true); + } + // Actions _onActionFocusSearchBox() { @@ -329,13 +333,23 @@ class SearchDisplayController { _updateClipboardMonitorEnabled() { const enabled = this._clipboardMonitorEnabled; this._clipboardMonitorEnableCheckbox.checked = enabled; - if (enabled && this._searchPersistentStateController.mode !== 'popup') { + if (enabled && this._canEnableClipboardMonitor()) { this._clipboardMonitor.start(); } else { this._clipboardMonitor.stop(); } } + _canEnableClipboardMonitor() { + switch (this._searchPersistentStateController.mode) { + case 'popup': + case 'action-popup': + return false; + default: + return true; + } + } + _requestPermissions(permissions) { return new Promise((resolve) => { chrome.permissions.request( diff --git a/ext/js/display/search-main.js b/ext/js/display/search-main.js index 04886bc8..7d39b3b7 100644 --- a/ext/js/display/search-main.js +++ b/ext/js/display/search-main.js @@ -20,6 +20,7 @@ * DocumentFocusController * HotkeyHandler * JapaneseUtil + * SearchActionPopupController * SearchDisplayController * SearchPersistentStateController * wanakana @@ -33,6 +34,9 @@ const searchPersistentStateController = new SearchPersistentStateController(); searchPersistentStateController.prepare(); + const searchActionPopupController = new SearchActionPopupController(searchPersistentStateController); + searchActionPopupController.prepare(); + await yomichan.prepare(); const {tabId, frameId} = await yomichan.api.frameInformationGet(); diff --git a/ext/js/pages/action-popup-main.js b/ext/js/pages/action-popup-main.js index 4934802b..b3198676 100644 --- a/ext/js/pages/action-popup-main.js +++ b/ext/js/pages/action-popup-main.js @@ -31,7 +31,7 @@ class DisplayController { this._showExtensionInfo(manifest); this._setupEnvironment(); - this._setupButtonEvents('.action-open-search', 'openSearchPage', chrome.runtime.getURL('/search.html')); + this._setupButtonEvents('.action-open-search', 'openSearchPage', chrome.runtime.getURL('/search.html'), this._onSearchClick.bind(this)); this._setupButtonEvents('.action-open-info', 'openInfoPage', chrome.runtime.getURL('/info.html')); const optionsFull = await yomichan.api.optionsGetFull(); @@ -60,6 +60,13 @@ class DisplayController { // Private + _onSearchClick(e) { + if (!e.shiftKey) { return; } + e.preventDefault(); + location.href = '/search.html?action-popup=true'; + return false; + } + _showExtensionInfo(manifest) { const node = document.getElementById('extension-info'); if (node === null) { return; } @@ -67,12 +74,16 @@ class DisplayController { node.textContent = `${manifest.name} v${manifest.version}`; } - _setupButtonEvents(selector, command, url) { + _setupButtonEvents(selector, command, url, customHandler) { const nodes = document.querySelectorAll(selector); for (const node of nodes) { if (typeof command === 'string') { node.addEventListener('click', (e) => { if (e.button !== 0) { return; } + if (typeof customHandler === 'function') { + const result = customHandler(e); + if (typeof result !== 'undefined') { return; } + } yomichan.api.commandExec(command, {mode: e.ctrlKey ? 'newTab' : 'existingOrNewTab'}); e.preventDefault(); }, false); diff --git a/ext/search.html b/ext/search.html index 578e1763..63e1fd9d 100644 --- a/ext/search.html +++ b/ext/search.html @@ -36,7 +36,7 @@ Automatic kana conversion -