aboutsummaryrefslogtreecommitdiff
path: root/ext/js/display
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js/display')
-rw-r--r--ext/js/display/display-resizer.js172
-rw-r--r--ext/js/display/display.js170
-rw-r--r--ext/js/display/popup-main.js4
3 files changed, 197 insertions, 149 deletions
diff --git a/ext/js/display/display-resizer.js b/ext/js/display/display-resizer.js
new file mode 100644
index 00000000..9fd56045
--- /dev/null
+++ b/ext/js/display/display-resizer.js
@@ -0,0 +1,172 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+class DisplayResizer {
+ constructor(display) {
+ this._display = display;
+ this._token = null;
+ this._handle = null;
+ this._touchIdentifier = null;
+ this._startSize = null;
+ this._startOffset = null;
+ this._eventListeners = new EventListenerCollection();
+ }
+
+ prepare() {
+ this._handle = document.querySelector('#frame-resizer-handle');
+ if (this._handle === null) { return; }
+
+ this._handle.addEventListener('mousedown', this._onFrameResizerMouseDown.bind(this), false);
+ this._handle.addEventListener('touchstart', this._onFrameResizerTouchStart.bind(this), false);
+ }
+
+ // Private
+
+ _onFrameResizerMouseDown(e) {
+ if (e.button !== 0) { return; }
+ // Don't do e.preventDefault() here; this allows mousemove events to be processed
+ // if the pointer moves out of the frame.
+ this._startFrameResize(e);
+ }
+
+ _onFrameResizerTouchStart(e) {
+ e.preventDefault();
+ this._startFrameResizeTouch(e);
+ }
+
+ _onFrameResizerMouseUp() {
+ this._stopFrameResize();
+ }
+
+ _onFrameResizerWindowBlur() {
+ this._stopFrameResize();
+ }
+
+ _onFrameResizerMouseMove(e) {
+ if ((e.buttons & 0x1) === 0x0) {
+ this._stopFrameResize();
+ } else {
+ if (this._startSize === null) { return; }
+ const {clientX: x, clientY: y} = e;
+ this._updateFrameSize(x, y);
+ }
+ }
+
+ _onFrameResizerTouchEnd(e) {
+ if (this._getTouch(e.changedTouches, this._touchIdentifier) === null) { return; }
+ this._stopFrameResize();
+ }
+
+ _onFrameResizerTouchCancel(e) {
+ if (this._getTouch(e.changedTouches, this._touchIdentifier) === null) { return; }
+ this._stopFrameResize();
+ }
+
+ _onFrameResizerTouchMove(e) {
+ if (this._startSize === null) { return; }
+ const primaryTouch = this._getTouch(e.changedTouches, this._touchIdentifier);
+ if (primaryTouch === null) { return; }
+ const {clientX: x, clientY: y} = primaryTouch;
+ this._updateFrameSize(x, y);
+ }
+
+ _startFrameResize(e) {
+ if (this._token !== null) { return; }
+
+ const {clientX: x, clientY: y} = e;
+ const token = {};
+ this._token = token;
+ this._startOffset = {x, y};
+ this._eventListeners.addEventListener(window, 'mouseup', this._onFrameResizerMouseUp.bind(this), false);
+ this._eventListeners.addEventListener(window, 'blur', this._onFrameResizerWindowBlur.bind(this), false);
+ this._eventListeners.addEventListener(window, 'mousemove', this._onFrameResizerMouseMove.bind(this), false);
+
+ const {documentElement} = document;
+ if (documentElement !== null) {
+ documentElement.dataset.isResizing = 'true';
+ }
+
+ this._initializeFrameResize(token);
+ }
+
+ _startFrameResizeTouch(e) {
+ if (this._token !== null) { return; }
+
+ const {clientX: x, clientY: y, identifier} = e.changedTouches[0];
+ const token = {};
+ this._token = token;
+ this._startOffset = {x, y};
+ this._touchIdentifier = identifier;
+ this._eventListeners.addEventListener(window, 'touchend', this._onFrameResizerTouchEnd.bind(this), false);
+ this._eventListeners.addEventListener(window, 'touchcancel', this._onFrameResizerTouchCancel.bind(this), false);
+ this._eventListeners.addEventListener(window, 'blur', this._onFrameResizerWindowBlur.bind(this), false);
+ this._eventListeners.addEventListener(window, 'touchmove', this._onFrameResizerTouchMove.bind(this), false);
+
+ const {documentElement} = document;
+ if (documentElement !== null) {
+ documentElement.dataset.isResizing = 'true';
+ }
+
+ this._initializeFrameResize(token);
+ }
+
+ async _initializeFrameResize(token) {
+ const {parentPopupId} = this._display;
+ if (parentPopupId === null) { return; }
+
+ const size = await this._display.invokeParentFrame('popup.getFrameSize', {id: parentPopupId});
+ if (this._token !== token) { return; }
+ this._startSize = size;
+ }
+
+ _stopFrameResize() {
+ if (this._token === null) { return; }
+
+ this._eventListeners.removeAllEventListeners();
+ this._startSize = null;
+ this._startOffset = null;
+ this._touchIdentifier = null;
+ this._token = null;
+
+ const {documentElement} = document;
+ if (documentElement !== null) {
+ delete documentElement.dataset.isResizing;
+ }
+ }
+
+ async _updateFrameSize(x, y) {
+ const {parentPopupId} = this._display;
+ if (parentPopupId === null) { return; }
+
+ const handleSize = this._handle.getBoundingClientRect();
+ let {width, height} = this._startSize;
+ width += x - this._startOffset.x;
+ height += y - this._startOffset.y;
+ width = Math.max(Math.max(0, handleSize.width), width);
+ height = Math.max(Math.max(0, handleSize.height), height);
+ await this._display.invokeParentFrame('popup.setFrameSize', {id: parentPopupId, width, height});
+ }
+
+ _getTouch(touchList, identifier) {
+ for (const touch of touchList) {
+ if (touch.identifier === identifier) {
+ return touch;
+ }
+ }
+ return null;
+ }
+}
diff --git a/ext/js/display/display.js b/ext/js/display/display.js
index d584db11..e564c4ec 100644
--- a/ext/js/display/display.js
+++ b/ext/js/display/display.js
@@ -106,12 +106,6 @@ class Display extends EventDispatcher {
this._browser = null;
this._copyTextarea = null;
this._definitionTextScanner = null;
- this._frameResizeToken = null;
- this._frameResizeHandle = document.querySelector('#frame-resizer-handle');
- this._frameResizeTouchIdentifier = null;
- this._frameResizeStartSize = null;
- this._frameResizeStartOffset = null;
- this._frameResizeEventListeners = new EventListenerCollection();
this._tagNotification = null;
this._footerNotificationContainer = document.querySelector('#content-footer');
this._displayAudio = new DisplayAudio(this);
@@ -204,6 +198,10 @@ class Display extends EventDispatcher {
return this._frameId;
}
+ get parentPopupId() {
+ return this._parentPopupId;
+ }
+
async prepare() {
// State setup
const {documentElement} = document;
@@ -243,11 +241,6 @@ class Display extends EventDispatcher {
if (this._navigationNextButton !== null) {
this._navigationNextButton.addEventListener('click', this._onNextTermView.bind(this), false);
}
-
- if (this._frameResizeHandle !== null) {
- this._frameResizeHandle.addEventListener('mousedown', this._onFrameResizerMouseDown.bind(this), false);
- this._frameResizeHandle.addEventListener('touchstart', this._onFrameResizerTouchStart.bind(this), false);
- }
}
getContentOrigin() {
@@ -399,7 +392,7 @@ class Display extends EventDispatcher {
close() {
switch (this._pageType) {
case 'popup':
- this._invokeContentOrigin('closePopup');
+ this.invokeContentOrigin('closePopup');
break;
case 'search':
this._closeTab();
@@ -439,6 +432,20 @@ class Display extends EventDispatcher {
this.setContent(details);
}
+ async invokeContentOrigin(action, params={}) {
+ if (this._contentOriginTabId === this._tabId && this._contentOriginFrameId === this._frameId) {
+ throw new Error('Content origin is same page');
+ }
+ return await yomichan.crossFrame.invokeTab(this._contentOriginTabId, this._contentOriginFrameId, action, params);
+ }
+
+ async invokeParentFrame(action, params={}) {
+ if (this._parentFrameId === null || this._parentFrameId === this._frameId) {
+ throw new Error('Invalid parent frame');
+ }
+ return await yomichan.crossFrame.invoke(this._parentFrameId, action, params);
+ }
+
// Message handlers
_onDirectMessage(data) {
@@ -1618,13 +1625,6 @@ class Display extends EventDispatcher {
await frontend.prepare();
}
- async _invokeContentOrigin(action, params={}) {
- if (this._contentOriginTabId === this._tabId && this._contentOriginFrameId === this._frameId) {
- throw new Error('Content origin is same page');
- }
- return await yomichan.crossFrame.invokeTab(this._contentOriginTabId, this._contentOriginFrameId, action, params);
- }
-
_copyHostSelection() {
if (this._contentOriginFrameId === null || window.getSelection().toString()) { return false; }
this._copyHostSelectionSafe();
@@ -1646,7 +1646,7 @@ class Display extends EventDispatcher {
{
let text;
try {
- text = await this._invokeContentOrigin('getSelectionText');
+ text = await this.invokeContentOrigin('getSelectionText');
} catch (e) {
break;
}
@@ -1654,7 +1654,7 @@ class Display extends EventDispatcher {
}
break;
default:
- await this._invokeContentOrigin('copySelection');
+ await this.invokeContentOrigin('copySelection');
break;
}
}
@@ -1779,138 +1779,10 @@ class Display extends EventDispatcher {
this.setContent(details);
}
- _onFrameResizerMouseDown(e) {
- if (e.button !== 0) { return; }
- // Don't do e.preventDefault() here; this allows mousemove events to be processed
- // if the pointer moves out of the frame.
- this._startFrameResize(e);
- }
-
- _onFrameResizerTouchStart(e) {
- e.preventDefault();
- this._startFrameResizeTouch(e);
- }
-
- _onFrameResizerMouseUp() {
- this._stopFrameResize();
- }
-
- _onFrameResizerWindowBlur() {
- this._stopFrameResize();
- }
-
- _onFrameResizerMouseMove(e) {
- if ((e.buttons & 0x1) === 0x0) {
- this._stopFrameResize();
- } else {
- if (this._frameResizeStartSize === null) { return; }
- const {clientX: x, clientY: y} = e;
- this._updateFrameSize(x, y);
- }
- }
-
- _onFrameResizerTouchEnd(e) {
- if (this._getTouch(e.changedTouches, this._frameResizeTouchIdentifier) === null) { return; }
- this._stopFrameResize();
- }
-
- _onFrameResizerTouchCancel(e) {
- if (this._getTouch(e.changedTouches, this._frameResizeTouchIdentifier) === null) { return; }
- this._stopFrameResize();
- }
-
- _onFrameResizerTouchMove(e) {
- if (this._frameResizeStartSize === null) { return; }
- const primaryTouch = this._getTouch(e.changedTouches, this._frameResizeTouchIdentifier);
- if (primaryTouch === null) { return; }
- const {clientX: x, clientY: y} = primaryTouch;
- this._updateFrameSize(x, y);
- }
-
_getSearchContext() {
return {optionsContext: this.getOptionsContext()};
}
- _startFrameResize(e) {
- if (this._frameResizeToken !== null) { return; }
-
- const {clientX: x, clientY: y} = e;
- const token = {};
- this._frameResizeToken = token;
- this._frameResizeStartOffset = {x, y};
- this._frameResizeEventListeners.addEventListener(window, 'mouseup', this._onFrameResizerMouseUp.bind(this), false);
- this._frameResizeEventListeners.addEventListener(window, 'blur', this._onFrameResizerWindowBlur.bind(this), false);
- this._frameResizeEventListeners.addEventListener(window, 'mousemove', this._onFrameResizerMouseMove.bind(this), false);
-
- const {documentElement} = document;
- if (documentElement !== null) {
- documentElement.dataset.isResizing = 'true';
- }
-
- this._initializeFrameResize(token);
- }
-
- _startFrameResizeTouch(e) {
- if (this._frameResizeToken !== null) { return; }
-
- const {clientX: x, clientY: y, identifier} = e.changedTouches[0];
- const token = {};
- this._frameResizeToken = token;
- this._frameResizeStartOffset = {x, y};
- this._frameResizeTouchIdentifier = identifier;
- this._frameResizeEventListeners.addEventListener(window, 'touchend', this._onFrameResizerTouchEnd.bind(this), false);
- this._frameResizeEventListeners.addEventListener(window, 'touchcancel', this._onFrameResizerTouchCancel.bind(this), false);
- this._frameResizeEventListeners.addEventListener(window, 'blur', this._onFrameResizerWindowBlur.bind(this), false);
- this._frameResizeEventListeners.addEventListener(window, 'touchmove', this._onFrameResizerTouchMove.bind(this), false);
-
- const {documentElement} = document;
- if (documentElement !== null) {
- documentElement.dataset.isResizing = 'true';
- }
-
- this._initializeFrameResize(token);
- }
-
- async _initializeFrameResize(token) {
- const size = await this._invokeContentOrigin('getFrameSize');
- if (this._frameResizeToken !== token) { return; }
- this._frameResizeStartSize = size;
- }
-
- _stopFrameResize() {
- if (this._frameResizeToken === null) { return; }
-
- this._frameResizeEventListeners.removeAllEventListeners();
- this._frameResizeStartSize = null;
- this._frameResizeStartOffset = null;
- this._frameResizeTouchIdentifier = null;
- this._frameResizeToken = null;
-
- const {documentElement} = document;
- if (documentElement !== null) {
- delete documentElement.dataset.isResizing;
- }
- }
-
- async _updateFrameSize(x, y) {
- const handleSize = this._frameResizeHandle.getBoundingClientRect();
- let {width, height} = this._frameResizeStartSize;
- width += x - this._frameResizeStartOffset.x;
- height += y - this._frameResizeStartOffset.y;
- width = Math.max(Math.max(0, handleSize.width), width);
- height = Math.max(Math.max(0, handleSize.height), height);
- await this._invokeContentOrigin('setFrameSize', {width, height});
- }
-
- _getTouch(touchList, identifier) {
- for (const touch of touchList) {
- if (touch.identifier === identifier) {
- return touch;
- }
- }
- return null;
- }
-
_updateHotkeys(options) {
this._hotkeyHandler.setHotkeys(this._pageType, options.inputs.hotkeys);
}
diff --git a/ext/js/display/popup-main.js b/ext/js/display/popup-main.js
index 55f19984..0b5e338d 100644
--- a/ext/js/display/popup-main.js
+++ b/ext/js/display/popup-main.js
@@ -18,6 +18,7 @@
/* global
* Display
* DisplayProfileSelection
+ * DisplayResizer
* DocumentFocusController
* HotkeyHandler
* JapaneseUtil
@@ -43,6 +44,9 @@
const displayProfileSelection = new DisplayProfileSelection(display);
displayProfileSelection.prepare();
+ const displayResizer = new DisplayResizer(display);
+ displayResizer.prepare();
+
display.initializeState();
document.documentElement.dataset.loaded = 'true';