19

I'd like to track the movement of the caret/cursor in a contenteditable. I'm not sure what's the best way to do this, though.

I'm currently listening for click, keydown, keyup. (keypress of course doesn't even fire for things like arrow keys or ctrl-x.)

While click works fine, the problem with keydown is that it's fired before the caret actually moves, so when I query the current document selection range, I get the old position and not the new one. But if I rely on keyup to get the updated position, it fires too late: the caret moves as soon as the key is pressed down, but the key is released an arbitrary time later.

This must be possible because things like CKeditor are able to do this. Any hints?

4

4 に答える 4

10

人々が CKEditor について話しているのを読んでうれしいです :)。私はその開発者の 1 人であり、選択にあまり取り組んでいませんが、手助けをしようと思います。

私が知っているのは、内部selectionChangeイベントがあるということです。では、いつ変更されたかどうかを確認しますか? ... ... 少なくとも 200ms ごとに 1 回 :) 参照:

http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L39

また、選択が変更された可能性があることを知るたびに、選択をチェックします (たとえば、API または keyup/mouseup またはネイティブ selectionchange - http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection )。 /plugin.js#L554 )。だから...ほとんどいつも:)知る限り、私たちはいくつかのトリックを行っているので、CPUを燃やしませんが、それでも重いです. ただし、これを行った場合、これがうまく機能する唯一の可能な方法です。

残念ながら、wysiwygs の世界では、選択の処理は断然最悪の作業です。古いブラウザーでも新しいブラウザーでも、すべてが壊れています。上でリンクしたファイルの 75% 以上の LOC はハックとトリックです。それは完全な狂気です。

于 2012-07-13T22:31:57.653 に答える
5

Mozilla と Opera では、キーとマウスのイベントを処理する厄介なビジネスが唯一のオプションです。面倒なだけでなく、すべてのケースに対応しているわけではありません。編集メニューとコンテキスト メニュー (たとえば、[すべて選択] を使用) を使用して選択を変更することができます。それをカバーするには、選択オブジェクトのある種のポーリングも追加する必要があります。

ただし、IE (少なくとも 5.5 までさかのぼる) と最近の WebKit では、選択が変更されるたびにドキュメントで発生するselectionchangeイベントがあります。

document.onselectionchange = function() {
    alert("Selection changed!");
};

Mozilla が将来サポートする可能性があります: https://bugzilla.mozilla.org/show_bug.cgi?id=571294

于 2012-07-12T00:34:47.187 に答える
0

選択が更新された後にイベントをキャッチする WRT : ハンドラー関数をタイムアウトでラップするだけです。

editor.onkeydown = function() {
  window.setTimeout( function(){
    // Your handler code here
  }, 0 );
};

これにより、ハンドラーがブラウザのイベント ループでできるだけ早く実行されるように登録されますが、現在の (クリックなどの) イベントが処理された後に実行されます。ただし、コンテンツを変更する他のスクリプトがある場合は、競合が発生する可能性があることに注意してください。タイムアウトが次に実行されるという保証はありません。

于 2012-07-26T13:06:22.880 に答える
0

あなたが言った理由から、それは簡単な仕事ではありません。私はこのようないくつかのクラッジを思いついた:

var caretInterval, caretOffset;
document.addEventListener("keydown", function(e) {
    if (!e.target.contentEditable || caretInterval) return;
    if (e.keyCode !== 37 && e.keyCode !== 39) // Left and right
        return;
    var sel = getSelection();
    caretInterval = setInterval(function() {
        if (sel.type === "Caret") caretOffset = sel.baseOffset;
    }, 50);
});
document.addEventListener("keyup", function(e) {
    if (e.keyCode !== 37 && e.keyCode !== 39) // Left and right
        return;
    clearInterval(caretInterval);
    caretInverval = null;
    var sel = getSelection();
    if (sel.type === "Caret") caretOffset = sel.baseOffset;
});

誰かが左右を同時に押そうとすると、小さな問題が発生する可能性があります。ctrl-X と ctrl-V の場合は、cutandpasteイベントをキャッチする必要がありますが、これは実際には別の問題です。

結局、自分の目的のために努力する価値はないと判断しました。たぶん、あなたはさまざまなニーズを持っています。

于 2012-07-11T22:49:25.000 に答える