aboutsummaryrefslogtreecommitdiff
path: root/ext/fg
diff options
context:
space:
mode:
authorAlex Yatskov <alex@foosoft.net>2019-12-03 18:30:22 -0800
committerAlex Yatskov <alex@foosoft.net>2019-12-03 18:30:22 -0800
commitf9ea6206550ceee625ea93215a6e08d45a750086 (patch)
tree803fe11a788a631076b3fb11a98e50bb8b454396 /ext/fg
parent08ad2779678cd447bd747c2b155ef9b5135fdf5d (diff)
parent3975aabf4dc283d49ec46d0ed7ead982b9fa7441 (diff)
Merge branch 'master' into testing
Diffstat (limited to 'ext/fg')
-rw-r--r--ext/fg/float.html6
-rw-r--r--ext/fg/js/api.js70
-rw-r--r--ext/fg/js/document.js23
-rw-r--r--ext/fg/js/float.js4
-rw-r--r--ext/fg/js/frontend-api-receiver.js6
-rw-r--r--ext/fg/js/frontend-api-sender.js6
-rw-r--r--ext/fg/js/frontend.js53
-rw-r--r--ext/fg/js/popup-nested.js5
-rw-r--r--ext/fg/js/popup-proxy-host.js4
-rw-r--r--ext/fg/js/popup.js10
-rw-r--r--ext/fg/js/source.js16
-rw-r--r--ext/fg/js/util.js52
12 files changed, 102 insertions, 153 deletions
diff --git a/ext/fg/float.html b/ext/fg/float.html
index aec3db20..8cc5a129 100644
--- a/ext/fg/float.html
+++ b/ext/fg/float.html
@@ -31,15 +31,15 @@
</div>
</div>
- <script src="/mixed/lib/wanakana.min.js"></script>
-
- <script src="/mixed/js/extension.js"></script>
+ <script src="/mixed/js/core.js"></script>
+ <script src="/mixed/js/dom.js"></script>
<script src="/fg/js/api.js"></script>
<script src="/fg/js/util.js"></script>
<script src="/fg/js/document.js"></script>
<script src="/fg/js/source.js"></script>
<script src="/mixed/js/audio.js"></script>
+ <script src="/mixed/js/display-context.js"></script>
<script src="/mixed/js/display.js"></script>
<script src="/mixed/js/scroll.js"></script>
diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js
index 54818702..0e100b59 100644
--- a/ext/fg/js/api.js
+++ b/ext/fg/js/api.js
@@ -18,65 +18,101 @@
function apiOptionsGet(optionsContext) {
- return utilInvoke('optionsGet', {optionsContext});
+ return _apiInvoke('optionsGet', {optionsContext});
}
function apiOptionsSet(changedOptions, optionsContext, source) {
- return utilInvoke('optionsSet', {changedOptions, optionsContext, source});
+ return _apiInvoke('optionsSet', {changedOptions, optionsContext, source});
}
-function apiTermsFind(text, optionsContext) {
- return utilInvoke('termsFind', {text, optionsContext});
+function apiTermsFind(text, details, optionsContext) {
+ return _apiInvoke('termsFind', {text, details, optionsContext});
+}
+
+function apiTextParse(text, optionsContext) {
+ return _apiInvoke('textParse', {text, optionsContext});
+}
+
+function apiTextParseMecab(text, optionsContext) {
+ return _apiInvoke('textParseMecab', {text, optionsContext});
}
function apiKanjiFind(text, optionsContext) {
- return utilInvoke('kanjiFind', {text, optionsContext});
+ return _apiInvoke('kanjiFind', {text, optionsContext});
}
function apiDefinitionAdd(definition, mode, context, optionsContext) {
- return utilInvoke('definitionAdd', {definition, mode, context, optionsContext});
+ return _apiInvoke('definitionAdd', {definition, mode, context, optionsContext});
}
function apiDefinitionsAddable(definitions, modes, optionsContext) {
- return utilInvoke('definitionsAddable', {definitions, modes, optionsContext}).catch(() => null);
+ return _apiInvoke('definitionsAddable', {definitions, modes, optionsContext}).catch(() => null);
}
function apiNoteView(noteId) {
- return utilInvoke('noteView', {noteId});
+ return _apiInvoke('noteView', {noteId});
}
function apiTemplateRender(template, data, dynamic) {
- return utilInvoke('templateRender', {data, template, dynamic});
+ return _apiInvoke('templateRender', {data, template, dynamic});
}
function apiAudioGetUrl(definition, source, optionsContext) {
- return utilInvoke('audioGetUrl', {definition, source, optionsContext});
+ return _apiInvoke('audioGetUrl', {definition, source, optionsContext});
}
function apiCommandExec(command, params) {
- return utilInvoke('commandExec', {command, params});
+ return _apiInvoke('commandExec', {command, params});
}
function apiScreenshotGet(options) {
- return utilInvoke('screenshotGet', {options});
+ return _apiInvoke('screenshotGet', {options});
}
function apiForward(action, params) {
- return utilInvoke('forward', {action, params});
+ return _apiInvoke('forward', {action, params});
}
function apiFrameInformationGet() {
- return utilInvoke('frameInformationGet');
+ return _apiInvoke('frameInformationGet');
}
function apiInjectStylesheet(css) {
- return utilInvoke('injectStylesheet', {css});
+ return _apiInvoke('injectStylesheet', {css});
}
function apiGetEnvironmentInfo() {
- return utilInvoke('getEnvironmentInfo');
+ return _apiInvoke('getEnvironmentInfo');
}
function apiClipboardGet() {
- return utilInvoke('clipboardGet');
+ return _apiInvoke('clipboardGet');
+}
+
+function _apiInvoke(action, params={}) {
+ const data = {action, params};
+ return new Promise((resolve, reject) => {
+ try {
+ chrome.runtime.sendMessage(data, (response) => {
+ _apiCheckLastError(chrome.runtime.lastError);
+ if (response !== null && typeof response === 'object') {
+ if (typeof response.error !== 'undefined') {
+ reject(jsonToError(response.error));
+ } else {
+ resolve(response.result);
+ }
+ } else {
+ const message = response === null ? 'Unexpected null response' : `Unexpected response of type ${typeof response}`;
+ reject(new Error(`${message} (${JSON.stringify(data)})`));
+ }
+ });
+ } catch (e) {
+ window.yomichan_orphaned = true;
+ reject(e);
+ }
+ });
+}
+
+function _apiCheckLastError() {
+ // NOP
}
diff --git a/ext/fg/js/document.js b/ext/fg/js/document.js
index a168705e..10dea7df 100644
--- a/ext/fg/js/document.js
+++ b/ext/fg/js/document.js
@@ -17,7 +17,7 @@
*/
-const REGEX_TRANSPARENT_COLOR = /rgba\s*\([^\)]*,\s*0(?:\.0+)?\s*\)/;
+const REGEX_TRANSPARENT_COLOR = /rgba\s*\([^)]*,\s*0(?:\.0+)?\s*\)/;
function docSetImposterStyle(style, propertyName, value) {
style.setProperty(propertyName, value, 'important');
@@ -223,7 +223,7 @@ function isPointInRange(x, y, range) {
const {node, offset, content} = TextSourceRange.seekForward(range.endContainer, range.endOffset, 1);
range.setEnd(node, offset);
- if (!isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) {
+ if (!isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) {
return true;
}
} finally {
@@ -234,7 +234,7 @@ function isPointInRange(x, y, range) {
const {node, offset, content} = TextSourceRange.seekBackward(range.startContainer, range.startOffset, 1);
range.setStart(node, offset);
- if (!isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) {
+ if (!isWhitespace(content) && DOM.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;
@@ -248,21 +248,6 @@ function isWhitespace(string) {
return string.trim().length === 0;
}
-function isPointInAnyRect(x, y, rects) {
- for (const rect of rects) {
- if (isPointInRect(x, y, rect)) {
- return true;
- }
- }
- return false;
-}
-
-function isPointInRect(x, y, rect) {
- return (
- x >= rect.left && x < rect.right &&
- y >= rect.top && y < rect.bottom);
-}
-
const caretRangeFromPoint = (() => {
if (typeof document.caretRangeFromPoint === 'function') {
// Chrome, Edge
@@ -359,7 +344,7 @@ function isElementTransparent(element) {
}
const style = window.getComputedStyle(element);
return (
- parseFloat(style.opacity) < 0 ||
+ parseFloat(style.opacity) <= 0 ||
style.visibility === 'hidden' ||
(style.backgroundImage === 'none' && isColorTransparent(style.backgroundColor))
);
diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js
index 089c9422..ae54be00 100644
--- a/ext/fg/js/float.js
+++ b/ext/fg/js/float.js
@@ -49,7 +49,7 @@ class DisplayFloat extends Display {
onMessage(e) {
const {action, params} = e.data;
const handlers = DisplayFloat.messageHandlers;
- if (handlers.hasOwnProperty(action)) {
+ if (hasOwn(handlers, action)) {
const handler = handlers[action];
handler(this, params);
}
@@ -58,7 +58,7 @@ class DisplayFloat extends Display {
onKeyDown(e) {
const key = Display.getKeyFromEvent(e);
const handlers = DisplayFloat.onKeyDownHandlers;
- if (handlers.hasOwnProperty(key)) {
+ if (hasOwn(handlers, key)) {
const handler = handlers[key];
if (handler(this, e)) {
e.preventDefault();
diff --git a/ext/fg/js/frontend-api-receiver.js b/ext/fg/js/frontend-api-receiver.js
index fbfb3ab0..7d38ddd5 100644
--- a/ext/fg/js/frontend-api-receiver.js
+++ b/ext/fg/js/frontend-api-receiver.js
@@ -34,7 +34,7 @@ class FrontendApiReceiver {
onMessage(port, {id, action, params, target, senderId}) {
if (
target !== this.source ||
- !this.handlers.hasOwnProperty(action)
+ !hasOwn(this.handlers, action)
) {
return;
}
@@ -43,10 +43,10 @@ class FrontendApiReceiver {
const handler = this.handlers[action];
handler(params).then(
- result => {
+ (result) => {
this.sendResult(port, id, senderId, {result});
},
- error => {
+ (error) => {
this.sendResult(port, id, senderId, {error: errorToJson(error)});
});
}
diff --git a/ext/fg/js/frontend-api-sender.js b/ext/fg/js/frontend-api-sender.js
index c6eeaeb2..af998a8f 100644
--- a/ext/fg/js/frontend-api-sender.js
+++ b/ext/fg/js/frontend-api-sender.js
@@ -78,7 +78,7 @@ class FrontendApiSender {
}
onAck(id) {
- if (!this.callbacks.hasOwnProperty(id)) {
+ if (!hasOwn(this.callbacks, id)) {
console.warn(`ID ${id} not found for ack`);
return;
}
@@ -95,7 +95,7 @@ class FrontendApiSender {
}
onResult(id, data) {
- if (!this.callbacks.hasOwnProperty(id)) {
+ if (!hasOwn(this.callbacks, id)) {
console.warn(`ID ${id} not found`);
return;
}
@@ -118,7 +118,7 @@ class FrontendApiSender {
}
onError(id, reason) {
- if (!this.callbacks.hasOwnProperty(id)) { return; }
+ if (!hasOwn(this.callbacks, id)) { return; }
const info = this.callbacks[id];
delete this.callbacks[id];
info.timer = null;
diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js
index e67008df..9a1d507b 100644
--- a/ext/fg/js/frontend.js
+++ b/ext/fg/js/frontend.js
@@ -80,7 +80,7 @@ class Frontend {
onMouseMove(e) {
this.popupTimerClear();
- if (this.pendingLookup || Frontend.isMouseButton('primary', e)) {
+ if (this.pendingLookup || DOM.isMouseButtonDown(e, 'primary')) {
return;
}
@@ -88,7 +88,7 @@ class Frontend {
const scanningModifier = scanningOptions.modifier;
if (!(
Frontend.isScanningModifierPressed(scanningModifier, e) ||
- (scanningOptions.middleMouse && Frontend.isMouseButton('auxiliary', e))
+ (scanningOptions.middleMouse && DOM.isMouseButtonDown(e, 'auxiliary'))
)) {
return;
}
@@ -122,7 +122,7 @@ class Frontend {
}
}
- onMouseOut(e) {
+ onMouseOut() {
this.popupTimerClear();
}
@@ -135,7 +135,7 @@ class Frontend {
}
}
- onAuxClick(e) {
+ onAuxClick() {
this.preventNextContextMenu = false;
}
@@ -159,7 +159,7 @@ class Frontend {
this.preventNextClick = false;
const primaryTouch = e.changedTouches[0];
- if (Frontend.selectionContainsPoint(window.getSelection(), primaryTouch.clientX, primaryTouch.clientY)) {
+ if (DOM.isPointInSelection(primaryTouch.clientX, primaryTouch.clientY, window.getSelection())) {
return;
}
@@ -237,7 +237,7 @@ class Frontend {
onWindowMessage(e) {
const action = e.data;
const handlers = Frontend.windowMessageHandlers;
- if (handlers.hasOwnProperty(action)) {
+ if (hasOwn(handlers, action)) {
const handler = handlers[action];
handler(this);
}
@@ -245,7 +245,7 @@ class Frontend {
onRuntimeMessage({action, params}, sender, callback) {
const handlers = Frontend.runtimeMessageHandlers;
- if (handlers.hasOwnProperty(action)) {
+ if (hasOwn(handlers, action)) {
const handler = handlers[action];
const result = handler(this, params);
callback(result);
@@ -398,7 +398,7 @@ class Frontend {
textSource.getRect(),
textSource.getWritingMode(),
type,
- {definitions, context: {sentence, url, focus}}
+ {definitions, context: {sentence, url, focus, disableHistory: true}}
);
this.textSourceCurrent = textSource;
@@ -413,7 +413,7 @@ class Frontend {
const searchText = textSource.text();
if (searchText.length === 0) { return null; }
- const {definitions, length} = await apiTermsFind(searchText, this.getOptionsContext());
+ const {definitions, length} = await apiTermsFind(searchText, {}, this.getOptionsContext());
if (definitions.length === 0) { return null; }
textSource.setEndOffset(length);
@@ -447,8 +447,8 @@ class Frontend {
}
getIndexOfTouch(touchList, identifier) {
- for (let i in touchList) {
- let t = touchList[i];
+ for (const i in touchList) {
+ const t = touchList[i];
if (t.identifier === identifier) {
return i;
}
@@ -456,18 +456,6 @@ class Frontend {
return -1;
}
- static selectionContainsPoint(selection, x, y) {
- for (let i = 0; i < selection.rangeCount; ++i) {
- const range = selection.getRangeAt(i);
- for (const rect of range.getClientRects()) {
- if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
- return true;
- }
- }
- }
- return false;
- }
-
setTextSourceScanLength(textSource, length) {
textSource.setEndOffset(length);
if (this.ignoreNodes === null || !textSource.range) {
@@ -499,25 +487,6 @@ class Frontend {
default: return false;
}
}
-
- static isMouseButton(button, mouseEvent) {
- switch (mouseEvent.type) {
- case 'mouseup':
- case 'mousedown':
- case 'click': switch (button) {
- case 'primary': return mouseEvent.button === 0;
- case 'secondary': return mouseEvent.button === 2;
- case 'auxiliary': return mouseEvent.button === 1;
- default: return false;
- }
- default: switch (button) {
- case 'primary': return (mouseEvent.buttons & 0x1) !== 0x0;
- case 'secondary': return (mouseEvent.buttons & 0x2) !== 0x0;
- case 'auxiliary': return (mouseEvent.buttons & 0x4) !== 0x0;
- default: return false;
- }
- }
- }
}
Frontend.windowMessageHandlers = {
diff --git a/ext/fg/js/popup-nested.js b/ext/fg/js/popup-nested.js
index cec95aea..31cb1cda 100644
--- a/ext/fg/js/popup-nested.js
+++ b/ext/fg/js/popup-nested.js
@@ -33,7 +33,10 @@ async function popupNestedInitialize(id, depth, parentFrameId, url) {
return;
}
- const ignoreNodes = options.scanning.enableOnPopupExpressions ? [] : [ '.expression', '.expression *' ];
+ const ignoreNodes = ['.scan-disable', '.scan-disable *'];
+ if (!options.scanning.enableOnPopupExpressions) {
+ ignoreNodes.push('.expression-scan-toggle', '.expression-scan-toggle *');
+ }
window.frontendInitializationData = {id, depth, parentFrameId, ignoreNodes, url, proxy: true};
diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js
index d8dec4df..b2f18b97 100644
--- a/ext/fg/js/popup-proxy-host.js
+++ b/ext/fg/js/popup-proxy-host.js
@@ -50,7 +50,7 @@ class PopupProxyHost {
}
createPopup(parentId, depth) {
- const parent = (typeof parentId === 'string' && this.popups.hasOwnProperty(parentId) ? this.popups[parentId] : null);
+ const parent = (typeof parentId === 'string' && hasOwn(this.popups, parentId) ? this.popups[parentId] : null);
const id = `${this.nextId}`;
if (parent !== null) {
depth = parent.depth + 1;
@@ -70,7 +70,7 @@ class PopupProxyHost {
}
getPopup(id) {
- if (!this.popups.hasOwnProperty(id)) {
+ if (!hasOwn(this.popups, id)) {
throw new Error('Invalid popup ID');
}
diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js
index 1f9317e0..42475d96 100644
--- a/ext/fg/js/popup.js
+++ b/ext/fg/js/popup.js
@@ -28,8 +28,8 @@ class Popup {
this.childrenSupported = true;
this.container = document.createElement('iframe');
this.container.className = 'yomichan-float';
- this.container.addEventListener('mousedown', e => e.stopPropagation());
- this.container.addEventListener('scroll', e => e.stopPropagation());
+ this.container.addEventListener('mousedown', (e) => e.stopPropagation());
+ this.container.addEventListener('scroll', (e) => e.stopPropagation());
this.container.setAttribute('src', chrome.runtime.getURL('/fg/float.html'));
this.container.style.width = '0px';
this.container.style.height = '0px';
@@ -303,7 +303,7 @@ class Popup {
}
static getColorInfo(cssColor) {
- const m = /^\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d\.]+)\s*)?\)\s*$/.exec(cssColor);
+ const m = /^\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)\s*$/.exec(cssColor);
if (m === null) { return null; }
const m4 = m[4];
@@ -391,7 +391,7 @@ class Popup {
static isOnExtensionPage() {
try {
const url = chrome.runtime.getURL('/');
- return window.location.href.substr(0, url.length) === url;
+ return window.location.href.substring(0, url.length) === url;
} catch (e) {
// NOP
}
@@ -401,7 +401,7 @@ class Popup {
if (Popup.outerStylesheet === null) {
if (!css) { return; }
Popup.outerStylesheet = document.createElement('style');
- Popup.outerStylesheet.id = "yomichan-popup-outer-stylesheet";
+ Popup.outerStylesheet.id = 'yomichan-popup-outer-stylesheet';
}
const outerStylesheet = Popup.outerStylesheet;
diff --git a/ext/fg/js/source.js b/ext/fg/js/source.js
index c3da9f46..a84feed4 100644
--- a/ext/fg/js/source.js
+++ b/ext/fg/js/source.js
@@ -99,15 +99,19 @@ class TextSourceRange {
static getRubyElement(node) {
node = TextSourceRange.getParentElement(node);
- if (node !== null && node.nodeName.toUpperCase() === "RT") {
+ if (node !== null && node.nodeName.toUpperCase() === 'RT') {
node = node.parentNode;
- return (node !== null && node.nodeName.toUpperCase() === "RUBY") ? node : null;
+ return (node !== null && node.nodeName.toUpperCase() === 'RUBY') ? node : null;
}
return null;
}
static seekForward(node, offset, length) {
const state = {node, offset, remainder: length, content: ''};
+ if (length <= 0) {
+ return state;
+ }
+
const TEXT_NODE = Node.TEXT_NODE;
const ELEMENT_NODE = Node.ELEMENT_NODE;
let resetOffset = false;
@@ -166,6 +170,10 @@ class TextSourceRange {
static seekBackward(node, offset, length) {
const state = {node, offset, remainder: length, content: ''};
+ if (length <= 0) {
+ return state;
+ }
+
const TEXT_NODE = Node.TEXT_NODE;
const ELEMENT_NODE = Node.ELEMENT_NODE;
let resetOffset = false;
@@ -353,7 +361,7 @@ class TextSourceElement {
let consumed = 0;
let content = '';
- for (let currentChar of this.content || '') {
+ for (const currentChar of this.content || '') {
if (consumed >= length) {
break;
} else if (!currentChar.match(IGNORE_TEXT_PATTERN)) {
@@ -367,7 +375,7 @@ class TextSourceElement {
return this.content.length;
}
- setStartOffset(length) {
+ setStartOffset() {
return 0;
}
diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js
deleted file mode 100644
index 9a7968a7..00000000
--- a/ext/fg/js/util.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016-2017 Alex Yatskov <alex@foosoft.net>
- * Author: Alex Yatskov <alex@foosoft.net>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-
-function utilAsync(func) {
- return function(...args) {
- func.apply(this, args);
- };
-}
-
-function utilInvoke(action, params={}) {
- const data = {action, params};
- return new Promise((resolve, reject) => {
- try {
- chrome.runtime.sendMessage(data, (response) => {
- utilCheckLastError(chrome.runtime.lastError);
- if (response !== null && typeof response === 'object') {
- if (typeof response.error !== 'undefined') {
- reject(jsonToError(response.error));
- } else {
- resolve(response.result);
- }
- } else {
- const message = response === null ? 'Unexpected null response' : `Unexpected response of type ${typeof response}`;
- reject(new Error(`${message} (${JSON.stringify(data)})`));
- }
- });
- } catch (e) {
- window.yomichan_orphaned = true;
- reject(e);
- }
- });
-}
-
-function utilCheckLastError(e) {
- // NOP
-}