aboutsummaryrefslogtreecommitdiff
path: root/ext/fg/js/source-range.js
diff options
context:
space:
mode:
authorAlex Yatskov <alex@foosoft.net>2016-07-24 21:18:17 -0700
committerAlex Yatskov <alex@foosoft.net>2016-07-24 21:18:17 -0700
commit19cc8fda335f27229753038709f3765090e169e8 (patch)
tree49ee07eb15e84c78eca7e07ac81aa88a2c453f08 /ext/fg/js/source-range.js
parent871acf7c2d75b349e55b761d5513223cf716464e (diff)
Better range handling.
Diffstat (limited to 'ext/fg/js/source-range.js')
-rw-r--r--ext/fg/js/source-range.js68
1 files changed, 52 insertions, 16 deletions
diff --git a/ext/fg/js/source-range.js b/ext/fg/js/source-range.js
index e09ec33a..fbab45f9 100644
--- a/ext/fg/js/source-range.js
+++ b/ext/fg/js/source-range.js
@@ -26,9 +26,16 @@ class TextSourceRange {
return this.rng.toString();
}
- setLength(length) {
- const end = TextSourceRange.seekEnd(this.rng.startContainer, this.rng.startOffset + length);
+ setEndOffset(length) {
+ const end = TextSourceRange.seekForward(this.rng.startContainer, this.rng.startOffset + length);
this.rng.setEnd(end.node, end.offset);
+ return length - end.length;
+ }
+
+ setStartOffset(length) {
+ const start = TextSourceRange.seekBackward(this.rng.startContainer, length + (this.rng.startContainer.length - this.rng.startOffset));
+ this.rng.setStart(start.node, start.offset);
+ return length - start.length;
}
containsPoint(point) {
@@ -67,37 +74,66 @@ class TextSourceRange {
return other.rng && other.rng.compareBoundaryPoints(Range.START_TO_START, this.rng) == 0;
}
- static seekEnd(node, length) {
+ static seekForward(node, length) {
const state = {node, offset: 0, length};
+ if (!TextSourceRange.seekForwardHelper(node, state)) {
+ return state;
+ }
- if (!TextSourceRange.seekEndRecurse(node, state)) {
- return {node: state.node, offset: state.offset};
+ for (let current = node; current !== null; current = current.parentElement) {
+ for (let sibling = current.nextSibling; sibling !== null; sibling = sibling.nextSibling) {
+ if (!TextSourceRange.seekForwardHelper(sibling, state)) {
+ return state;
+ }
+ }
}
- for (let sibling = node.nextSibling; sibling !== null; sibling = sibling.nextSibling) {
- if (!TextSourceRange.seekEndRecurse(sibling, state)) {
- return {node: state.node, offset: state.offset};
+ return state;
+ }
+
+ static seekForwardHelper(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 (!TextSourceRange.seekForwardHelper(node.childNodes[i], state)) {
+ break;
+ }
}
}
- for (let sibling = node.parentElement.nextSibling; sibling !== null; sibling = sibling.nextSibling) {
- if (!TextSourceRange.seekEndRecurse(sibling, state)) {
- return {node: state.node, offset: state.offset};
+ return state.length > 0;
+ }
+
+ static seekBackward(node, length) {
+ const state = {node, offset: node.length, length};
+ if (!TextSourceRange.seekBackwardHelper(node, state)) {
+ return state;
+ }
+
+ for (let current = node; current !== null; current = current.parentElement) {
+ for (let sibling = current.previousSibling; sibling !== null; sibling = sibling.previousSibling) {
+ if (!TextSourceRange.seekBackwardHelper(sibling, state)) {
+ return state;
+ }
}
}
- return {node: state.node, offset: state.offset};
+ return state;
}
- static seekEndRecurse(node, state) {
+ static seekBackwardHelper(node, state) {
if (node.nodeType === 3) {
const consumed = Math.min(node.length, state.length);
state.node = node;
- state.offset = consumed;
+ state.offset = node.length - consumed;
state.length -= consumed;
} else {
- for (let i = 0; i < node.childNodes.length; ++i) {
- if (!TextSourceRange.seekEndRecurse(node.childNodes[i], state)) {
+ for (let i = node.childNodes.length - 1; i >= 0; --i) {
+ if (!TextSourceRange.seekBackwardHelper(node.childNodes[i], state)) {
break;
}
}