private Point<Node> linearSearchForRange(JsTextRangeIE target, Element parent) {
try {
// We'll iterate through the parent's children while moving
// a new collapsed range, attempt, through the points before
// each child.
Node child = parent.getFirstChild();
// Start attempt at beginning of parent
JsTextRangeIE attempt = JsTextRangeIE.create().moveToElementText(parent).collapse(true);
while (child != null) {
// Treat text node children separately
if (DomHelper.isTextNode(child)) {
// Move attempt to end of the text node
int len = child.<Text> cast().getLength();
attempt.move(character, len);
// Test if attempt is now at or past target
if (attempt.compareEndPoints(StartToStart, target) >= 0) {
// Target is in this text node. Compute the offset by creating a new
// text range from target to attempt and measuring the length of the
// text in that range
JsTextRangeIE dup =
attempt.duplicate().setEndPoint(StartToStart, target)
.setEndPoint(EndToEnd, attempt);
return Point.inText(child, len - dup.getText().length());
}
} else {
// Child is an element. Move attempt before child, and test
// if attempt is at or past range
attempt.moveToElementText(child.<Element> cast()).collapse(true);
if (attempt.compareEndPoints(StartToStart, target) >= 0) {
// Return the point before child
return Point.inElement(parent, child);
} else {
// Move attempt past child
// We use our inline, non-empty marker element to do this.
// We also leave it in the dom for max reliability until it's needed
// later, or gets taken out in the finally clause at the end of this method
child.getParentNode().insertAfter(setter, child);
// skip pass the setter.
child = child.getNextSibling();
attempt.moveToElementText(setter).collapse(false);
}
}
// Move to next child
child = child.getNextSibling();
}
// We didn't find target before or in children; return point at end of
// parent
return Point.<Node> end(parent);