这是我的最新尝试。从表面上看似乎可以工作,但我不能保证:这是一段不平凡的代码,我还没有彻底测试过。
一旦我整理和测试了它,它很可能会以某种形式出现在我的Rangy库中。
现场演示:http: //jsfiddle.net/timdown/ABjQP/8/
代码摘录(Firefox 和 Opera 位):
function getNodeIndex(node) {
var i = 0;
while( (node = node.previousSibling) ) {
i++;
}
return i;
}
function getLastRangeRect(range) {
var rects = range.getClientRects();
return (rects.length > 0) ? rects[rects.length - 1] : null;
}
function pointIsInOrAboveRect(x, y, rect) {
return y < rect.bottom && x >= rect.left && x <= rect.right;
}
function positionFromPoint(doc, x, y, favourPrecedingPosition) {
var el = doc.elementFromPoint(x, y);
var range = doc.createRange();
range.selectNodeContents(el);
range.collapse(true);
var offsetNode = el.firstChild, offset, position, rect;
if (!offsetNode) {
offsetNode = el.parentNode;
offset = getNodeIndex(el);
if (!favourPrecedingPosition) {
++offset;
}
} else {
// Search through the text node children of el
main: while (offsetNode) {
if (offsetNode.nodeType == 3) {
// Go through the text node character by character
for (offset = 0, textLen = offsetNode.length; offset <= textLen; ++offset) {
range.setEnd(offsetNode, offset);
rect = getLastRangeRect(range);
if (rect && pointIsInOrAboveRect(x, y, rect)) {
// We've gone past the point. Now we check which side
// (left or right) of the character the point is nearer to
if (rect.right - x > x - rect.left) {
--offset;
}
break main;
}
}
} else {
// Handle elements
range.setEndAfter(offsetNode);
rect = getLastRangeRect(range);
if (rect && pointIsInOrAboveRect(x, y, rect)) {
offset = getNodeIndex(offsetNode);
offsetNode = el.parentNode;
if (!favourPrecedingPosition) {
++offset;
}
break main;
}
}
offsetNode = offsetNode.nextSibling;
}
if (!offsetNode) {
offsetNode = el;
offset = el.childNodes.length;
}
}
return {
offsetNode: offsetNode,
offset: offset
};
}