DOM + DocumentUtil merge (#727)

* Add DOM functions to DocumentUtil

* Use DocumentUtil instead of DOM

* Remove DOM

* Move document-util.js into mixed
This commit is contained in:
toasted-nutbread 2020-08-09 21:07:11 -04:00 committed by GitHub
parent 9f8f83508e
commit 2a86d66092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 157 additions and 185 deletions

View File

@ -42,12 +42,11 @@
"mixed/js/core.js",
"mixed/js/yomichan.js",
"mixed/js/comm.js",
"mixed/js/dom.js",
"mixed/js/api.js",
"mixed/js/dynamic-loader.js",
"mixed/js/frame-client.js",
"mixed/js/text-scanner.js",
"fg/js/document-util.js",
"mixed/js/document-util.js",
"fg/js/dom-text-scanner.js",
"fg/js/popup.js",
"fg/js/source.js",

View File

@ -17,8 +17,8 @@
/* global
* ClipboardMonitor
* DOM
* Display
* DocumentUtil
* api
* wanakana
*/
@ -104,7 +104,7 @@ class DisplaySearch extends Display {
}
onKeyDown(e) {
const key = DOM.getKeyFromEvent(e);
const key = DocumentUtil.getKeyFromEvent(e);
const ignoreKeys = this._onKeyDownIgnoreKeys;
const activeModifierMap = new Map([

View File

@ -16,7 +16,7 @@
*/
/* global
* DOM
* DocumentUtil
* conditionsNormalizeOptionValue
*/
@ -323,7 +323,7 @@ ConditionsUI.Condition = class Condition {
const pressedKeyIndices = new Set();
const onKeyDown = ({originalEvent}) => {
const pressedKeyEventName = DOM.getKeyFromEvent(originalEvent);
const pressedKeyEventName = DocumentUtil.getKeyFromEvent(originalEvent);
if (pressedKeyEventName === 'Escape' || pressedKeyEventName === 'Backspace') {
pressedKeyIndices.clear();
inputInner.val('');
@ -331,7 +331,7 @@ ConditionsUI.Condition = class Condition {
return;
}
const pressedModifiers = DOM.getActiveModifiers(originalEvent);
const pressedModifiers = DocumentUtil.getActiveModifiers(originalEvent);
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
// https://askubuntu.com/questions/567731/why-is-shift-alt-being-mapped-to-meta
// It works with mouse events on some platforms, so try to determine if metaKey is pressed

View File

@ -73,12 +73,11 @@
<script src="/mixed/js/core.js"></script>
<script src="/mixed/js/yomichan.js"></script>
<script src="/mixed/js/comm.js"></script>
<script src="/mixed/js/dom.js"></script>
<script src="/mixed/js/api.js"></script>
<script src="/mixed/js/japanese.js"></script>
<script src="/bg/js/handlebars.js"></script>
<script src="/fg/js/document-util.js"></script>
<script src="/mixed/js/document-util.js"></script>
<script src="/fg/js/dom-text-scanner.js"></script>
<script src="/fg/js/source.js"></script>
<script src="/mixed/js/audio-system.js"></script>

View File

@ -121,13 +121,12 @@
<script src="/mixed/js/core.js"></script>
<script src="/mixed/js/yomichan.js"></script>
<script src="/mixed/js/comm.js"></script>
<script src="/mixed/js/dom.js"></script>
<script src="/mixed/js/api.js"></script>
<script src="/mixed/js/dynamic-loader.js"></script>
<script src="/mixed/js/frame-client.js"></script>
<script src="/mixed/js/text-scanner.js"></script>
<script src="/fg/js/document-util.js"></script>
<script src="/mixed/js/document-util.js"></script>
<script src="/fg/js/dom-text-scanner.js"></script>
<script src="/fg/js/popup.js"></script>
<script src="/fg/js/source.js"></script>

View File

@ -1135,7 +1135,6 @@
<script src="/mixed/js/core.js"></script>
<script src="/mixed/js/yomichan.js"></script>
<script src="/mixed/js/comm.js"></script>
<script src="/mixed/js/dom.js"></script>
<script src="/mixed/js/environment.js"></script>
<script src="/mixed/js/api.js"></script>
<script src="/mixed/js/japanese.js"></script>
@ -1148,6 +1147,7 @@
<script src="/bg/js/profile-conditions.js"></script>
<script src="/bg/js/util.js"></script>
<script src="/mixed/js/audio-system.js"></script>
<script src="/mixed/js/document-util.js"></script>
<script src="/bg/js/settings/anki.js"></script>
<script src="/bg/js/settings/anki-templates.js"></script>

View File

@ -47,11 +47,10 @@
<script src="/mixed/js/core.js"></script>
<script src="/mixed/js/yomichan.js"></script>
<script src="/mixed/js/comm.js"></script>
<script src="/mixed/js/dom.js"></script>
<script src="/mixed/js/api.js"></script>
<script src="/mixed/js/japanese.js"></script>
<script src="/fg/js/document-util.js"></script>
<script src="/mixed/js/document-util.js"></script>
<script src="/fg/js/dom-text-scanner.js"></script>
<script src="/fg/js/source.js"></script>
<script src="/mixed/js/audio-system.js"></script>

View File

@ -16,7 +16,6 @@
*/
/* global
* DOM
* DocumentUtil
* FrameOffsetForwarder
* PopupProxy
@ -98,7 +97,7 @@ class Frontend {
this._textScanner.prepare();
window.addEventListener('resize', this._onResize.bind(this), false);
DOM.addFullscreenChangeEventListener(this._updatePopup.bind(this));
DocumentUtil.addFullscreenChangeEventListener(this._updatePopup.bind(this));
const visualViewport = window.visualViewport;
if (visualViewport !== null && typeof visualViewport === 'object') {
@ -274,7 +273,7 @@ class Frontend {
if (
isIframe &&
showIframePopupsInRootFrame &&
DOM.getFullscreenElement() === null &&
DocumentUtil.getFullscreenElement() === null &&
this._allowRootFramePopupProxy
) {
popupPromise = this._popupCache.get('iframe');

View File

@ -16,7 +16,7 @@
*/
/* global
* DOM
* DocumentUtil
* FrameClient
* api
* dynamicLoader
@ -349,7 +349,7 @@ class Popup {
return;
}
DOM.addFullscreenChangeEventListener(this._onFullscreenChanged.bind(this), this._fullscreenEventListeners);
DocumentUtil.addFullscreenChangeEventListener(this._onFullscreenChanged.bind(this), this._fullscreenEventListeners);
}
_onFullscreenChanged() {
@ -475,7 +475,7 @@ class Popup {
_getFrameParentElement() {
const defaultParent = document.body;
const fullscreenElement = DOM.getFullscreenElement();
const fullscreenElement = DocumentUtil.getFullscreenElement();
if (
fullscreenElement === null ||
fullscreenElement.shadowRoot ||

View File

@ -41,12 +41,11 @@
"mixed/js/core.js",
"mixed/js/yomichan.js",
"mixed/js/comm.js",
"mixed/js/dom.js",
"mixed/js/api.js",
"mixed/js/dynamic-loader.js",
"mixed/js/frame-client.js",
"mixed/js/text-scanner.js",
"fg/js/document-util.js",
"mixed/js/document-util.js",
"fg/js/dom-text-scanner.js",
"fg/js/popup.js",
"fg/js/source.js",

View File

@ -17,7 +17,6 @@
/* global
* AudioSystem
* DOM
* DisplayGenerator
* DisplayHistory
* DocumentUtil
@ -186,11 +185,11 @@ class Display extends EventDispatcher {
}
onKeyDown(e) {
const key = DOM.getKeyFromEvent(e);
const key = DocumentUtil.getKeyFromEvent(e);
const handlers = this._hotkeys.get(key);
if (typeof handlers === 'undefined') { return false; }
const eventModifiers = DOM.getActiveModifiers(e);
const eventModifiers = DocumentUtil.getActiveModifiers(e);
for (const {modifiers, action} of handlers) {
if (getSetDifference(modifiers, eventModifiers).size !== 0) { continue; }
@ -558,7 +557,7 @@ class Display extends EventDispatcher {
}
_onGlossaryMouseDown(e) {
if (DOM.isMouseButtonPressed(e, 'primary')) {
if (DocumentUtil.isMouseButtonPressed(e, 'primary')) {
this._clickScanPrevent = false;
}
}
@ -568,7 +567,7 @@ class Display extends EventDispatcher {
}
_onGlossaryMouseUp(e) {
if (!this._clickScanPrevent && DOM.isMouseButtonPressed(e, 'primary')) {
if (!this._clickScanPrevent && DocumentUtil.isMouseButtonPressed(e, 'primary')) {
try {
this._onTermLookup(e);
} catch (error) {

View File

@ -16,7 +16,6 @@
*/
/* global
* DOM
* DOMTextScanner
* TextSourceElement
* TextSourceRange
@ -134,6 +133,132 @@ class DocumentUtil {
};
}
static isPointInRect(x, y, rect) {
return (
x >= rect.left && x < rect.right &&
y >= rect.top && y < rect.bottom
);
}
static isPointInAnyRect(x, y, rects) {
for (const rect of rects) {
if (this.isPointInRect(x, y, rect)) {
return true;
}
}
return false;
}
static isPointInSelection(x, y, selection) {
for (let i = 0; i < selection.rangeCount; ++i) {
const range = selection.getRangeAt(i);
if (this.isPointInAnyRect(x, y, range.getClientRects())) {
return true;
}
}
return false;
}
static isMouseButtonPressed(mouseEvent, button) {
const mouseEventButton = mouseEvent.button;
switch (button) {
case 'primary': return mouseEventButton === 0;
case 'secondary': return mouseEventButton === 2;
case 'auxiliary': return mouseEventButton === 1;
default: return false;
}
}
static isMouseButtonDown(mouseEvent, button) {
const mouseEventButtons = mouseEvent.buttons;
switch (button) {
case 'primary': return (mouseEventButtons & 0x1) !== 0x0;
case 'secondary': return (mouseEventButtons & 0x2) !== 0x0;
case 'auxiliary': return (mouseEventButtons & 0x4) !== 0x0;
default: return false;
}
}
static getActiveModifiers(event) {
const modifiers = new Set();
if (event.altKey) { modifiers.add('alt'); }
if (event.ctrlKey) { modifiers.add('ctrl'); }
if (event.metaKey) { modifiers.add('meta'); }
if (event.shiftKey) { modifiers.add('shift'); }
return modifiers;
}
static getKeyFromEvent(event) {
const key = event.key;
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
}
static addFullscreenChangeEventListener(onFullscreenChanged, eventListenerCollection=null) {
const target = document;
const options = false;
const fullscreenEventNames = [
'fullscreenchange',
'MSFullscreenChange',
'mozfullscreenchange',
'webkitfullscreenchange'
];
for (const eventName of fullscreenEventNames) {
if (eventListenerCollection === null) {
target.addEventListener(eventName, onFullscreenChanged, options);
} else {
eventListenerCollection.addEventListener(target, eventName, onFullscreenChanged, options);
}
}
}
static getFullscreenElement() {
return (
document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement ||
null
);
}
static getNodesInRange(range) {
const end = range.endContainer;
const nodes = [];
for (let node = range.startContainer; node !== null; node = this.getNextNode(node)) {
nodes.push(node);
if (node === end) { break; }
}
return nodes;
}
static getNextNode(node) {
let next = node.firstChild;
if (next === null) {
while (true) {
next = node.nextSibling;
if (next !== null) { break; }
next = node.parentNode;
if (next === null) { break; }
node = next;
}
}
return next;
}
static anyNodeMatchesSelector(nodes, selector) {
const ELEMENT_NODE = Node.ELEMENT_NODE;
for (let node of nodes) {
for (; node !== null; node = node.parentNode) {
if (node.nodeType !== ELEMENT_NODE) { continue; }
if (node.matches(selector)) { return true; }
break;
}
}
return false;
}
// Private
_setImposterStyle(style, propertyName, value) {
@ -240,7 +365,7 @@ class DocumentUtil {
const {node, offset, content} = new DOMTextScanner(range.endContainer, range.endOffset, true, false).seek(1);
range.setEnd(node, offset);
if (!this._isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) {
if (!this._isWhitespace(content) && DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) {
return true;
}
} finally {
@ -251,7 +376,7 @@ class DocumentUtil {
const {node, offset, content} = new DOMTextScanner(range.startContainer, range.startOffset, true, false).seek(-1);
range.setStart(node, offset);
if (!this._isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) {
if (!this._isWhitespace(content) && DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) {
// This purposefully leaves the starting offset as modified and sets the range length to 0.
range.setEnd(node, offset);
return true;

View File

@ -1,145 +0,0 @@
/*
* Copyright (C) 2019-2020 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 DOM {
static isPointInRect(x, y, rect) {
return (
x >= rect.left && x < rect.right &&
y >= rect.top && y < rect.bottom
);
}
static isPointInAnyRect(x, y, rects) {
for (const rect of rects) {
if (DOM.isPointInRect(x, y, rect)) {
return true;
}
}
return false;
}
static isPointInSelection(x, y, selection) {
for (let i = 0; i < selection.rangeCount; ++i) {
const range = selection.getRangeAt(i);
if (DOM.isPointInAnyRect(x, y, range.getClientRects())) {
return true;
}
}
return false;
}
static isMouseButtonPressed(mouseEvent, button) {
const mouseEventButton = mouseEvent.button;
switch (button) {
case 'primary': return mouseEventButton === 0;
case 'secondary': return mouseEventButton === 2;
case 'auxiliary': return mouseEventButton === 1;
default: return false;
}
}
static isMouseButtonDown(mouseEvent, button) {
const mouseEventButtons = mouseEvent.buttons;
switch (button) {
case 'primary': return (mouseEventButtons & 0x1) !== 0x0;
case 'secondary': return (mouseEventButtons & 0x2) !== 0x0;
case 'auxiliary': return (mouseEventButtons & 0x4) !== 0x0;
default: return false;
}
}
static getActiveModifiers(event) {
const modifiers = new Set();
if (event.altKey) { modifiers.add('alt'); }
if (event.ctrlKey) { modifiers.add('ctrl'); }
if (event.metaKey) { modifiers.add('meta'); }
if (event.shiftKey) { modifiers.add('shift'); }
return modifiers;
}
static getKeyFromEvent(event) {
const key = event.key;
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
}
static addFullscreenChangeEventListener(onFullscreenChanged, eventListenerCollection=null) {
const target = document;
const options = false;
const fullscreenEventNames = [
'fullscreenchange',
'MSFullscreenChange',
'mozfullscreenchange',
'webkitfullscreenchange'
];
for (const eventName of fullscreenEventNames) {
if (eventListenerCollection === null) {
target.addEventListener(eventName, onFullscreenChanged, options);
} else {
eventListenerCollection.addEventListener(target, eventName, onFullscreenChanged, options);
}
}
}
static getFullscreenElement() {
return (
document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement ||
null
);
}
static getNodesInRange(range) {
const end = range.endContainer;
const nodes = [];
for (let node = range.startContainer; node !== null; node = DOM.getNextNode(node)) {
nodes.push(node);
if (node === end) { break; }
}
return nodes;
}
static getNextNode(node) {
let next = node.firstChild;
if (next === null) {
while (true) {
next = node.nextSibling;
if (next !== null) { break; }
next = node.parentNode;
if (next === null) { break; }
node = next;
}
}
return next;
}
static anyNodeMatchesSelector(nodes, selector) {
const ELEMENT_NODE = Node.ELEMENT_NODE;
for (let node of nodes) {
for (; node !== null; node = node.parentNode) {
if (node.nodeType !== ELEMENT_NODE) { continue; }
if (node.matches(selector)) { return true; }
break;
}
}
return false;
}
}

View File

@ -16,7 +16,7 @@
*/
/* global
* DOM
* DocumentUtil
*/
class TextScanner extends EventDispatcher {
@ -155,8 +155,8 @@ class TextScanner extends EventDispatcher {
if (this._ignoreNodes !== null && clonedTextSource.range) {
length = clonedTextSource.text().length;
while (clonedTextSource.range && length > 0) {
const nodes = DOM.getNodesInRange(clonedTextSource.range);
if (!DOM.anyNodeMatchesSelector(nodes, this._ignoreNodes)) {
const nodes = DocumentUtil.getNodesInRange(clonedTextSource.range);
if (!DocumentUtil.anyNodeMatchesSelector(nodes, this._ignoreNodes)) {
break;
}
--length;
@ -204,16 +204,16 @@ class TextScanner extends EventDispatcher {
_onMouseMove(e) {
this._scanTimerClear();
if (this._pendingLookup || DOM.isMouseButtonDown(e, 'primary')) {
if (this._pendingLookup || DocumentUtil.isMouseButtonDown(e, 'primary')) {
return;
}
const modifiers = DOM.getActiveModifiers(e);
const modifiers = DocumentUtil.getActiveModifiers(e);
this.trigger('activeModifiersChanged', {modifiers});
if (!(
this._isScanningModifierPressed(this._modifier, e) ||
(this._useMiddleMouse && DOM.isMouseButtonDown(e, 'auxiliary'))
(this._useMiddleMouse && DocumentUtil.isMouseButtonDown(e, 'auxiliary'))
)) {
return;
}
@ -241,7 +241,7 @@ class TextScanner extends EventDispatcher {
return false;
}
if (DOM.isMouseButtonDown(e, 'primary')) {
if (DocumentUtil.isMouseButtonDown(e, 'primary')) {
this._scanTimerClear();
this.clearSelection(false);
}
@ -284,7 +284,7 @@ class TextScanner extends EventDispatcher {
this._preventNextClick = false;
const primaryTouch = e.changedTouches[0];
if (DOM.isPointInSelection(primaryTouch.clientX, primaryTouch.clientY, window.getSelection())) {
if (DocumentUtil.isPointInSelection(primaryTouch.clientX, primaryTouch.clientY, window.getSelection())) {
return;
}

View File

@ -93,10 +93,9 @@ async function testDocument1() {
const vm = new VM({document, window, Range, Node});
vm.execute([
'mixed/js/dom.js',
'fg/js/dom-text-scanner.js',
'fg/js/source.js',
'fg/js/document-util.js'
'mixed/js/document-util.js'
]);
const [DOMTextScanner, TextSourceRange, TextSourceElement, DocumentUtil] = vm.get([
'DOMTextScanner',