From 3ed5b90ccb6e5a6f73311abb29f4bb5e5c6821b6 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 12 Jun 2016 20:48:21 -0700 Subject: [PATCH] Improved text scanning --- ext/fg/js/range.js | 62 ++++++++++++++++++++++++++++++---------------- 1 file 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);