Improved text scanning

This commit is contained in:
Alex Yatskov 2016-06-12 20:48:21 -07:00
parent 061cbb0141
commit 3ed5b90ccb

View File

@ -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);