Better range handling.

This commit is contained in:
Alex Yatskov 2016-07-24 21:18:17 -07:00
parent 871acf7c2d
commit 19cc8fda33
4 changed files with 70 additions and 22 deletions

View File

@ -110,13 +110,13 @@ class Client {
return; return;
} }
textSource.setLength(this.options.scanLength); textSource.setEndOffset(this.options.scanLength);
bgFindTerm(textSource.text(), ({definitions, length}) => { bgFindTerm(textSource.text(), ({definitions, length}) => {
if (length === 0) { if (length === 0) {
this.hidePopup(); this.hidePopup();
} else { } else {
const sequence = ++this.sequence; const sequence = ++this.sequence;
textSource.setLength(length); textSource.setEndOffset(length);
bgRenderText( bgRenderText(
{definitions, root: this.fgRoot, options: this.options, sequence}, {definitions, root: this.fgRoot, options: this.options, sequence},

View File

@ -32,8 +32,14 @@ class TextSourceImage {
return this.img.getAttribute('alt') || ''; return this.img.getAttribute('alt') || '';
} }
setLength(length) { setStartOffset(length) {
// NOP
return 0;
}
setEndOffset(length) {
this.length = length; this.length = length;
return length;
} }
containsPoint(point) { containsPoint(point) {

View File

@ -32,8 +32,14 @@ class TextSourceInput {
return this.input.nodeName === 'BUTTON' ? this.input.innerHTML : this.input.value; return this.input.nodeName === 'BUTTON' ? this.input.innerHTML : this.input.value;
} }
setLength(length) { setStartOffset(length) {
// NOP
return 0;
}
setEndOffset(length) {
this.length = length; this.length = length;
return length;
} }
containsPoint(point) { containsPoint(point) {

View File

@ -26,9 +26,16 @@ class TextSourceRange {
return this.rng.toString(); return this.rng.toString();
} }
setLength(length) { setEndOffset(length) {
const end = TextSourceRange.seekEnd(this.rng.startContainer, this.rng.startOffset + length); const end = TextSourceRange.seekForward(this.rng.startContainer, this.rng.startOffset + length);
this.rng.setEnd(end.node, end.offset); 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) { containsPoint(point) {
@ -67,29 +74,24 @@ class TextSourceRange {
return other.rng && other.rng.compareBoundaryPoints(Range.START_TO_START, this.rng) == 0; 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}; const state = {node, offset: 0, length};
if (!TextSourceRange.seekForwardHelper(node, state)) {
if (!TextSourceRange.seekEndRecurse(node, state)) { return state;
return {node: state.node, offset: state.offset};
} }
for (let sibling = node.nextSibling; sibling !== null; sibling = sibling.nextSibling) { for (let current = node; current !== null; current = current.parentElement) {
if (!TextSourceRange.seekEndRecurse(sibling, state)) { for (let sibling = current.nextSibling; sibling !== null; sibling = sibling.nextSibling) {
return {node: state.node, offset: state.offset}; if (!TextSourceRange.seekForwardHelper(sibling, state)) {
return state;
}
} }
} }
for (let sibling = node.parentElement.nextSibling; sibling !== null; sibling = sibling.nextSibling) { return state;
if (!TextSourceRange.seekEndRecurse(sibling, state)) {
return {node: state.node, offset: state.offset};
}
}
return {node: state.node, offset: state.offset};
} }
static seekEndRecurse(node, state) { static seekForwardHelper(node, state) {
if (node.nodeType === 3) { if (node.nodeType === 3) {
const consumed = Math.min(node.length, state.length); const consumed = Math.min(node.length, state.length);
state.node = node; state.node = node;
@ -97,7 +99,41 @@ class TextSourceRange {
state.length -= consumed; state.length -= consumed;
} else { } else {
for (let i = 0; i < node.childNodes.length; ++i) { for (let i = 0; i < node.childNodes.length; ++i) {
if (!TextSourceRange.seekEndRecurse(node.childNodes[i], state)) { if (!TextSourceRange.seekForwardHelper(node.childNodes[i], state)) {
break;
}
}
}
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 state;
}
static seekBackwardHelper(node, state) {
if (node.nodeType === 3) {
const consumed = Math.min(node.length, state.length);
state.node = node;
state.offset = node.length - consumed;
state.length -= consumed;
} else {
for (let i = node.childNodes.length - 1; i >= 0; --i) {
if (!TextSourceRange.seekBackwardHelper(node.childNodes[i], state)) {
break; break;
} }
} }