aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/fg/js/range.js62
1 files changed, 40 insertions, 22 deletions
diff --git a/ext/fg/js/range.js b/ext/fg/js/range.js
index f6af7122..182e242c 100644
--- a/ext/fg/js/range.js
+++ b/ext/fg/js/range.js
@@ -27,31 +27,10 @@ class Range {
}
setLength(length) {
- const end = this.findEnd(this.rng.startContainer, this.rng.startOffset, length);
+ const end = Range.seekEnd(this.rng.startContainer, this.rng.startOffset + length);
this.rng.setEnd(end.node, end.offset);
}
- findEnd(node, offset, length) {
- if (node.nodeType === 3) {
- const remainder = node.data.length - offset;
- if (remainder >= length) {
- return {node, offset: offset + length};
- }
-
- length -= remainder;
- }
-
- if (node.childNodes.length > 0) {
- return this.findEnd(node.childNodes[0], 0, length);
- }
-
- if (node.nextSibling !== null) {
- return this.findEnd(node.nextSibling, 0, length);
- }
-
- return {node, offset: node.data.length};
- }
-
containsPoint(point) {
const rect = this.getPaddedRect();
return point.x >= rect.left && point.x <= rect.right;
@@ -88,6 +67,45 @@ class Range {
return range.rng.compareBoundaryPoints(Range.END_TO_END, this.rng);
}
+ static seekEnd(node, length) {
+ const state = {node, offset: 0, length};
+
+ if (!Range.seekEndRecurse(node, state)) {
+ return {node: state.node, offset: state.offset};
+ }
+
+ for (let sibling = node.nextSibling; sibling !== null; sibling = sibling.nextSibling) {
+ if (!Range.seekEndRecurse(sibling, state)) {
+ return {node: state.node, offset: state.offset};
+ }
+ }
+
+ for (let sibling = node.parentElement.nextSibling; sibling !== null; sibling = sibling.nextSibling) {
+ if (!Range.seekEndRecurse(sibling, state)) {
+ return {node: state.node, offset: state.offset};
+ }
+ }
+
+ return {node: state.node, offset: state.offset};
+ }
+
+ static seekEndRecurse(node, state) {
+ if (node.nodeType === 3) {
+ const consumed = Math.min(node.length, state.length);
+ state.node = node;
+ state.offset = consumed;
+ state.length -= consumed;
+ } else {
+ for (let i = 0; i < node.childNodes.length; ++i) {
+ if (!Range.seekEndRecurse(node.childNodes[i], state)) {
+ break;
+ }
+ }
+ }
+
+ return state.length > 0;
+ }
+
static fromPoint(point) {
const range = document.caretRangeFromPoint(point.x, point.y);
return range === null ? null : new Range(range);