RangyのSelectionおよびRangeAPIは、標準のDOMSelectionおよびRangeAPIのスーパーセットであるため、MDN(Range、Selection)などの場所からのドキュメントが適用されます。
あなたが抱えている問題は、範囲の境界が、含まれているDOMノード内のオフセットとして表されることです。たとえば、以下のHTMLでは、カレットはパイプ文字として示されています。
<p>Foo<br>b|ar</p>
...カレット範囲の開始境界と終了境界は同一であり、テキストノード「バー」でオフセット1に設定されます。
要素のテキストコンテンツ内のオフセットとして位置を設定する場合は、<p>
DOMトラバーサルを実行する必要があります。私の別の答えに基づいて、これの実装を書きました。これは単純な実装です。CSSによって、または要素内にあるなどの理由で非表示にされる可能性のあるテキストを考慮せず、改行を含むブラウザーの不一致(IEと他のすべて)がある可能性があります。折りたたまれた空白の説明はありません(2つ以上の連続したスペース文字がページ上の1つの表示可能なスペースに折りたたまれているなど)。これは正しく理解するのが難しいので、私は一般的にそれをお勧めしません。これらすべてを処理するRangy用のテキストベースのモジュールを作成することを計画していますが、まだ開始していません。
http://jsfiddle.net/ee93P/2/
コード:
function setCaretCharIndex(containerEl, index) {
var charIndex = 0, stop = {};
function traverseNodes(node) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (index >= charIndex && index <= nextCharIndex) {
rangy.getSelection().collapse(node, index - charIndex);
throw stop;
}
charIndex = nextCharIndex;
}
// Count an empty element as a single character. The list below may not be exhaustive.
else if (node.nodeType == 1
&& /^(input|br|img|col|area|link|meta|link|param|base)$/i.test(node.nodeName)) {
charIndex += 1;
} else {
var child = node.firstChild;
while (child) {
traverseNodes(child);
child = child.nextSibling;
}
}
}
try {
traverseNodes(containerEl);
} catch (ex) {
if (ex != stop) {
throw ex;
}
}
}