Skip to content

Commit

Permalink
Allow to detect URI-like text across boundaries between inline texts …
Browse files Browse the repository at this point in the history
…and "display:inline-flex" boxes
  • Loading branch information
piroor committed Dec 18, 2022
1 parent a66d041 commit c7bbfcf
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 8 deletions.
38 changes: 33 additions & 5 deletions webextensions/content_scripts/content.js
Expand Up @@ -7,6 +7,8 @@

gLogContext = 'content';

const INLINE_BOUNDARY_NODE = 'textlink-boundary-inline-node';

let gTryingAction = false;
let gLastActionResult = null;
let gMatchAllProgress = 0;
Expand All @@ -20,10 +22,17 @@ async function onDblClick(event) {
gTryingAction = true;
gLastActionResult = null;
const textFieldSelection = isInputField(event.target);
for (const node of data.boundaryInlineNodes) {
node.classList.add(INLINE_BOUNDARY_NODE);
}
gLastActionResult = await browser.runtime.sendMessage({
...data,
boundaryInlineNodes: [], // don't send raw DOM nodes
type: kCOMMAND_TRY_ACTION
});
for (const node of data.boundaryInlineNodes) {
node.classList.remove(INLINE_BOUNDARY_NODE);
}
if (textFieldSelection &&
gLastActionResult &&
gLastActionResult.range)
Expand Down Expand Up @@ -53,10 +62,17 @@ async function onKeyDown(event) {
gTryingAction = true;
gLastActionResult = null;
const textFieldSelection = isInputField(event.target);
for (const node of data.boundaryInlineNodes) {
node.classList.add(INLINE_BOUNDARY_NODE);
}
gLastActionResult = await browser.runtime.sendMessage({
...data,
boundaryInlineNodes: [], // don't send raw DOM nodes
type: kCOMMAND_TRY_ACTION
});
for (const node of data.boundaryInlineNodes) {
node.classList.remove(INLINE_BOUNDARY_NODE);
}
if (textFieldSelection &&
gLastActionResult &&
gLastActionResult.range)
Expand Down Expand Up @@ -200,21 +216,29 @@ async function findURIRanges(options = {}) {
}

const selectionRanges = [];
const boundaryInlineNodes = [];
for (let i = 0, maxi = selection.rangeCount; i < maxi; i++) {
const selectionRange = selection.getRangeAt(i);
const selectionText = rangeToText(selectionRange);
const precedings = getPrecedingRanges(selectionRange);
const followings = getFollowingRanges(selectionRange);
const rangeData = getRangeData(selectionRange);
rangeData.text = selectionText;
rangeData.expandedText = `${precedings.texts.join('')}${selectionText}${followings.texts.join('')}`;
rangeData.text = selectionText.text;
rangeData.expandedText = `${precedings.texts.join('')}${selectionText.text}${followings.texts.join('')}`;
selectionRanges.push(rangeData);
boundaryInlineNodes.push(...selectionText.boundaryInlineNodes, ...precedings.boundaryInlineNodes, ...followings.boundaryInlineNodes);
}
for (const node of boundaryInlineNodes) {
node.classList.add(INLINE_BOUNDARY_NODE);
}
const ranges = await browser.runtime.sendMessage({
type: kCOMMAND_FIND_URI_RANGES,
base: location.href,
ranges: selectionRanges
});
for (const node of boundaryInlineNodes) {
node.classList.remove(INLINE_BOUNDARY_NODE);
}
gFindingURIRanges = false;
return ranges;
}
Expand All @@ -226,17 +250,20 @@ function getSelectionEventData(event) {
if (!textFieldSelection && selection.rangeCount != 1)
return null;

let text, cursor;
let text, cursor, boundaryInlineNodes;
if (textFieldSelection) {
cursor = getFieldRangeData(event.target);
text = cursor.text;
boundaryInlineNodes = [];
}
else {
const selectionRange = selection.getRangeAt(0);
const selectionText = rangeToText(selectionRange);
const precedings = getPrecedingRanges(selectionRange);
const followings = getFollowingRanges(selectionRange);
text = `${precedings.texts.join('')}${rangeToText(selectionRange)}${followings.texts.join('')}`;
text = `${precedings.texts.join('')}${selectionText.text}${followings.texts.join('')}`;
cursor = getRangeData(selectionRange);
boundaryInlineNodes = [...selectionText.boundaryInlineNodes, ...precedings.boundaryInlineNodes, ...followings.boundaryInlineNodes];
}

const data = {
Expand All @@ -248,7 +275,8 @@ function getSelectionEventData(event) {
metaKey: event.metaKey,
shiftKey: event.shiftKey,
inEditable: textFieldSelection || isEditableNode(event.target)
}
},
boundaryInlineNodes,
};

if (event.type == 'dblclick' &&
Expand Down
16 changes: 13 additions & 3 deletions webextensions/content_scripts/range.js
Expand Up @@ -21,6 +21,7 @@ function rangeToText(range) {
result += text;
}

const boundaryInlineNodes = [];
while (walker.nextNode()) {
const node = walker.currentNode;
const position = range.endContainer.compareDocumentPosition(node);
Expand All @@ -36,9 +37,14 @@ function rangeToText(range) {
}
const { text, state } = nodeToText(node);
result += text;
if (state == STATE_CONTINUE_VISUALLY)
boundaryInlineNodes.push(node.offsetParent);
}

return result; // .replace(/\n\s*|\s*\n/g, '\n');
return {
text: result, // .replace(/\n\s*|\s*\n/g, '\n')
boundaryInlineNodes,
};
}

function nodeToText(node) {
Expand Down Expand Up @@ -76,6 +82,7 @@ function nodeToText(node) {
function getPrecedingRanges(sourceRange) {
const texts = [];
const ranges = [];
const boundaryInlineNodes = [];
const range = document.createRange();
range.setStart(sourceRange.startContainer, sourceRange.startOffset);
range.setEnd(sourceRange.startContainer, sourceRange.startOffset);
Expand Down Expand Up @@ -106,6 +113,7 @@ function getPrecedingRanges(sourceRange) {
case STATE_CONTINUE_VISUALLY:
texts.unshift(text);
ranges.unshift(range.cloneRange());
boundaryInlineNodes.unshift(walker.currentNode.offsetParent);
text = partialText;
range.collapse(true);
continue;
Expand All @@ -116,12 +124,13 @@ function getPrecedingRanges(sourceRange) {
}
texts.unshift(text);
ranges.unshift(range);
return { texts, ranges };
return { texts, ranges, boundaryInlineNodes };
}

function getFollowingRanges(sourceRange) {
const texts = [];
const ranges = [];
const boundaryInlineNodes = [];
const range = document.createRange();
range.setStart(sourceRange.endContainer, sourceRange.endOffset);
range.setEnd(sourceRange.endContainer, sourceRange.endOffset);
Expand Down Expand Up @@ -152,6 +161,7 @@ function getFollowingRanges(sourceRange) {
case STATE_CONTINUE_VISUALLY:
texts.push(text);
ranges.push(range.cloneRange());
boundaryInlineNodes.push(walker.currentNode.offsetParent);
text = partialText;
range.collapse(false);
continue;
Expand All @@ -162,7 +172,7 @@ function getFollowingRanges(sourceRange) {
}
texts.push(text);
ranges.push(range);
return { texts, ranges };
return { texts, ranges, boundaryInlineNodes };
}

function createVisibleTextNodeWalker() {
Expand Down
3 changes: 3 additions & 0 deletions webextensions/manifest.json
Expand Up @@ -34,6 +34,9 @@
"content_scripts/xpath.js",
"content_scripts/range.js",
"content_scripts/content.js"
],
"css": [
"resources/deactivate-boundary-inline-elements.css"
]
}
],
Expand Down
16 changes: 16 additions & 0 deletions webextensions/resources/deactivate-boundary-inline-elements.css
@@ -0,0 +1,16 @@
/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/*
An elements with "display:inline-flex" is visually rendered as a regular
inline box, but it is actually treated as a non-inline box internally.
The API "browser.find.find()" (and Firefox's native in-page find feature also)
fails to find a term across the boundary. Thus we need to change its "display"
temporary while finding URI-like texts in webpages.
*/
.textlink-boundary-inline-node:not(#never#match#to#any#element) {
display: inline !important;
}

0 comments on commit c7bbfcf

Please sign in to comment.