2012-05-11 17 views
1

すべてのRangy Q &を調査しましたが、このケースには何も適応できませんでした。Rangyはcontentedit div内のバックスペースでキャレット位置を失います

は、私はすべての時間は、ユーザーのタイプの何かが、それはコンテンツとフォーマット特定のトークンを解析し、呼び出しのcontentEditable

<div id="area" style="width:100%;height:2em;" 
contentEditable="true"; 
onkeyup="formatText();" 
></div> 

以下の機能を持っています。

function formatText() { 

    var el = document.getElementById('area'); 
    var savedSel = saveSelection(el); // calls Rangy function 

    var tokenColor; 

     // removes html tags before passing the expression to the parser 
    var userInput = document.getElementById('area').innerHTML.replace(/(<([^>]+)>)/g,"").replace(/&amp;/g, "").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/<span[^>]*>+<\/span>/, ""); 


    var i, newHTML=[]; 

    tokenType=[]; // [NUMBER,+,(,NUMBER,..] 
    tokenArray=[]; // [3,+,(5,...] 

    var resultOutput = parse(userInput); // parser also fills tokenType and tokenArray 

    for (i=0; i<tokenArray.length-1; i++){ 

     newHTML += "<span style='color: " + tokenColor + " '>" + tokenArray[i] + "</span>"; 

     } // newHTML looks like <span style='color: red'>3</span><span style='color: black'>+</span> etc. 


    el.innerHTML = newHTML; // replaces content of <div> with formatted text  

    restoreSelection(el, savedSel); // calls Rangy function to restore cursor position 
} 

私はこのフォーラムの他の記事では、著者が提示し、次のRangyベースの機能を使用します。私は、文字を削除しようとするまで

function saveSelection(containerEl) { 
    var charIndex = 0, start = 0, end = 0, foundStart = false, stop = {}; 
    var sel = rangy.getSelection(), range; 

    function traverseTextNodes(node, range) { 
     if (node.nodeType == 3) { 
      if (!foundStart && node == range.startContainer) { 
       start = charIndex + range.startOffset; 
       foundStart = true; 
      } 

      if (foundStart && node == range.endContainer) { 
       end = charIndex + range.endOffset; 
       throw stop; 
      } 
      charIndex += node.length; 


     } else { 
      for (var i = 0, len = node.childNodes.length; i < len; ++i) { 
       traverseTextNodes(node.childNodes[i], range); 
      } 
     } 
    } 

    if (sel.rangeCount) { 
     try { 
      traverseTextNodes(containerEl, sel.getRangeAt(0)); 
     } catch (ex) { 
      if (ex != stop) { 
       throw ex; 
      } 
     } 
    } 

    return { 
     start: start, 
     end: end 
    }; 
} 



function restoreSelection(containerEl, savedSel) { 
    var charIndex = 0, range = rangy.createRange(), foundStart = false, stop = {}; 
    range.collapseToPoint(containerEl, 0); 

    function traverseTextNodes(node) { 
     if (node.nodeType == 3) { 
      var nextCharIndex = charIndex + node.length; 
      if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) { 
       range.setStart(node, savedSel.start - charIndex); 
       foundStart = true; 
      } 
      if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) { 
       range.setEnd(node, savedSel.end - charIndex); 
       throw stop; 
      } 
      charIndex = nextCharIndex; 
     } 

     else { 
      for (var i = 0, len = node.childNodes.length; i < len; ++i) { 
       traverseTextNodes(node.childNodes[i]); 
      } 
     } 
    } 

    try { 
     traverseTextNodes(containerEl); 
    } catch (ex) { 
     if (ex == stop) { 
      rangy.getSelection().setSingleRange(range); 
     } else { 
      throw ex; 
     } 
    } 
} 

すべてが完璧に動作します。その時点で、カーソルはdivの先頭にジャンプします。

なぜこれが起こる可能性がありますか?

多くのありがとうございます。

+0

divの内容全体を破棄してinnerHTMLに置き換えると、選択したノードが存在しなくなります。 innerHTMLを使用する代わりに、不要なノードを手作業で削除し、他のノードはそのまま残しておく必要があります。 –

+0

@GGG:コードの2番目のブロックは、文字インデックスベースの保存と復元を行います。したがって、表示されるテキストが 'innerHTML'置換後も変更されない限り、それはうまくいきます。 –

+0

@TimDown私はあなたが今何を意味しているかを見て、私はその部分を前にスキミングしました。私はまだこの作業について疑問を持っています。いくつかの正規表現は、マークアップが壊れているように見えます。 「 '.replace(/(<([^>)+)>)/、' ')// –

答えて

0

私はそれがうまくいくかのように見えます。選択肢を復元する前に、のコンテンツ編集可能メソッド<div>を呼び出すような簡単な解決策があります。

+0

こんにちはTim、あなたの提案に応じて、私は以下を追加しました:\t \t $( '#area')。フォーカス(); \t \t restoreSelection(el、savedSel); }でも、削除を押してもまだ動作しません。最後の文字を削除し、divの先頭でジャンプします。それはあなたが入力するように完全に動作するので、それは奇妙です。削除時に空のブロックが生成され、最初のRange.StartContainer.nodeName = "SPAN"というブロックが生成されたように見えます。これが理由ですか? – Gian

+0

UPDATE:これは別の問題と関連していると思います。Shift +右矢印を押すと、前方の文字が正しく強調表示されます。左矢印を使用しようとすると、1つの文字が強調表示され、次にカーソルが左に移動し、別の文字などがハイライト表示されます。削除や後ろ向きの強調表示などの逆の操作が嫌なロジックがあると思います。ありがとう。 – Gian

2

私はTim Downの助けを借りて問題を解決しました(Timさんに感謝します)。

彼は最近、Rangyに新しいTextRangeモジュールを追加しました。これは完全に機能します。このモジュールでは、ページ上の可視テキスト内の文字インデックスに基づいて選択保存/復元が行われるため、innerHTML変更の影響を受けません。あなたはここでデモを見つけることができます。

http://rangy.googlecode.com/svn/trunk/demos/textrange.html

にマニュアル(暫定):http://code.google.com/p/rangy/wiki/TextRangeModule

をだから、基本的にコードがしなければならない:

document.getElementById("area").onkeyup = function() { 
    var sel = rangy.getSelection(); 
    var savedSel = sel.saveCharacterRanges(this);  

    var userInput = this.textContent || this.innerText; 

    var userInputLength = userInput.length; 
    var newHTML = []; 

    for (var i=0; i<userInputLength; i++) { 
     newHTML[i] = "<span style='color: red'>" + userInput.charAt(i) + "</span>"; 
    } 

    this.innerHTML = newHTML.join(""); 

    sel.restoreCharacterRanges(this, savedSel); 
}; 
​ 

は、この情報がお役に立てば幸いです。

関連する問題