編集可能な要素のカスタム ドラッグ要素の問題を解決するための私のアプローチを次に示します。大きな問題は、編集可能な要素の上にカーソルを置いたときに、マウス カーソルのテキスト オフセットを特定できないことです。マウスのクリックを偽造してキャレットを目的の位置に設定しようとしましたが、うまくいきませんでした。あったとしても、ドラッグ中にキャレットの配置を視覚的に確認することはできず、結果のドロップのみが表示されます。
マウスオーバー イベントをテキスト ノードではなく要素にバインドできるため、編集可能な要素を一時的に編集不可に設定できます。テキストの流れを壊さないように、すべての要素を検索し、各テキスト ノードをスパンでラップします。各スパンにはクラス名を付けて、再度見つけられるようにする必要があります。
ラッピング後、ラップされたすべてのテキストノードを再度見つけて、各文字を別のスパンでラップし、それらを再び見つけることができるクラス名を付ける必要があります。
イベント委任を使用すると、メインの編集可能な要素にイベントを追加して、キャレット (背景として点滅する GIF 画像) を表示する各文字スパンにスタイルを適用できます。
ここでも、イベント委任を使用して、各キャラクターのマウスアップ イベント (ドロップ イベント) のイベントを追加する必要があります。親(ラップされたテキストノード)内の文字スパンの位置(オフセット)を使用してオフセットを決定できるようになりました。計算されたオフセットへの参照を保持しながら、適用可能なテキストノードへの参照を保持しながらラッピングを元に戻すことで、すべてのラッピングを元に戻すことができるようになりました。
ブラウザの範囲と選択オブジェクトを使用して、計算されたオフセットを使用して適切なテキストノードに選択を設定し、新しく設定された選択 (キャレット位置) に必要な HTML を挿入できます。
テキストノードを見つけてラップする jQuery を使用したスニペットを次に示します。
editElement.find("*:not(.text-node)").contents().filter(function(){
return this.nodeType != 1;
}).wrap("<span class=\"text-node\"/>");
各テキストノードを見つけて各文字をラップするには、次を使用します。
editElement.find(".text-node").each(function()
{
var textnode = $(this), text = textnode.text(), result = [];
for (var i = 0; i < text.length; i++) result.push(text.substr(i, 1));
textnode.html("<span class=\"char\">"
+ result.join("</span><span class=\"char\">") + "</span>");
});
ラッピングを元に戻すには:
editElement.find(".text-node").each(function()
{
this.parentNode.replaceChild(document.createTextNode($(this).text()), this);
});
このアプローチが同様の課題を抱えている人に役立つことを願っています