diff options
| author | Alex Yatskov <alex@foosoft.net> | 2016-06-12 20:48:21 -0700 | 
|---|---|---|
| committer | Alex Yatskov <alex@foosoft.net> | 2016-06-14 20:44:38 -0700 | 
| commit | 3ed5b90ccb6e5a6f73311abb29f4bb5e5c6821b6 (patch) | |
| tree | 98f6201076105d79fc1220b4c102d592a4b4dc09 | |
| parent | 061cbb0141df513113563c86e5df7c17cd46700f (diff) | |
Improved text scanning
| -rw-r--r-- | ext/fg/js/range.js | 62 | 
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); |